acpi_status acpi_get_timer_duration ( u32 start_ticks, u32 end_ticks, u32 *time_elapsed) { u32 delta_ticks = 0; union uint64_overlay normalized_ticks; acpi_status status; acpi_integer out_quotient; ACPI_FUNCTION_TRACE ("acpi_get_timer_duration"); if (!time_elapsed) { return_ACPI_STATUS (AE_BAD_PARAMETER); } /* * Compute Tick Delta: * ------------------- * Handle (max one) timer rollovers on 24- versus 32-bit timers. */ if (start_ticks < end_ticks) { delta_ticks = end_ticks - start_ticks; } else if (start_ticks > end_ticks) { if (0 == acpi_gbl_FADT->tmr_val_ext) { /* 24-bit Timer */ delta_ticks = (((0x00FFFFFF - start_ticks) + end_ticks) & 0x00FFFFFF); } else { /* 32-bit Timer */ delta_ticks = (0xFFFFFFFF - start_ticks) + end_ticks; } } else { *time_elapsed = 0; return_ACPI_STATUS (AE_OK); } /* * Compute Duration: * ----------------- * * Requires a 64-bit divide: * * time_elapsed = (delta_ticks * 1000000) / PM_TIMER_FREQUENCY; */ normalized_ticks.full = ((u64) delta_ticks) * 1000000; status = acpi_ut_short_divide (&normalized_ticks.full, PM_TIMER_FREQUENCY, &out_quotient, NULL); *time_elapsed = (u32) out_quotient; return_ACPI_STATUS (status); }
/****************************************************************************** * * FUNCTION: acpi_get_timer_duration * * PARAMETERS: start_ticks - Starting timestamp * end_ticks - End timestamp * time_elapsed - Where the elapsed time is returned * * RETURN: Status and time_elapsed * * DESCRIPTION: Computes the time elapsed (in microseconds) between two * PM Timer time stamps, taking into account the possibility of * rollovers, the timer resolution, and timer frequency. * * The PM Timer's clock ticks at roughly 3.6 times per * _microsecond_, and its clock continues through Cx state * transitions (unlike many CPU timestamp counters) -- making it * a versatile and accurate timer. * * Note that this function accommodates only a single timer * rollover. Thus for 24-bit timers, this function should only * be used for calculating durations less than ~4.6 seconds * (~20 minutes for 32-bit timers) -- calculations below: * * 2**24 Ticks / 3,600,000 Ticks/Sec = 4.66 sec * 2**32 Ticks / 3,600,000 Ticks/Sec = 1193 sec or 19.88 minutes * ******************************************************************************/ acpi_status acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed) { acpi_status status; u32 delta_ticks; u64 quotient; ACPI_FUNCTION_TRACE(acpi_get_timer_duration); if (!time_elapsed) { return_ACPI_STATUS(AE_BAD_PARAMETER); } /* ACPI 5.0A: PM Timer is optional */ if (!acpi_gbl_FADT.xpm_timer_block.address) { return_ACPI_STATUS(AE_SUPPORT); } /* * Compute Tick Delta: * Handle (max one) timer rollovers on 24-bit versus 32-bit timers. */ if (start_ticks < end_ticks) { delta_ticks = end_ticks - start_ticks; } else if (start_ticks > end_ticks) { if ((acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) == 0) { /* 24-bit Timer */ delta_ticks = (((0x00FFFFFF - start_ticks) + end_ticks) & 0x00FFFFFF); } else { /* 32-bit Timer */ delta_ticks = (0xFFFFFFFF - start_ticks) + end_ticks; } } else { /* start_ticks == end_ticks */ *time_elapsed = 0; return_ACPI_STATUS(AE_OK); } /* * Compute Duration (Requires a 64-bit multiply and divide): * * time_elapsed (microseconds) = * (delta_ticks * ACPI_USEC_PER_SEC) / ACPI_PM_TIMER_FREQUENCY; */ status = acpi_ut_short_divide(((u64)delta_ticks) * ACPI_USEC_PER_SEC, ACPI_PM_TIMER_FREQUENCY, "ient, NULL); *time_elapsed = (u32) quotient; return_ACPI_STATUS(status); }
acpi_status acpi_get_timer_duration ( u32 start_ticks, u32 end_ticks, u32 *time_elapsed) { acpi_status status; u32 delta_ticks; acpi_integer quotient; ACPI_FUNCTION_TRACE ("acpi_get_timer_duration"); if (!time_elapsed) { return_ACPI_STATUS (AE_BAD_PARAMETER); } /* * Compute Tick Delta: * Handle (max one) timer rollovers on 24-bit versus 32-bit timers. */ if (start_ticks < end_ticks) { delta_ticks = end_ticks - start_ticks; } else if (start_ticks > end_ticks) { if (0 == acpi_gbl_FADT->tmr_val_ext) { /* 24-bit Timer */ delta_ticks = (((0x00FFFFFF - start_ticks) + end_ticks) & 0x00FFFFFF); } else { /* 32-bit Timer */ delta_ticks = (0xFFFFFFFF - start_ticks) + end_ticks; } } else /* start_ticks == end_ticks */ { *time_elapsed = 0; return_ACPI_STATUS (AE_OK); } /* * Compute Duration (Requires a 64-bit multiply and divide): * * time_elapsed = (delta_ticks * 1000000) / PM_TIMER_FREQUENCY; */ status = acpi_ut_short_divide (((u64) delta_ticks) * 1000000, PM_TIMER_FREQUENCY, "ient, NULL); *time_elapsed = (u32) quotient; return_ACPI_STATUS (status); }
acpi_status acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed) { acpi_status status; u32 delta_ticks; acpi_integer quotient; ACPI_FUNCTION_TRACE(acpi_get_timer_duration); if (!time_elapsed) { return_ACPI_STATUS(AE_BAD_PARAMETER); } if (start_ticks < end_ticks) { delta_ticks = end_ticks - start_ticks; } else if (start_ticks > end_ticks) { if ((acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) == 0) { delta_ticks = (((0x00FFFFFF - start_ticks) + end_ticks) & 0x00FFFFFF); } else { delta_ticks = (0xFFFFFFFF - start_ticks) + end_ticks; } } else { *time_elapsed = 0; return_ACPI_STATUS(AE_OK); } status = acpi_ut_short_divide(((u64) delta_ticks) * 1000000, PM_TIMER_FREQUENCY, "ient, NULL); *time_elapsed = (u32) quotient; return_ACPI_STATUS(status); }
acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer) { u32 this_digit = 0; u64 return_value = 0; u64 quotient; u64 dividend; u32 to_integer_op = (base == ACPI_ANY_BASE); u32 mode32 = (acpi_gbl_integer_byte_width == 4); u8 valid_digits = 0; u8 sign_of0x = 0; u8 term = 0; ACPI_FUNCTION_TRACE_STR(ut_strtoul64, string); switch (base) { case ACPI_ANY_BASE: case 16: break; default: /* Invalid Base */ return_ACPI_STATUS(AE_BAD_PARAMETER); } if (!string) { goto error_exit; } /* Skip over any white space in the buffer */ while ((*string) && (isspace((int)*string) || *string == '\t')) { string++; } if (to_integer_op) { /* * Base equal to ACPI_ANY_BASE means 'ToInteger operation case'. * We need to determine if it is decimal or hexadecimal. */ if ((*string == '0') && (tolower((int)*(string + 1)) == 'x')) { sign_of0x = 1; base = 16; /* Skip over the leading '0x' */ string += 2; } else { base = 10; } } /* Any string left? Check that '0x' is not followed by white space. */ if (!(*string) || isspace((int)*string) || *string == '\t') { if (to_integer_op) { goto error_exit; } else { goto all_done; } } /* * Perform a 32-bit or 64-bit conversion, depending upon the current * execution mode of the interpreter */ dividend = (mode32) ? ACPI_UINT32_MAX : ACPI_UINT64_MAX; /* Main loop: convert the string to a 32- or 64-bit integer */ while (*string) { if (isdigit((int)*string)) { /* Convert ASCII 0-9 to Decimal value */ this_digit = ((u8)*string) - '0'; } else if (base == 10) { /* Digit is out of range; possible in to_integer case only */ term = 1; } else { this_digit = (u8)toupper((int)*string); if (isxdigit((int)this_digit)) { /* Convert ASCII Hex char to value */ this_digit = this_digit - 'A' + 10; } else { term = 1; } } if (term) { if (to_integer_op) { goto error_exit; } else { break; } } else if ((valid_digits == 0) && (this_digit == 0) && !sign_of0x) { /* Skip zeros */ string++; continue; } valid_digits++; if (sign_of0x && ((valid_digits > 16) || ((valid_digits > 8) && mode32))) { /* * This is to_integer operation case. * No any restrictions for string-to-integer conversion, * see ACPI spec. */ goto error_exit; } /* Divide the digit into the correct position */ (void)acpi_ut_short_divide((dividend - (u64)this_digit), base, "ient, NULL); if (return_value > quotient) { if (to_integer_op) { goto error_exit; } else { break; } } return_value *= base; return_value += this_digit; string++; } /* All done, normal exit */ all_done: ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Converted value: %8.8X%8.8X\n", ACPI_FORMAT_UINT64(return_value))); *ret_integer = return_value; return_ACPI_STATUS(AE_OK); error_exit: /* Base was set/validated above */ if (base == 10) { return_ACPI_STATUS(AE_BAD_DECIMAL_CONSTANT); } else { return_ACPI_STATUS(AE_BAD_HEX_CONSTANT); } }
static u32 acpi_ex_convert_to_ascii(acpi_integer integer, u16 base, u8 * string, u8 data_width) { acpi_integer digit; acpi_native_uint i; acpi_native_uint j; acpi_native_uint k = 0; acpi_native_uint hex_length; acpi_native_uint decimal_length; u32 remainder; u8 supress_zeros; ACPI_FUNCTION_ENTRY(); switch (base) { case 10: /* Setup max length for the decimal number */ switch (data_width) { case 1: decimal_length = ACPI_MAX8_DECIMAL_DIGITS; break; case 4: decimal_length = ACPI_MAX32_DECIMAL_DIGITS; break; case 8: default: decimal_length = ACPI_MAX64_DECIMAL_DIGITS; break; } supress_zeros = TRUE; /* No leading zeros */ remainder = 0; for (i = decimal_length; i > 0; i--) { /* Divide by nth factor of 10 */ digit = integer; for (j = 0; j < i; j++) { (void)acpi_ut_short_divide(digit, 10, &digit, &remainder); } /* Handle leading zeros */ if (remainder != 0) { supress_zeros = FALSE; } if (!supress_zeros) { string[k] = (u8) (ACPI_ASCII_ZERO + remainder); k++; } } break; case 16: /* hex_length: 2 ascii hex chars per data byte */ hex_length = (acpi_native_uint) ACPI_MUL_2(data_width); for (i = 0, j = (hex_length - 1); i < hex_length; i++, j--) { /* Get one hex digit, most significant digits first */ string[k] = (u8) acpi_ut_hex_to_ascii_char(integer, ACPI_MUL_4(j)); k++; } break; default: return (0); } /* * Since leading zeros are supressed, we must check for the case where * the integer equals 0 * * Finally, null terminate the string and return the length */ if (!k) { string[0] = ACPI_ASCII_ZERO; k = 1; } string[k] = 0; return ((u32) k); }
/******************************************************************************* * * FUNCTION: acpi_ex_system_memory_space_handler * * PARAMETERS: Function - Read or Write operation * Address - Where in the space to read or write * bit_width - Field width in bits (8, 16, or 32) * Value - Pointer to in or out value * handler_context - Pointer to Handler's context * region_context - Pointer to context specific to the * accessed region * * RETURN: Status * * DESCRIPTION: Handler for the System Memory address space (Op Region) * ******************************************************************************/ acpi_status acpi_ex_system_memory_space_handler(u32 function, acpi_physical_address address, u32 bit_width, u64 *value, void *handler_context, void *region_context) { acpi_status status = AE_OK; void *logical_addr_ptr = NULL; struct acpi_mem_space_context *mem_info = region_context; u32 length; acpi_size map_length; acpi_size page_boundary_map_length; #ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED u32 remainder; #endif ACPI_FUNCTION_TRACE(ex_system_memory_space_handler); /* Validate and translate the bit width */ switch (bit_width) { case 8: length = 1; break; case 16: length = 2; break; case 32: length = 4; break; case 64: length = 8; break; default: ACPI_ERROR((AE_INFO, "Invalid SystemMemory width %u", bit_width)); return_ACPI_STATUS(AE_AML_OPERAND_VALUE); } #ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED /* * Hardware does not support non-aligned data transfers, we must verify * the request. */ (void)acpi_ut_short_divide((u64) address, length, NULL, &remainder); if (remainder != 0) { return_ACPI_STATUS(AE_AML_ALIGNMENT); } #endif /* * Does the request fit into the cached memory mapping? * Is 1) Address below the current mapping? OR * 2) Address beyond the current mapping? */ if ((address < mem_info->mapped_physical_address) || (((u64) address + length) > ((u64) mem_info->mapped_physical_address + mem_info->mapped_length))) { /* * The request cannot be resolved by the current memory mapping; * Delete the existing mapping and create a new one. */ if (mem_info->mapped_length) { /* Valid mapping, delete it */ acpi_os_unmap_memory(mem_info->mapped_logical_address, mem_info->mapped_length); } /* * Attempt to map from the requested address to the end of the region. * However, we will never map more than one page, nor will we cross * a page boundary. */ map_length = (acpi_size) ((mem_info->address + mem_info->length) - address); /* * If mapping the entire remaining portion of the region will cross * a page boundary, just map up to the page boundary, do not cross. * On some systems, crossing a page boundary while mapping regions * can cause warnings if the pages have different attributes * due to resource management */ page_boundary_map_length = ACPI_ROUND_UP(address, ACPI_DEFAULT_PAGE_SIZE) - address; if (!page_boundary_map_length) { page_boundary_map_length = ACPI_DEFAULT_PAGE_SIZE; } if (map_length > page_boundary_map_length) { map_length = page_boundary_map_length; } /* Create a new mapping starting at the address given */ mem_info->mapped_logical_address = acpi_os_map_memory((acpi_physical_address) address, map_length); if (!mem_info->mapped_logical_address) { ACPI_ERROR((AE_INFO, "Could not map memory at 0x%8.8X%8.8X, size %u", ACPI_FORMAT_NATIVE_UINT(address), (u32) map_length)); mem_info->mapped_length = 0; return_ACPI_STATUS(AE_NO_MEMORY); } /* Save the physical address and mapping size */ mem_info->mapped_physical_address = address; mem_info->mapped_length = map_length; } /* * Generate a logical pointer corresponding to the address we want to * access */ logical_addr_ptr = mem_info->mapped_logical_address + ((u64) address - (u64) mem_info->mapped_physical_address); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "System-Memory (width %u) R/W %u Address=%8.8X%8.8X\n", bit_width, function, ACPI_FORMAT_NATIVE_UINT(address))); /* * Perform the memory read or write * * Note: For machines that do not support non-aligned transfers, the target * address was checked for alignment above. We do not attempt to break the * transfer up into smaller (byte-size) chunks because the AML specifically * asked for a transfer width that the hardware may require. */ switch (function) { case ACPI_READ: *value = 0; switch (bit_width) { case 8: *value = (u64) ACPI_GET8(logical_addr_ptr); break; case 16: *value = (u64) ACPI_GET16(logical_addr_ptr); break; case 32: *value = (u64) ACPI_GET32(logical_addr_ptr); break; case 64: *value = (u64) ACPI_GET64(logical_addr_ptr); break; default: /* bit_width was already validated */ break; } break; case ACPI_WRITE: switch (bit_width) { case 8: ACPI_SET8(logical_addr_ptr) = (u8) * value; break; case 16: ACPI_SET16(logical_addr_ptr) = (u16) * value; break; case 32: ACPI_SET32(logical_addr_ptr) = (u32) * value; break; case 64: ACPI_SET64(logical_addr_ptr) = (u64) * value; break; default: /* bit_width was already validated */ break; } break; default: status = AE_BAD_PARAMETER; break; } return_ACPI_STATUS(status); }
acpi_status acpi_ex_system_memory_space_handler ( u32 function, acpi_physical_address address, u32 bit_width, acpi_integer *value, void *handler_context, void *region_context) { acpi_status status = AE_OK; void *logical_addr_ptr = NULL; struct acpi_mem_space_context *mem_info = region_context; u32 length; acpi_size window_size; #ifndef ACPI_MISALIGNED_TRANSFERS u32 remainder; #endif ACPI_FUNCTION_TRACE ("ex_system_memory_space_handler"); /* Validate and translate the bit width */ switch (bit_width) { case 8: length = 1; break; case 16: length = 2; break; case 32: length = 4; break; case 64: length = 8; break; default: ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid system_memory width %d\n", bit_width)); return_ACPI_STATUS (AE_AML_OPERAND_VALUE); } #ifndef ACPI_MISALIGNED_TRANSFERS /* * Hardware does not support non-aligned data transfers, we must verify * the request. */ (void) acpi_ut_short_divide ((acpi_integer) address, length, NULL, &remainder); if (remainder != 0) { return_ACPI_STATUS (AE_AML_ALIGNMENT); } #endif /* * Does the request fit into the cached memory mapping? * Is 1) Address below the current mapping? OR * 2) Address beyond the current mapping? */ if ((address < mem_info->mapped_physical_address) || (((acpi_integer) address + length) > ((acpi_integer) mem_info->mapped_physical_address + mem_info->mapped_length))) { /* * The request cannot be resolved by the current memory mapping; * Delete the existing mapping and create a new one. */ if (mem_info->mapped_length) { /* Valid mapping, delete it */ acpi_os_unmap_memory (mem_info->mapped_logical_address, mem_info->mapped_length); } /* * Don't attempt to map memory beyond the end of the region, and * constrain the maximum mapping size to something reasonable. */ window_size = (acpi_size) ((mem_info->address + mem_info->length) - address); if (window_size > ACPI_SYSMEM_REGION_WINDOW_SIZE) { window_size = ACPI_SYSMEM_REGION_WINDOW_SIZE; } /* Create a new mapping starting at the address given */ status = acpi_os_map_memory (address, window_size, (void **) &mem_info->mapped_logical_address); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %8.8X%8.8X, size %X\n", ACPI_FORMAT_UINT64 (address), (u32) window_size)); mem_info->mapped_length = 0; return_ACPI_STATUS (status); } /* Save the physical address and mapping size */ mem_info->mapped_physical_address = address; mem_info->mapped_length = window_size; } /* * Generate a logical pointer corresponding to the address we want to * access */ logical_addr_ptr = mem_info->mapped_logical_address + ((acpi_integer) address - (acpi_integer) mem_info->mapped_physical_address); ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "system_memory %d (%d width) Address=%8.8X%8.8X\n", function, bit_width, ACPI_FORMAT_UINT64 (address))); /* * Perform the memory read or write * * Note: For machines that do not support non-aligned transfers, the target * address was checked for alignment above. We do not attempt to break the * transfer up into smaller (byte-size) chunks because the AML specifically * asked for a transfer width that the hardware may require. */ switch (function) { case ACPI_READ: *value = 0; switch (bit_width) { case 8: *value = (acpi_integer) *((u8 *) logical_addr_ptr); break; case 16: *value = (acpi_integer) *((u16 *) logical_addr_ptr); break; case 32: *value = (acpi_integer) *((u32 *) logical_addr_ptr); break; #if ACPI_MACHINE_WIDTH != 16 case 64: *value = (acpi_integer) *((u64 *) logical_addr_ptr); break; #endif default: /* bit_width was already validated */ break; } break; case ACPI_WRITE: switch (bit_width) { case 8: *(u8 *) logical_addr_ptr = (u8) *value; break; case 16: *(u16 *) logical_addr_ptr = (u16) *value; break; case 32: *(u32 *) logical_addr_ptr = (u32) *value; break; #if ACPI_MACHINE_WIDTH != 16 case 64: *(u64 *) logical_addr_ptr = (u64) *value; break; #endif default: /* bit_width was already validated */ break; } break; default: status = AE_BAD_PARAMETER; break; } return_ACPI_STATUS (status); }
acpi_status acpi_ut_strtoul64 ( char *string, u32 base, acpi_integer *ret_integer) { u32 this_digit = 0; acpi_integer return_value = 0; acpi_integer quotient; ACPI_FUNCTION_TRACE ("ut_stroul64"); if ((!string) || !(*string)) { goto error_exit; } switch (base) { case ACPI_ANY_BASE: case 10: case 16: break; default: /* Invalid Base */ return_ACPI_STATUS (AE_BAD_PARAMETER); } /* Skip over any white space in the buffer */ while (ACPI_IS_SPACE (*string) || *string == '\t') { string++; } /* * If the input parameter Base is zero, then we need to * determine if it is decimal or hexadecimal: */ if (base == 0) { if ((*string == '0') && (ACPI_TOLOWER (*(string + 1)) == 'x')) { base = 16; string += 2; } else { base = 10; } } /* * For hexadecimal base, skip over the leading * 0 or 0x, if they are present. */ if ((base == 16) && (*string == '0') && (ACPI_TOLOWER (*(string + 1)) == 'x')) { string += 2; } /* Any string left? */ if (!(*string)) { goto error_exit; } /* Main loop: convert the string to a 64-bit integer */ while (*string) { if (ACPI_IS_DIGIT (*string)) { /* Convert ASCII 0-9 to Decimal value */ this_digit = ((u8) *string) - '0'; } else { if (base == 10) { /* Digit is out of range */ goto error_exit; } this_digit = (u8) ACPI_TOUPPER (*string); if (ACPI_IS_XDIGIT ((char) this_digit)) { /* Convert ASCII Hex char to value */ this_digit = this_digit - 'A' + 10; } else { /* * We allow non-hex chars, just stop now, same as end-of-string. * See ACPI spec, string-to-integer conversion. */ break; } } /* Divide the digit into the correct position */ (void) acpi_ut_short_divide ((ACPI_INTEGER_MAX - (acpi_integer) this_digit), base, "ient, NULL); if (return_value > quotient) { goto error_exit; } return_value *= base; return_value += this_digit; string++; } /* All done, normal exit */ *ret_integer = return_value; return_ACPI_STATUS (AE_OK); error_exit: /* Base was set/validated above */ if (base == 10) { return_ACPI_STATUS (AE_BAD_DECIMAL_CONSTANT); } else { return_ACPI_STATUS (AE_BAD_HEX_CONSTANT); } }
acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state) { acpi_status status = AE_OK; union acpi_operand_object **operand = &walk_state->operands[0]; union acpi_operand_object *return_desc = NULL; union acpi_operand_object *return_desc2 = NULL; u32 temp32; u32 i; acpi_integer power_of_ten; acpi_integer digit; ACPI_FUNCTION_TRACE_STR(ex_opcode_1A_1T_1R, acpi_ps_get_opcode_name(walk_state->opcode)); /* Examine the AML opcode */ switch (walk_state->opcode) { case AML_BIT_NOT_OP: case AML_FIND_SET_LEFT_BIT_OP: case AML_FIND_SET_RIGHT_BIT_OP: case AML_FROM_BCD_OP: case AML_TO_BCD_OP: case AML_COND_REF_OF_OP: /* Create a return object of type Integer for these opcodes */ return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; } switch (walk_state->opcode) { case AML_BIT_NOT_OP: /* Not (Operand, Result) */ return_desc->integer.value = ~operand[0]->integer.value; break; case AML_FIND_SET_LEFT_BIT_OP: /* find_set_left_bit (Operand, Result) */ return_desc->integer.value = operand[0]->integer.value; /* * Acpi specification describes Integer type as a little * endian unsigned value, so this boundary condition is valid. */ for (temp32 = 0; return_desc->integer.value && temp32 < ACPI_INTEGER_BIT_SIZE; ++temp32) { return_desc->integer.value >>= 1; } return_desc->integer.value = temp32; break; case AML_FIND_SET_RIGHT_BIT_OP: /* find_set_right_bit (Operand, Result) */ return_desc->integer.value = operand[0]->integer.value; /* * The Acpi specification describes Integer type as a little * endian unsigned value, so this boundary condition is valid. */ for (temp32 = 0; return_desc->integer.value && temp32 < ACPI_INTEGER_BIT_SIZE; ++temp32) { return_desc->integer.value <<= 1; } /* Since the bit position is one-based, subtract from 33 (65) */ return_desc->integer.value = temp32 == 0 ? 0 : (ACPI_INTEGER_BIT_SIZE + 1) - temp32; break; case AML_FROM_BCD_OP: /* from_bcd (BCDValue, Result) */ /* * The 64-bit ACPI integer can hold 16 4-bit BCD characters * (if table is 32-bit, integer can hold 8 BCD characters) * Convert each 4-bit BCD value */ power_of_ten = 1; return_desc->integer.value = 0; digit = operand[0]->integer.value; /* Convert each BCD digit (each is one nybble wide) */ for (i = 0; (i < acpi_gbl_integer_nybble_width) && (digit > 0); i++) { /* Get the least significant 4-bit BCD digit */ temp32 = ((u32) digit) & 0xF; /* Check the range of the digit */ if (temp32 > 9) { ACPI_ERROR((AE_INFO, "BCD digit too large (not decimal): 0x%X", temp32)); status = AE_AML_NUMERIC_OVERFLOW; goto cleanup; } /* Sum the digit into the result with the current power of 10 */ return_desc->integer.value += (((acpi_integer) temp32) * power_of_ten); /* Shift to next BCD digit */ digit >>= 4; /* Next power of 10 */ power_of_ten *= 10; } break; case AML_TO_BCD_OP: /* to_bcd (Operand, Result) */ return_desc->integer.value = 0; digit = operand[0]->integer.value; /* Each BCD digit is one nybble wide */ for (i = 0; (i < acpi_gbl_integer_nybble_width) && (digit > 0); i++) { (void)acpi_ut_short_divide(digit, 10, &digit, &temp32); /* * Insert the BCD digit that resides in the * remainder from above */ return_desc->integer.value |= (((acpi_integer) temp32) << ACPI_MUL_4(i)); } /* Overflow if there is any data left in Digit */ if (digit > 0) { ACPI_ERROR((AE_INFO, "Integer too large to convert to BCD: %8.8X%8.8X", ACPI_FORMAT_UINT64(operand[0]-> integer.value))); status = AE_AML_NUMERIC_OVERFLOW; goto cleanup; } break; case AML_COND_REF_OF_OP: /* cond_ref_of (source_object, Result) */ /* * This op is a little strange because the internal return value is * different than the return value stored in the result descriptor * (There are really two return values) */ if ((struct acpi_namespace_node *)operand[0] == acpi_gbl_root_node) { /* * This means that the object does not exist in the namespace, * return FALSE */ return_desc->integer.value = 0; goto cleanup; } /* Get the object reference, store it, and remove our reference */ status = acpi_ex_get_object_reference(operand[0], &return_desc2, walk_state); if (ACPI_FAILURE(status)) { goto cleanup; } status = acpi_ex_store(return_desc2, operand[1], walk_state); acpi_ut_remove_reference(return_desc2); /* The object exists in the namespace, return TRUE */ return_desc->integer.value = ACPI_INTEGER_MAX; goto cleanup; default: /* No other opcodes get here */ break; } break; case AML_STORE_OP: /* Store (Source, Target) */ /* * A store operand is typically a number, string, buffer or lvalue * Be careful about deleting the source object, * since the object itself may have been stored. */ status = acpi_ex_store(operand[0], operand[1], walk_state); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* It is possible that the Store already produced a return object */ if (!walk_state->result_obj) { /* * Normally, we would remove a reference on the Operand[0] * parameter; But since it is being used as the internal return * object (meaning we would normally increment it), the two * cancel out, and we simply don't do anything. */ walk_state->result_obj = operand[0]; walk_state->operands[0] = NULL; /* Prevent deletion */ } return_ACPI_STATUS(status); /* * ACPI 2.0 Opcodes */ case AML_COPY_OP: /* Copy (Source, Target) */ status = acpi_ut_copy_iobject_to_iobject(operand[0], &return_desc, walk_state); break; case AML_TO_DECSTRING_OP: /* to_decimal_string (Data, Result) */ status = acpi_ex_convert_to_string(operand[0], &return_desc, ACPI_EXPLICIT_CONVERT_DECIMAL); if (return_desc == operand[0]) { /* No conversion performed, add ref to handle return value */ acpi_ut_add_reference(return_desc); } break; case AML_TO_HEXSTRING_OP: /* to_hex_string (Data, Result) */ status = acpi_ex_convert_to_string(operand[0], &return_desc, ACPI_EXPLICIT_CONVERT_HEX); if (return_desc == operand[0]) { /* No conversion performed, add ref to handle return value */ acpi_ut_add_reference(return_desc); } break; case AML_TO_BUFFER_OP: /* to_buffer (Data, Result) */ status = acpi_ex_convert_to_buffer(operand[0], &return_desc); if (return_desc == operand[0]) { /* No conversion performed, add ref to handle return value */ acpi_ut_add_reference(return_desc); } break; case AML_TO_INTEGER_OP: /* to_integer (Data, Result) */ status = acpi_ex_convert_to_integer(operand[0], &return_desc, ACPI_ANY_BASE); if (return_desc == operand[0]) { /* No conversion performed, add ref to handle return value */ acpi_ut_add_reference(return_desc); } break; case AML_SHIFT_LEFT_BIT_OP: /* shift_left_bit (Source, bit_num) */ case AML_SHIFT_RIGHT_BIT_OP: /* shift_right_bit (Source, bit_num) */ /* These are two obsolete opcodes */ ACPI_ERROR((AE_INFO, "%s is obsolete and not implemented", acpi_ps_get_opcode_name(walk_state->opcode))); status = AE_SUPPORT; goto cleanup; default: /* Unknown opcode */ ACPI_ERROR((AE_INFO, "Unknown AML opcode %X", walk_state->opcode)); status = AE_AML_BAD_OPCODE; goto cleanup; } if (ACPI_SUCCESS(status)) { /* Store the return value computed above into the target object */ status = acpi_ex_store(return_desc, operand[1], walk_state); } cleanup: /* Delete return object on error */ if (ACPI_FAILURE(status)) { acpi_ut_remove_reference(return_desc); } /* Save return object on success */ else if (!walk_state->result_obj) { walk_state->result_obj = return_desc; } return_ACPI_STATUS(status); }