acpi_status acpi_ex_do_concatenate(union acpi_operand_object *operand0, union acpi_operand_object *operand1, union acpi_operand_object **actual_return_desc, struct acpi_walk_state *walk_state) { union acpi_operand_object *local_operand0 = operand0; union acpi_operand_object *local_operand1 = operand1; union acpi_operand_object *temp_operand1 = NULL; union acpi_operand_object *return_desc; char *buffer; acpi_object_type operand0_type; acpi_object_type operand1_type; acpi_status status; ACPI_FUNCTION_TRACE(ex_do_concatenate); /* Operand 0 preprocessing */ switch (operand0->common.type) { case ACPI_TYPE_INTEGER: case ACPI_TYPE_STRING: case ACPI_TYPE_BUFFER: operand0_type = operand0->common.type; break; default: /* For all other types, get the "object type" string */ status = acpi_ex_convert_to_object_type_string(operand0, &local_operand0); if (ACPI_FAILURE(status)) { goto cleanup; } operand0_type = ACPI_TYPE_STRING; break; } /* Operand 1 preprocessing */ switch (operand1->common.type) { case ACPI_TYPE_INTEGER: case ACPI_TYPE_STRING: case ACPI_TYPE_BUFFER: operand1_type = operand1->common.type; break; default: /* For all other types, get the "object type" string */ status = acpi_ex_convert_to_object_type_string(operand1, &local_operand1); if (ACPI_FAILURE(status)) { goto cleanup; } operand1_type = ACPI_TYPE_STRING; break; } /* * Convert the second operand if necessary. The first operand (0) * determines the type of the second operand (1) (See the Data Types * section of the ACPI specification). Both object types are * guaranteed to be either Integer/String/Buffer by the operand * resolution mechanism. */ switch (operand0_type) { case ACPI_TYPE_INTEGER: status = acpi_ex_convert_to_integer(local_operand1, &temp_operand1, 16); break; case ACPI_TYPE_BUFFER: status = acpi_ex_convert_to_buffer(local_operand1, &temp_operand1); break; case ACPI_TYPE_STRING: switch (operand1_type) { case ACPI_TYPE_INTEGER: case ACPI_TYPE_STRING: case ACPI_TYPE_BUFFER: /* Other types have already been converted to string */ status = acpi_ex_convert_to_string(local_operand1, &temp_operand1, ACPI_IMPLICIT_CONVERT_HEX); break; default: status = AE_OK; break; } break; default: ACPI_ERROR((AE_INFO, "Invalid object type: 0x%X", operand0->common.type)); status = AE_AML_INTERNAL; } if (ACPI_FAILURE(status)) { goto cleanup; } /* Take care with any newly created operand objects */ if ((local_operand1 != operand1) && (local_operand1 != temp_operand1)) { acpi_ut_remove_reference(local_operand1); } local_operand1 = temp_operand1; /* * Both operands are now known to be the same object type * (Both are Integer, String, or Buffer), and we can now perform * the concatenation. * * There are three cases to handle, as per the ACPI spec: * * 1) Two Integers concatenated to produce a new Buffer * 2) Two Strings concatenated to produce a new String * 3) Two Buffers concatenated to produce a new Buffer */ switch (operand0_type) { case ACPI_TYPE_INTEGER: /* Result of two Integers is a Buffer */ /* Need enough buffer space for two integers */ return_desc = acpi_ut_create_buffer_object((acpi_size) ACPI_MUL_2 (acpi_gbl_integer_byte_width)); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; } buffer = (char *)return_desc->buffer.pointer; /* Copy the first integer, LSB first */ memcpy(buffer, &operand0->integer.value, acpi_gbl_integer_byte_width); /* Copy the second integer (LSB first) after the first */ memcpy(buffer + acpi_gbl_integer_byte_width, &local_operand1->integer.value, acpi_gbl_integer_byte_width); break; case ACPI_TYPE_STRING: /* Result of two Strings is a String */ return_desc = acpi_ut_create_string_object(((acpi_size) local_operand0-> string.length + local_operand1-> string.length)); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; } buffer = return_desc->string.pointer; /* Concatenate the strings */ strcpy(buffer, local_operand0->string.pointer); strcat(buffer, local_operand1->string.pointer); break; case ACPI_TYPE_BUFFER: /* Result of two Buffers is a Buffer */ return_desc = acpi_ut_create_buffer_object(((acpi_size) operand0->buffer. length + local_operand1-> buffer.length)); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; } buffer = (char *)return_desc->buffer.pointer; /* Concatenate the buffers */ memcpy(buffer, operand0->buffer.pointer, operand0->buffer.length); memcpy(buffer + operand0->buffer.length, local_operand1->buffer.pointer, local_operand1->buffer.length); break; default: /* Invalid object type, should not happen here */ ACPI_ERROR((AE_INFO, "Invalid object type: 0x%X", operand0->common.type)); status = AE_AML_INTERNAL; goto cleanup; } *actual_return_desc = return_desc; cleanup: if (local_operand0 != operand0) { acpi_ut_remove_reference(local_operand0); } if (local_operand1 != operand1) { acpi_ut_remove_reference(local_operand1); } return_ACPI_STATUS(status); }
acpi_status acpi_ex_convert_to_target_type(acpi_object_type destination_type, union acpi_operand_object *source_desc, union acpi_operand_object **result_desc, struct acpi_walk_state *walk_state) { acpi_status status = AE_OK; ACPI_FUNCTION_TRACE(ex_convert_to_target_type); /* Default behavior */ *result_desc = source_desc; /* * If required by the target, * perform implicit conversion on the source before we store it. */ switch (GET_CURRENT_ARG_TYPE(walk_state->op_info->runtime_args)) { case ARGI_SIMPLE_TARGET: case ARGI_FIXED_TARGET: case ARGI_INTEGER_REF: /* Handles Increment, Decrement cases */ switch (destination_type) { case ACPI_TYPE_LOCAL_REGION_FIELD: /* * Named field can always handle conversions */ break; default: /* No conversion allowed for these types */ if (destination_type != ACPI_GET_OBJECT_TYPE(source_desc)) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Explicit operator, will store (%s) over existing type (%s)\n", acpi_ut_get_object_type_name (source_desc), acpi_ut_get_type_name (destination_type))); status = AE_TYPE; } } break; case ARGI_TARGETREF: switch (destination_type) { case ACPI_TYPE_INTEGER: case ACPI_TYPE_BUFFER_FIELD: case ACPI_TYPE_LOCAL_BANK_FIELD: case ACPI_TYPE_LOCAL_INDEX_FIELD: /* * These types require an Integer operand. We can convert * a Buffer or a String to an Integer if necessary. */ status = acpi_ex_convert_to_integer(source_desc, result_desc, 16); break; case ACPI_TYPE_STRING: /* * The operand must be a String. We can convert an * Integer or Buffer if necessary */ status = acpi_ex_convert_to_string(source_desc, result_desc, ACPI_IMPLICIT_CONVERT_HEX); break; case ACPI_TYPE_BUFFER: /* * The operand must be a Buffer. We can convert an * Integer or String if necessary */ status = acpi_ex_convert_to_buffer(source_desc, result_desc); break; default: ACPI_ERROR((AE_INFO, "Bad destination type during conversion: %X", destination_type)); status = AE_AML_INTERNAL; break; } break; case ARGI_REFERENCE: /* * create_xxxx_field cases - we are storing the field object into the name */ break; default: ACPI_ERROR((AE_INFO, "Unknown Target type ID 0x%X AmlOpcode %X DestType %s", GET_CURRENT_ARG_TYPE(walk_state->op_info->runtime_args), walk_state->opcode, acpi_ut_get_type_name(destination_type))); status = AE_AML_INTERNAL; } /* * Source-to-Target conversion semantics: * * If conversion to the target type cannot be performed, then simply * overwrite the target with the new object and type. */ if (status == AE_TYPE) { status = AE_OK; } return_ACPI_STATUS(status); }
acpi_status acpi_ex_do_logical_op ( u16 opcode, union acpi_operand_object *operand0, union acpi_operand_object *operand1, u8 *logical_result) { union acpi_operand_object *local_operand1 = operand1; acpi_integer integer0; acpi_integer integer1; u32 length0; u32 length1; acpi_status status = AE_OK; u8 local_result = FALSE; int compare; ACPI_FUNCTION_TRACE ("ex_do_logical_op"); /* * Convert the second operand if necessary. The first operand * determines the type of the second operand, (See the Data Types * section of the ACPI 3.0+ specification.) Both object types are * guaranteed to be either Integer/String/Buffer by the operand * resolution mechanism. */ switch (ACPI_GET_OBJECT_TYPE (operand0)) { case ACPI_TYPE_INTEGER: status = acpi_ex_convert_to_integer (operand1, &local_operand1, 16); break; case ACPI_TYPE_STRING: status = acpi_ex_convert_to_string (operand1, &local_operand1, ACPI_IMPLICIT_CONVERT_HEX); break; case ACPI_TYPE_BUFFER: status = acpi_ex_convert_to_buffer (operand1, &local_operand1); break; default: status = AE_AML_INTERNAL; break; } if (ACPI_FAILURE (status)) { goto cleanup; } /* * Two cases: 1) Both Integers, 2) Both Strings or Buffers */ if (ACPI_GET_OBJECT_TYPE (operand0) == ACPI_TYPE_INTEGER) { /* * 1) Both operands are of type integer * Note: local_operand1 may have changed above */ integer0 = operand0->integer.value; integer1 = local_operand1->integer.value; switch (opcode) { case AML_LEQUAL_OP: /* LEqual (Operand0, Operand1) */ if (integer0 == integer1) { local_result = TRUE; } break; case AML_LGREATER_OP: /* LGreater (Operand0, Operand1) */ if (integer0 > integer1) { local_result = TRUE; } break; case AML_LLESS_OP: /* LLess (Operand0, Operand1) */ if (integer0 < integer1) { local_result = TRUE; } break; default: status = AE_AML_INTERNAL; break; } } else { /* * 2) Both operands are Strings or both are Buffers * Note: Code below takes advantage of common Buffer/String * object fields. local_operand1 may have changed above. Use * memcmp to handle nulls in buffers. */ length0 = operand0->buffer.length; length1 = local_operand1->buffer.length; /* Lexicographic compare: compare the data bytes */ compare = ACPI_MEMCMP ((const char * ) operand0->buffer.pointer, (const char * ) local_operand1->buffer.pointer, (length0 > length1) ? length1 : length0); switch (opcode) { case AML_LEQUAL_OP: /* LEqual (Operand0, Operand1) */ /* Length and all bytes must be equal */ if ((length0 == length1) && (compare == 0)) { /* Length and all bytes match ==> TRUE */ local_result = TRUE; } break; case AML_LGREATER_OP: /* LGreater (Operand0, Operand1) */ if (compare > 0) { local_result = TRUE; goto cleanup; /* TRUE */ } if (compare < 0) { goto cleanup; /* FALSE */ } /* Bytes match (to shortest length), compare lengths */ if (length0 > length1) { local_result = TRUE; } break; case AML_LLESS_OP: /* LLess (Operand0, Operand1) */ if (compare > 0) { goto cleanup; /* FALSE */ } if (compare < 0) { local_result = TRUE; goto cleanup; /* TRUE */ } /* Bytes match (to shortest length), compare lengths */ if (length0 < length1) { local_result = TRUE; } break; default: status = AE_AML_INTERNAL; break; } } cleanup: /* New object was created if implicit conversion performed - delete */ if (local_operand1 != operand1) { acpi_ut_remove_reference (local_operand1); } /* Return the logical result and status */ *logical_result = local_result; return_ACPI_STATUS (status); }
acpi_status acpi_ex_do_concatenate ( union acpi_operand_object *operand0, union acpi_operand_object *operand1, union acpi_operand_object **actual_return_desc, struct acpi_walk_state *walk_state) { union acpi_operand_object *local_operand1 = operand1; union acpi_operand_object *return_desc; char *new_buf; acpi_status status; acpi_size new_length; ACPI_FUNCTION_TRACE ("ex_do_concatenate"); /* * Convert the second operand if necessary. The first operand * determines the type of the second operand, (See the Data Types * section of the ACPI specification.) Both object types are * guaranteed to be either Integer/String/Buffer by the operand * resolution mechanism. */ switch (ACPI_GET_OBJECT_TYPE (operand0)) { case ACPI_TYPE_INTEGER: status = acpi_ex_convert_to_integer (operand1, &local_operand1, 16); break; case ACPI_TYPE_STRING: status = acpi_ex_convert_to_string (operand1, &local_operand1, ACPI_IMPLICIT_CONVERT_HEX); break; case ACPI_TYPE_BUFFER: status = acpi_ex_convert_to_buffer (operand1, &local_operand1); break; default: ACPI_REPORT_ERROR (("Concat - invalid obj type: %X\n", ACPI_GET_OBJECT_TYPE (operand0))); status = AE_AML_INTERNAL; } if (ACPI_FAILURE (status)) { goto cleanup; } /* * Both operands are now known to be the same object type * (Both are Integer, String, or Buffer), and we can now perform the * concatenation. */ /* * There are three cases to handle: * * 1) Two Integers concatenated to produce a new Buffer * 2) Two Strings concatenated to produce a new String * 3) Two Buffers concatenated to produce a new Buffer */ switch (ACPI_GET_OBJECT_TYPE (operand0)) { case ACPI_TYPE_INTEGER: /* Result of two Integers is a Buffer */ /* Need enough buffer space for two integers */ return_desc = acpi_ut_create_buffer_object ( ACPI_MUL_2 (acpi_gbl_integer_byte_width)); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; } new_buf = (char *) return_desc->buffer.pointer; /* Copy the first integer, LSB first */ ACPI_MEMCPY (new_buf, &operand0->integer.value, acpi_gbl_integer_byte_width); /* Copy the second integer (LSB first) after the first */ ACPI_MEMCPY (new_buf + acpi_gbl_integer_byte_width, &local_operand1->integer.value, acpi_gbl_integer_byte_width); break; case ACPI_TYPE_STRING: /* Result of two Strings is a String */ new_length = (acpi_size) operand0->string.length + (acpi_size) local_operand1->string.length; if (new_length > ACPI_MAX_STRING_CONVERSION) { status = AE_AML_STRING_LIMIT; goto cleanup; } return_desc = acpi_ut_create_string_object (new_length); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; } new_buf = return_desc->string.pointer; /* Concatenate the strings */ ACPI_STRCPY (new_buf, operand0->string.pointer); ACPI_STRCPY (new_buf + operand0->string.length, local_operand1->string.pointer); break; case ACPI_TYPE_BUFFER: /* Result of two Buffers is a Buffer */ return_desc = acpi_ut_create_buffer_object ( (acpi_size) operand0->buffer.length + (acpi_size) local_operand1->buffer.length); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; } new_buf = (char *) return_desc->buffer.pointer; /* Concatenate the buffers */ ACPI_MEMCPY (new_buf, operand0->buffer.pointer, operand0->buffer.length); ACPI_MEMCPY (new_buf + operand0->buffer.length, local_operand1->buffer.pointer, local_operand1->buffer.length); break; default: /* Invalid object type, should not happen here */ ACPI_REPORT_ERROR (("Concatenate - Invalid object type: %X\n", ACPI_GET_OBJECT_TYPE (operand0))); status =AE_AML_INTERNAL; goto cleanup; } *actual_return_desc = return_desc; cleanup: if (local_operand1 != operand1) { acpi_ut_remove_reference (local_operand1); } return_ACPI_STATUS (AE_OK); }
acpi_status acpi_ns_convert_to_string(union acpi_operand_object *original_object, union acpi_operand_object **return_object) { union acpi_operand_object *new_object; acpi_size length; acpi_status status; switch (original_object->common.type) { case ACPI_TYPE_INTEGER: /* * Integer-to-String conversion. Commonly, convert * an integer of value 0 to a NULL string. The last element of * _BIF and _BIX packages occasionally need this fix. */ if (original_object->integer.value == 0) { /* Allocate a new NULL string object */ new_object = acpi_ut_create_string_object(0); if (!new_object) { return (AE_NO_MEMORY); } } else { status = acpi_ex_convert_to_string(original_object, &new_object, ACPI_IMPLICIT_CONVERT_HEX); if (ACPI_FAILURE(status)) { return (status); } } break; case ACPI_TYPE_BUFFER: /* * Buffer-to-String conversion. Use a to_string * conversion, no transform performed on the buffer data. The best * example of this is the _BIF method, where the string data from * the battery is often (incorrectly) returned as buffer object(s). */ length = 0; while ((length < original_object->buffer.length) && (original_object->buffer.pointer[length])) { length++; } /* Allocate a new string object */ new_object = acpi_ut_create_string_object(length); if (!new_object) { return (AE_NO_MEMORY); } /* * Copy the raw buffer data with no transform. String is already NULL * terminated at Length+1. */ ACPI_MEMCPY(new_object->string.pointer, original_object->buffer.pointer, length); break; default: return (AE_AML_OPERAND_TYPE); } *return_object = new_object; return (AE_OK); }
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); }
acpi_status acpi_ex_opcode_2A_1T_1R ( acpi_walk_state *walk_state) { acpi_operand_object **operand = &walk_state->operands[0]; acpi_operand_object *return_desc = NULL; acpi_operand_object *temp_desc; u32 index; acpi_status status = AE_OK; FUNCTION_TRACE_STR ("Ex_opcode_2A_1T_1R", acpi_ps_get_opcode_name (walk_state->opcode)); /* * Execute the opcode */ if (walk_state->op_info->flags & AML_MATH) { /* All simple math opcodes (add, etc.) */ return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; } return_desc->integer.value = acpi_ex_do_math_op (walk_state->opcode, operand[0]->integer.value, operand[1]->integer.value); goto store_result_to_target; } switch (walk_state->opcode) { case AML_MOD_OP: /* Mod (Dividend, Divisor, Remainder_result (ACPI 2.0) */ return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; } /* Return_desc will contain the remainder */ status = acpi_ut_divide (&operand[0]->integer.value, &operand[1]->integer.value, NULL, &return_desc->integer.value); break; case AML_CONCAT_OP: /* Concatenate (Data1, Data2, Result) */ /* * Convert the second operand if necessary. The first operand * determines the type of the second operand, (See the Data Types * section of the ACPI specification.) Both object types are * guaranteed to be either Integer/String/Buffer by the operand * resolution mechanism above. */ switch (operand[0]->common.type) { case ACPI_TYPE_INTEGER: status = acpi_ex_convert_to_integer (operand[1], &operand[1], walk_state); break; case ACPI_TYPE_STRING: status = acpi_ex_convert_to_string (operand[1], &operand[1], 16, ACPI_UINT32_MAX, walk_state); break; case ACPI_TYPE_BUFFER: status = acpi_ex_convert_to_buffer (operand[1], &operand[1], walk_state); break; default: status = AE_AML_INTERNAL; } if (ACPI_FAILURE (status)) { goto cleanup; } /* * Both operands are now known to be the same object type * (Both are Integer, String, or Buffer), and we can now perform the * concatenation. */ status = acpi_ex_do_concatenate (operand[0], operand[1], &return_desc, walk_state); break; case AML_TO_STRING_OP: /* To_string (Buffer, Length, Result) (ACPI 2.0) */ status = acpi_ex_convert_to_string (operand[0], &return_desc, 16, (u32) operand[1]->integer.value, walk_state); break; case AML_CONCAT_RES_OP: /* Concatenate_res_template (Buffer, Buffer, Result) (ACPI 2.0) */ status = AE_NOT_IMPLEMENTED; break; case AML_INDEX_OP: /* Index (Source Index Result) */ /* Create the internal return object */ return_desc = acpi_ut_create_internal_object (INTERNAL_TYPE_REFERENCE); if (!return_desc) { status = AE_NO_MEMORY; goto cleanup; } index = (u32) operand[1]->integer.value; /* * At this point, the Source operand is either a Package or a Buffer */ if (operand[0]->common.type == ACPI_TYPE_PACKAGE) { /* Object to be indexed is a Package */ if (index >= operand[0]->package.count) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Index value beyond package end\n")); status = AE_AML_PACKAGE_LIMIT; goto cleanup; } if ((operand[2]->common.type == INTERNAL_TYPE_REFERENCE) && (operand[2]->reference.opcode == AML_ZERO_OP)) { /* * There is no actual result descriptor (the Zero_op Result * descriptor is a placeholder), so just delete the placeholder and * return a reference to the package element */ acpi_ut_remove_reference (operand[2]); } else { /* * Each element of the package is an internal object. Get the one * we are after. */ temp_desc = operand[0]->package.elements [index]; return_desc->reference.opcode = AML_INDEX_OP; return_desc->reference.target_type = temp_desc->common.type; return_desc->reference.object = temp_desc; status = acpi_ex_store (return_desc, operand[2], walk_state); return_desc->reference.object = NULL; } /* * The local return object must always be a reference to the package element, * not the element itself. */ return_desc->reference.opcode = AML_INDEX_OP; return_desc->reference.target_type = ACPI_TYPE_PACKAGE; return_desc->reference.where = &operand[0]->package.elements [index]; } else { /* Object to be indexed is a Buffer */ if (index >= operand[0]->buffer.length) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Index value beyond end of buffer\n")); status = AE_AML_BUFFER_LIMIT; goto cleanup; } return_desc->reference.opcode = AML_INDEX_OP; return_desc->reference.target_type = ACPI_TYPE_BUFFER_FIELD; return_desc->reference.object = operand[0]; return_desc->reference.offset = index; status = acpi_ex_store (return_desc, operand[2], walk_state); } walk_state->result_obj = return_desc; goto cleanup; break; default: REPORT_ERROR (("Acpi_ex_opcode_2A_1T_1R: Unknown opcode %X\n", walk_state->opcode)); status = AE_AML_BAD_OPCODE; break; } store_result_to_target: if (ACPI_SUCCESS (status)) { /* * Store the result of the operation (which is now in Return_desc) into * the Target descriptor. */ status = acpi_ex_store (return_desc, operand[2], walk_state); if (ACPI_FAILURE (status)) { goto cleanup; } walk_state->result_obj = return_desc; } cleanup: /* Delete return object on error */ if (ACPI_FAILURE (status)) { acpi_ut_remove_reference (return_desc); } return_ACPI_STATUS (status); }