ACPI_STATUS AcpiExOpcode_1A_1T_1R ( ACPI_WALK_STATE *WalkState) { ACPI_STATUS Status = AE_OK; ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; ACPI_OPERAND_OBJECT *ReturnDesc = NULL; ACPI_OPERAND_OBJECT *ReturnDesc2 = NULL; UINT32 Temp32; UINT32 i; UINT64 PowerOfTen; UINT64 Digit; ACPI_FUNCTION_TRACE_STR (ExOpcode_1A_1T_1R, AcpiPsGetOpcodeName (WalkState->Opcode)); /* Examine the AML opcode */ switch (WalkState->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 */ ReturnDesc = AcpiUtCreateInternalObject (ACPI_TYPE_INTEGER); if (!ReturnDesc) { Status = AE_NO_MEMORY; goto Cleanup; } switch (WalkState->Opcode) { case AML_BIT_NOT_OP: /* Not (Operand, Result) */ ReturnDesc->Integer.Value = ~Operand[0]->Integer.Value; break; case AML_FIND_SET_LEFT_BIT_OP: /* FindSetLeftBit (Operand, Result) */ ReturnDesc->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; ReturnDesc->Integer.Value && Temp32 < ACPI_INTEGER_BIT_SIZE; ++Temp32) { ReturnDesc->Integer.Value >>= 1; } ReturnDesc->Integer.Value = Temp32; break; case AML_FIND_SET_RIGHT_BIT_OP: /* FindSetRightBit (Operand, Result) */ ReturnDesc->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; ReturnDesc->Integer.Value && Temp32 < ACPI_INTEGER_BIT_SIZE; ++Temp32) { ReturnDesc->Integer.Value <<= 1; } /* Since the bit position is one-based, subtract from 33 (65) */ ReturnDesc->Integer.Value = Temp32 == 0 ? 0 : (ACPI_INTEGER_BIT_SIZE + 1) - Temp32; break; case AML_FROM_BCD_OP: /* FromBcd (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 */ PowerOfTen = 1; ReturnDesc->Integer.Value = 0; Digit = Operand[0]->Integer.Value; /* Convert each BCD digit (each is one nybble wide) */ for (i = 0; (i < AcpiGbl_IntegerNybbleWidth) && (Digit > 0); i++) { /* Get the least significant 4-bit BCD digit */ Temp32 = ((UINT32) 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 */ ReturnDesc->Integer.Value += (((UINT64) Temp32) * PowerOfTen); /* Shift to next BCD digit */ Digit >>= 4; /* Next power of 10 */ PowerOfTen *= 10; } break; case AML_TO_BCD_OP: /* ToBcd (Operand, Result) */ ReturnDesc->Integer.Value = 0; Digit = Operand[0]->Integer.Value; /* Each BCD digit is one nybble wide */ for (i = 0; (i < AcpiGbl_IntegerNybbleWidth) && (Digit > 0); i++) { (void) AcpiUtShortDivide (Digit, 10, &Digit, &Temp32); /* * Insert the BCD digit that resides in the * remainder from above */ ReturnDesc->Integer.Value |= (((UINT64) 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: 0x%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: /* CondRefOf (SourceObject, 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 ((ACPI_NAMESPACE_NODE *) Operand[0] == AcpiGbl_RootNode) { /* * This means that the object does not exist in the namespace, * return FALSE */ ReturnDesc->Integer.Value = 0; goto Cleanup; } /* Get the object reference, store it, and remove our reference */ Status = AcpiExGetObjectReference (Operand[0], &ReturnDesc2, WalkState); if (ACPI_FAILURE (Status)) { goto Cleanup; } Status = AcpiExStore (ReturnDesc2, Operand[1], WalkState); AcpiUtRemoveReference (ReturnDesc2); /* The object exists in the namespace, return TRUE */ ReturnDesc->Integer.Value = ACPI_UINT64_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 = AcpiExStore (Operand[0], Operand[1], WalkState); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } /* It is possible that the Store already produced a return object */ if (!WalkState->ResultObj) { /* * 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. */ WalkState->ResultObj = Operand[0]; WalkState->Operands[0] = NULL; /* Prevent deletion */ } return_ACPI_STATUS (Status); /* * ACPI 2.0 Opcodes */ case AML_COPY_OP: /* Copy (Source, Target) */ Status = AcpiUtCopyIobjectToIobject (Operand[0], &ReturnDesc, WalkState); break; case AML_TO_DECSTRING_OP: /* ToDecimalString (Data, Result) */ Status = AcpiExConvertToString (Operand[0], &ReturnDesc, ACPI_EXPLICIT_CONVERT_DECIMAL); if (ReturnDesc == Operand[0]) { /* No conversion performed, add ref to handle return value */ AcpiUtAddReference (ReturnDesc); } break; case AML_TO_HEXSTRING_OP: /* ToHexString (Data, Result) */ Status = AcpiExConvertToString (Operand[0], &ReturnDesc, ACPI_EXPLICIT_CONVERT_HEX); if (ReturnDesc == Operand[0]) { /* No conversion performed, add ref to handle return value */ AcpiUtAddReference (ReturnDesc); } break; case AML_TO_BUFFER_OP: /* ToBuffer (Data, Result) */ Status = AcpiExConvertToBuffer (Operand[0], &ReturnDesc); if (ReturnDesc == Operand[0]) { /* No conversion performed, add ref to handle return value */ AcpiUtAddReference (ReturnDesc); } break; case AML_TO_INTEGER_OP: /* ToInteger (Data, Result) */ Status = AcpiExConvertToInteger (Operand[0], &ReturnDesc, ACPI_ANY_BASE); if (ReturnDesc == Operand[0]) { /* No conversion performed, add ref to handle return value */ AcpiUtAddReference (ReturnDesc); } break; case AML_SHIFT_LEFT_BIT_OP: /* ShiftLeftBit (Source, BitNum) */ case AML_SHIFT_RIGHT_BIT_OP: /* ShiftRightBit (Source, BitNum) */ /* These are two obsolete opcodes */ ACPI_ERROR ((AE_INFO, "%s is obsolete and not implemented", AcpiPsGetOpcodeName (WalkState->Opcode))); Status = AE_SUPPORT; goto Cleanup; default: /* Unknown opcode */ ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X", WalkState->Opcode)); Status = AE_AML_BAD_OPCODE; goto Cleanup; } if (ACPI_SUCCESS (Status)) { /* Store the return value computed above into the target object */ Status = AcpiExStore (ReturnDesc, Operand[1], WalkState); } Cleanup: /* Delete return object on error */ if (ACPI_FAILURE (Status)) { AcpiUtRemoveReference (ReturnDesc); } /* Save return object on success */ else if (!WalkState->ResultObj) { WalkState->ResultObj = ReturnDesc; } return_ACPI_STATUS (Status); }
ACPI_STATUS AcpiExConvertToTargetType ( ACPI_OBJECT_TYPE DestinationType, ACPI_OPERAND_OBJECT *SourceDesc, ACPI_OPERAND_OBJECT **ResultDesc, ACPI_WALK_STATE *WalkState) { ACPI_STATUS Status = AE_OK; ACPI_FUNCTION_TRACE (ExConvertToTargetType); /* Default behavior */ *ResultDesc = SourceDesc; /* * If required by the target, * perform implicit conversion on the source before we store it. */ switch (GET_CURRENT_ARG_TYPE (WalkState->OpInfo->RuntimeArgs)) { case ARGI_SIMPLE_TARGET: case ARGI_FIXED_TARGET: case ARGI_INTEGER_REF: /* Handles Increment, Decrement cases */ switch (DestinationType) { case ACPI_TYPE_LOCAL_REGION_FIELD: /* * Named field can always handle conversions */ break; default: /* No conversion allowed for these types */ if (DestinationType != SourceDesc->Common.Type) { ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Explicit operator, will store (%s) over existing type (%s)\n", AcpiUtGetObjectTypeName (SourceDesc), AcpiUtGetTypeName (DestinationType))); Status = AE_TYPE; } } break; case ARGI_TARGETREF: switch (DestinationType) { 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 = AcpiExConvertToInteger (SourceDesc, ResultDesc, 16); break; case ACPI_TYPE_STRING: /* * The operand must be a String. We can convert an * Integer or Buffer if necessary */ Status = AcpiExConvertToString (SourceDesc, ResultDesc, 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 = AcpiExConvertToBuffer (SourceDesc, ResultDesc); break; default: ACPI_ERROR ((AE_INFO, "Bad destination type during conversion: 0x%X", DestinationType)); Status = AE_AML_INTERNAL; break; } break; case ARGI_REFERENCE: /* * CreateXxxxField cases - we are storing the field object into the name */ break; default: ACPI_ERROR ((AE_INFO, "Unknown Target type ID 0x%X AmlOpcode 0x%X DestType %s", GET_CURRENT_ARG_TYPE (WalkState->OpInfo->RuntimeArgs), WalkState->Opcode, AcpiUtGetTypeName (DestinationType))); 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 AcpiExDoLogicalOp ( UINT16 Opcode, ACPI_OPERAND_OBJECT *Operand0, ACPI_OPERAND_OBJECT *Operand1, BOOLEAN *LogicalResult) { ACPI_OPERAND_OBJECT *LocalOperand1 = Operand1; UINT64 Integer0; UINT64 Integer1; UINT32 Length0; UINT32 Length1; ACPI_STATUS Status = AE_OK; BOOLEAN LocalResult = FALSE; int Compare; ACPI_FUNCTION_TRACE (ExDoLogicalOp); /* * 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 (Operand0->Common.Type) { case ACPI_TYPE_INTEGER: Status = AcpiExConvertToInteger (Operand1, &LocalOperand1, ACPI_STRTOUL_BASE16); break; case ACPI_TYPE_STRING: Status = AcpiExConvertToString ( Operand1, &LocalOperand1, ACPI_IMPLICIT_CONVERT_HEX); break; case ACPI_TYPE_BUFFER: Status = AcpiExConvertToBuffer (Operand1, &LocalOperand1); break; default: Status = AE_AML_INTERNAL; break; } if (ACPI_FAILURE (Status)) { goto Cleanup; } /* * Two cases: 1) Both Integers, 2) Both Strings or Buffers */ if (Operand0->Common.Type == ACPI_TYPE_INTEGER) { /* * 1) Both operands are of type integer * Note: LocalOperand1 may have changed above */ Integer0 = Operand0->Integer.Value; Integer1 = LocalOperand1->Integer.Value; switch (Opcode) { case AML_LEQUAL_OP: /* LEqual (Operand0, Operand1) */ if (Integer0 == Integer1) { LocalResult = TRUE; } break; case AML_LGREATER_OP: /* LGreater (Operand0, Operand1) */ if (Integer0 > Integer1) { LocalResult = TRUE; } break; case AML_LLESS_OP: /* LLess (Operand0, Operand1) */ if (Integer0 < Integer1) { LocalResult = 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. LocalOperand1 may have changed above. Use * memcmp to handle nulls in buffers. */ Length0 = Operand0->Buffer.Length; Length1 = LocalOperand1->Buffer.Length; /* Lexicographic compare: compare the data bytes */ Compare = memcmp (Operand0->Buffer.Pointer, LocalOperand1->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 */ LocalResult = TRUE; } break; case AML_LGREATER_OP: /* LGreater (Operand0, Operand1) */ if (Compare > 0) { LocalResult = TRUE; goto Cleanup; /* TRUE */ } if (Compare < 0) { goto Cleanup; /* FALSE */ } /* Bytes match (to shortest length), compare lengths */ if (Length0 > Length1) { LocalResult = TRUE; } break; case AML_LLESS_OP: /* LLess (Operand0, Operand1) */ if (Compare > 0) { goto Cleanup; /* FALSE */ } if (Compare < 0) { LocalResult = TRUE; goto Cleanup; /* TRUE */ } /* Bytes match (to shortest length), compare lengths */ if (Length0 < Length1) { LocalResult = TRUE; } break; default: Status = AE_AML_INTERNAL; break; } } Cleanup: /* New object was created if implicit conversion performed - delete */ if (LocalOperand1 != Operand1) { AcpiUtRemoveReference (LocalOperand1); } /* Return the logical result and status */ *LogicalResult = LocalResult; return_ACPI_STATUS (Status); }
ACPI_STATUS AcpiExDoConcatenate ( ACPI_OPERAND_OBJECT *Operand0, ACPI_OPERAND_OBJECT *Operand1, ACPI_OPERAND_OBJECT **ActualReturnDesc, ACPI_WALK_STATE *WalkState) { ACPI_OPERAND_OBJECT *LocalOperand0 = Operand0; ACPI_OPERAND_OBJECT *LocalOperand1 = Operand1; ACPI_OPERAND_OBJECT *TempOperand1 = NULL; ACPI_OPERAND_OBJECT *ReturnDesc; char *Buffer; ACPI_OBJECT_TYPE Operand0Type; ACPI_OBJECT_TYPE Operand1Type; ACPI_STATUS Status; ACPI_FUNCTION_TRACE (ExDoConcatenate); /* Operand 0 preprocessing */ switch (Operand0->Common.Type) { case ACPI_TYPE_INTEGER: case ACPI_TYPE_STRING: case ACPI_TYPE_BUFFER: Operand0Type = Operand0->Common.Type; break; default: /* For all other types, get the "object type" string */ Status = AcpiExConvertToObjectTypeString ( Operand0, &LocalOperand0); if (ACPI_FAILURE (Status)) { goto Cleanup; } Operand0Type = ACPI_TYPE_STRING; break; } /* Operand 1 preprocessing */ switch (Operand1->Common.Type) { case ACPI_TYPE_INTEGER: case ACPI_TYPE_STRING: case ACPI_TYPE_BUFFER: Operand1Type = Operand1->Common.Type; break; default: /* For all other types, get the "object type" string */ Status = AcpiExConvertToObjectTypeString ( Operand1, &LocalOperand1); if (ACPI_FAILURE (Status)) { goto Cleanup; } Operand1Type = 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 (Operand0Type) { case ACPI_TYPE_INTEGER: Status = AcpiExConvertToInteger (LocalOperand1, &TempOperand1, ACPI_STRTOUL_BASE16); break; case ACPI_TYPE_BUFFER: Status = AcpiExConvertToBuffer (LocalOperand1, &TempOperand1); break; case ACPI_TYPE_STRING: switch (Operand1Type) { case ACPI_TYPE_INTEGER: case ACPI_TYPE_STRING: case ACPI_TYPE_BUFFER: /* Other types have already been converted to string */ Status = AcpiExConvertToString ( LocalOperand1, &TempOperand1, 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 ((LocalOperand1 != Operand1) && (LocalOperand1 != TempOperand1)) { AcpiUtRemoveReference (LocalOperand1); } LocalOperand1 = TempOperand1; /* * 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 (Operand0Type) { case ACPI_TYPE_INTEGER: /* Result of two Integers is a Buffer */ /* Need enough buffer space for two integers */ ReturnDesc = AcpiUtCreateBufferObject ( (ACPI_SIZE) ACPI_MUL_2 (AcpiGbl_IntegerByteWidth)); if (!ReturnDesc) { Status = AE_NO_MEMORY; goto Cleanup; } Buffer = (char *) ReturnDesc->Buffer.Pointer; /* Copy the first integer, LSB first */ memcpy (Buffer, &Operand0->Integer.Value, AcpiGbl_IntegerByteWidth); /* Copy the second integer (LSB first) after the first */ memcpy (Buffer + AcpiGbl_IntegerByteWidth, &LocalOperand1->Integer.Value, AcpiGbl_IntegerByteWidth); break; case ACPI_TYPE_STRING: /* Result of two Strings is a String */ ReturnDesc = AcpiUtCreateStringObject ( ((ACPI_SIZE) LocalOperand0->String.Length + LocalOperand1->String.Length)); if (!ReturnDesc) { Status = AE_NO_MEMORY; goto Cleanup; } Buffer = ReturnDesc->String.Pointer; /* Concatenate the strings */ strcpy (Buffer, LocalOperand0->String.Pointer); strcat (Buffer, LocalOperand1->String.Pointer); break; case ACPI_TYPE_BUFFER: /* Result of two Buffers is a Buffer */ ReturnDesc = AcpiUtCreateBufferObject ( ((ACPI_SIZE) Operand0->Buffer.Length + LocalOperand1->Buffer.Length)); if (!ReturnDesc) { Status = AE_NO_MEMORY; goto Cleanup; } Buffer = (char *) ReturnDesc->Buffer.Pointer; /* Concatenate the buffers */ memcpy (Buffer, Operand0->Buffer.Pointer, Operand0->Buffer.Length); memcpy (Buffer + Operand0->Buffer.Length, LocalOperand1->Buffer.Pointer, LocalOperand1->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; } *ActualReturnDesc = ReturnDesc; Cleanup: if (LocalOperand0 != Operand0) { AcpiUtRemoveReference (LocalOperand0); } if (LocalOperand1 != Operand1) { AcpiUtRemoveReference (LocalOperand1); } return_ACPI_STATUS (Status); }
ACPI_STATUS AcpiNsConvertToString ( ACPI_OPERAND_OBJECT *OriginalObject, ACPI_OPERAND_OBJECT **ReturnObject) { ACPI_OPERAND_OBJECT *NewObject; ACPI_SIZE Length; ACPI_STATUS Status; switch (OriginalObject->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 (OriginalObject->Integer.Value == 0) { /* Allocate a new NULL string object */ NewObject = AcpiUtCreateStringObject (0); if (!NewObject) { return (AE_NO_MEMORY); } } else { Status = AcpiExConvertToString (OriginalObject, &NewObject, ACPI_IMPLICIT_CONVERT_HEX); if (ACPI_FAILURE (Status)) { return (Status); } } break; case ACPI_TYPE_BUFFER: /* * Buffer-to-String conversion. Use a ToString * 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 < OriginalObject->Buffer.Length) && (OriginalObject->Buffer.Pointer[Length])) { Length++; } /* Allocate a new string object */ NewObject = AcpiUtCreateStringObject (Length); if (!NewObject) { return (AE_NO_MEMORY); } /* * Copy the raw buffer data with no transform. String is already NULL * terminated at Length+1. */ memcpy (NewObject->String.Pointer, OriginalObject->Buffer.Pointer, Length); break; default: return (AE_AML_OPERAND_TYPE); } *ReturnObject = NewObject; return (AE_OK); }
ACPI_STATUS AcpiExDoConcatenate ( ACPI_OPERAND_OBJECT *Operand0, ACPI_OPERAND_OBJECT *Operand1, ACPI_OPERAND_OBJECT **ActualReturnDesc, ACPI_WALK_STATE *WalkState) { ACPI_OPERAND_OBJECT *LocalOperand1 = Operand1; ACPI_OPERAND_OBJECT *ReturnDesc; char *NewBuf; ACPI_STATUS Status; ACPI_FUNCTION_TRACE (ExDoConcatenate); /* * 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 = AcpiExConvertToInteger (Operand1, &LocalOperand1, 16); break; case ACPI_TYPE_STRING: Status = AcpiExConvertToString (Operand1, &LocalOperand1, ACPI_IMPLICIT_CONVERT_HEX); break; case ACPI_TYPE_BUFFER: Status = AcpiExConvertToBuffer (Operand1, &LocalOperand1); break; default: ACPI_ERROR ((AE_INFO, "Invalid object type: %X", 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 */ ReturnDesc = AcpiUtCreateBufferObject ((ACPI_SIZE) ACPI_MUL_2 (AcpiGbl_IntegerByteWidth)); if (!ReturnDesc) { Status = AE_NO_MEMORY; goto Cleanup; } NewBuf = (char *) ReturnDesc->Buffer.Pointer; /* Copy the first integer, LSB first */ ACPI_MEMCPY (NewBuf, &Operand0->Integer.Value, AcpiGbl_IntegerByteWidth); /* Copy the second integer (LSB first) after the first */ ACPI_MEMCPY (NewBuf + AcpiGbl_IntegerByteWidth, &LocalOperand1->Integer.Value, AcpiGbl_IntegerByteWidth); break; case ACPI_TYPE_STRING: /* Result of two Strings is a String */ ReturnDesc = AcpiUtCreateStringObject ((ACPI_SIZE) (Operand0->String.Length + LocalOperand1->String.Length)); if (!ReturnDesc) { Status = AE_NO_MEMORY; goto Cleanup; } NewBuf = ReturnDesc->String.Pointer; /* Concatenate the strings */ ACPI_STRCPY (NewBuf, Operand0->String.Pointer); ACPI_STRCPY (NewBuf + Operand0->String.Length, LocalOperand1->String.Pointer); break; case ACPI_TYPE_BUFFER: /* Result of two Buffers is a Buffer */ ReturnDesc = AcpiUtCreateBufferObject ((ACPI_SIZE) (Operand0->Buffer.Length + LocalOperand1->Buffer.Length)); if (!ReturnDesc) { Status = AE_NO_MEMORY; goto Cleanup; } NewBuf = (char *) ReturnDesc->Buffer.Pointer; /* Concatenate the buffers */ ACPI_MEMCPY (NewBuf, Operand0->Buffer.Pointer, Operand0->Buffer.Length); ACPI_MEMCPY (NewBuf + Operand0->Buffer.Length, LocalOperand1->Buffer.Pointer, LocalOperand1->Buffer.Length); break; default: /* Invalid object type, should not happen here */ ACPI_ERROR ((AE_INFO, "Invalid object type: %X", ACPI_GET_OBJECT_TYPE (Operand0))); Status =AE_AML_INTERNAL; goto Cleanup; } *ActualReturnDesc = ReturnDesc; Cleanup: if (LocalOperand1 != Operand1) { AcpiUtRemoveReference (LocalOperand1); } return_ACPI_STATUS (Status); }
ACPI_STATUS AcpiExResolveOperands ( UINT16 Opcode, ACPI_OPERAND_OBJECT **StackPtr, ACPI_WALK_STATE *WalkState) { ACPI_OPERAND_OBJECT *ObjDesc; ACPI_STATUS Status = AE_OK; UINT8 ObjectType; UINT32 ArgTypes; const ACPI_OPCODE_INFO *OpInfo; UINT32 ThisArgType; ACPI_OBJECT_TYPE TypeNeeded; UINT16 TargetOp = 0; ACPI_FUNCTION_TRACE_U32 (ExResolveOperands, Opcode); OpInfo = AcpiPsGetOpcodeInfo (Opcode); if (OpInfo->Class == AML_CLASS_UNKNOWN) { return_ACPI_STATUS (AE_AML_BAD_OPCODE); } ArgTypes = OpInfo->RuntimeArgs; if (ArgTypes == ARGI_INVALID_OPCODE) { ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X", Opcode)); return_ACPI_STATUS (AE_AML_INTERNAL); } ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Opcode %X [%s] RequiredOperandTypes=%8.8X\n", Opcode, OpInfo->Name, ArgTypes)); /* * Normal exit is with (ArgTypes == 0) at end of argument list. * Function will return an exception from within the loop upon * finding an entry which is not (or cannot be converted * to) the required type; if stack underflows; or upon * finding a NULL stack entry (which should not happen). */ while (GET_CURRENT_ARG_TYPE (ArgTypes)) { if (!StackPtr || !*StackPtr) { ACPI_ERROR ((AE_INFO, "Null stack entry at %p", StackPtr)); return_ACPI_STATUS (AE_AML_INTERNAL); } /* Extract useful items */ ObjDesc = *StackPtr; /* Decode the descriptor type */ switch (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc)) { case ACPI_DESC_TYPE_NAMED: /* Namespace Node */ ObjectType = ((ACPI_NAMESPACE_NODE *) ObjDesc)->Type; /* * Resolve an alias object. The construction of these objects * guarantees that there is only one level of alias indirection; * thus, the attached object is always the aliased namespace node */ if (ObjectType == ACPI_TYPE_LOCAL_ALIAS) { ObjDesc = AcpiNsGetAttachedObject ((ACPI_NAMESPACE_NODE *) ObjDesc); *StackPtr = ObjDesc; ObjectType = ((ACPI_NAMESPACE_NODE *) ObjDesc)->Type; } break; case ACPI_DESC_TYPE_OPERAND: /* ACPI internal object */ ObjectType = ObjDesc->Common.Type; /* Check for bad ACPI_OBJECT_TYPE */ if (!AcpiUtValidObjectType (ObjectType)) { ACPI_ERROR ((AE_INFO, "Bad operand object type [0x%X]", ObjectType)); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } if (ObjectType == (UINT8) ACPI_TYPE_LOCAL_REFERENCE) { /* Validate the Reference */ switch (ObjDesc->Reference.Class) { case ACPI_REFCLASS_DEBUG: TargetOp = AML_DEBUG_OP; /*lint -fallthrough */ case ACPI_REFCLASS_ARG: case ACPI_REFCLASS_LOCAL: case ACPI_REFCLASS_INDEX: case ACPI_REFCLASS_REFOF: case ACPI_REFCLASS_TABLE: /* DdbHandle from LOAD_OP or LOAD_TABLE_OP */ case ACPI_REFCLASS_NAME: /* Reference to a named object */ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Operand is a Reference, Class [%s] %2.2X\n", AcpiUtGetReferenceName (ObjDesc), ObjDesc->Reference.Class)); break; default: ACPI_ERROR ((AE_INFO, "Unknown Reference Class 0x%2.2X in %p", ObjDesc->Reference.Class, ObjDesc)); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } } break; default: /* Invalid descriptor */ ACPI_ERROR ((AE_INFO, "Invalid descriptor %p [%s]", ObjDesc, AcpiUtGetDescriptorName (ObjDesc))); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } /* Get one argument type, point to the next */ ThisArgType = GET_CURRENT_ARG_TYPE (ArgTypes); INCREMENT_ARG_LIST (ArgTypes); /* * Handle cases where the object does not need to be * resolved to a value */ switch (ThisArgType) { case ARGI_REF_OR_STRING: /* Can be a String or Reference */ if ((ACPI_GET_DESCRIPTOR_TYPE (ObjDesc) == ACPI_DESC_TYPE_OPERAND) && (ObjDesc->Common.Type == ACPI_TYPE_STRING)) { /* * String found - the string references a named object and * must be resolved to a node */ goto NextOperand; } /* * Else not a string - fall through to the normal Reference * case below */ /*lint -fallthrough */ case ARGI_REFERENCE: /* References: */ case ARGI_INTEGER_REF: case ARGI_OBJECT_REF: case ARGI_DEVICE_REF: case ARGI_TARGETREF: /* Allows implicit conversion rules before store */ case ARGI_FIXED_TARGET: /* No implicit conversion before store to target */ case ARGI_SIMPLE_TARGET: /* Name, Local, or Arg - no implicit conversion */ /* * Need an operand of type ACPI_TYPE_LOCAL_REFERENCE * A Namespace Node is OK as-is */ if (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc) == ACPI_DESC_TYPE_NAMED) { goto NextOperand; } Status = AcpiExCheckObjectType (ACPI_TYPE_LOCAL_REFERENCE, ObjectType, ObjDesc); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } goto NextOperand; case ARGI_DATAREFOBJ: /* Store operator only */ /* * We don't want to resolve IndexOp reference objects during * a store because this would be an implicit DeRefOf operation. * Instead, we just want to store the reference object. * -- All others must be resolved below. */ if ((Opcode == AML_STORE_OP) && ((*StackPtr)->Common.Type == ACPI_TYPE_LOCAL_REFERENCE) && ((*StackPtr)->Reference.Class == ACPI_REFCLASS_INDEX)) { goto NextOperand; } break; default: /* All cases covered above */ break; } /* * Resolve this object to a value */ Status = AcpiExResolveToValue (StackPtr, WalkState); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } /* Get the resolved object */ ObjDesc = *StackPtr; /* * Check the resulting object (value) type */ switch (ThisArgType) { /* * For the simple cases, only one type of resolved object * is allowed */ case ARGI_MUTEX: /* Need an operand of type ACPI_TYPE_MUTEX */ TypeNeeded = ACPI_TYPE_MUTEX; break; case ARGI_EVENT: /* Need an operand of type ACPI_TYPE_EVENT */ TypeNeeded = ACPI_TYPE_EVENT; break; case ARGI_PACKAGE: /* Package */ /* Need an operand of type ACPI_TYPE_PACKAGE */ TypeNeeded = ACPI_TYPE_PACKAGE; break; case ARGI_ANYTYPE: /* Any operand type will do */ TypeNeeded = ACPI_TYPE_ANY; break; case ARGI_DDBHANDLE: /* Need an operand of type ACPI_TYPE_DDB_HANDLE */ TypeNeeded = ACPI_TYPE_LOCAL_REFERENCE; break; /* * The more complex cases allow multiple resolved object types */ case ARGI_INTEGER: /* * Need an operand of type ACPI_TYPE_INTEGER, * But we can implicitly convert from a STRING or BUFFER * Aka - "Implicit Source Operand Conversion" */ Status = AcpiExConvertToInteger (ObjDesc, StackPtr, 16); if (ACPI_FAILURE (Status)) { if (Status == AE_TYPE) { ACPI_ERROR ((AE_INFO, "Needed [Integer/String/Buffer], found [%s] %p", AcpiUtGetObjectTypeName (ObjDesc), ObjDesc)); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } return_ACPI_STATUS (Status); } if (ObjDesc != *StackPtr) { AcpiUtRemoveReference (ObjDesc); } goto NextOperand; case ARGI_BUFFER: /* * Need an operand of type ACPI_TYPE_BUFFER, * But we can implicitly convert from a STRING or INTEGER * Aka - "Implicit Source Operand Conversion" */ Status = AcpiExConvertToBuffer (ObjDesc, StackPtr); if (ACPI_FAILURE (Status)) { if (Status == AE_TYPE) { ACPI_ERROR ((AE_INFO, "Needed [Integer/String/Buffer], found [%s] %p", AcpiUtGetObjectTypeName (ObjDesc), ObjDesc)); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } return_ACPI_STATUS (Status); } if (ObjDesc != *StackPtr) { AcpiUtRemoveReference (ObjDesc); } goto NextOperand; case ARGI_STRING: /* * Need an operand of type ACPI_TYPE_STRING, * But we can implicitly convert from a BUFFER or INTEGER * Aka - "Implicit Source Operand Conversion" */ Status = AcpiExConvertToString (ObjDesc, StackPtr, ACPI_IMPLICIT_CONVERT_HEX); if (ACPI_FAILURE (Status)) { if (Status == AE_TYPE) { ACPI_ERROR ((AE_INFO, "Needed [Integer/String/Buffer], found [%s] %p", AcpiUtGetObjectTypeName (ObjDesc), ObjDesc)); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } return_ACPI_STATUS (Status); } if (ObjDesc != *StackPtr) { AcpiUtRemoveReference (ObjDesc); } goto NextOperand; case ARGI_COMPUTEDATA: /* Need an operand of type INTEGER, STRING or BUFFER */ switch (ObjDesc->Common.Type) { case ACPI_TYPE_INTEGER: case ACPI_TYPE_STRING: case ACPI_TYPE_BUFFER: /* Valid operand */ break; default: ACPI_ERROR ((AE_INFO, "Needed [Integer/String/Buffer], found [%s] %p", AcpiUtGetObjectTypeName (ObjDesc), ObjDesc)); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } goto NextOperand; case ARGI_BUFFER_OR_STRING: /* Need an operand of type STRING or BUFFER */ switch (ObjDesc->Common.Type) { case ACPI_TYPE_STRING: case ACPI_TYPE_BUFFER: /* Valid operand */ break; case ACPI_TYPE_INTEGER: /* Highest priority conversion is to type Buffer */ Status = AcpiExConvertToBuffer (ObjDesc, StackPtr); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } if (ObjDesc != *StackPtr) { AcpiUtRemoveReference (ObjDesc); } break; default: ACPI_ERROR ((AE_INFO, "Needed [Integer/String/Buffer], found [%s] %p", AcpiUtGetObjectTypeName (ObjDesc), ObjDesc)); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } goto NextOperand; case ARGI_DATAOBJECT: /* * ARGI_DATAOBJECT is only used by the SizeOf operator. * Need a buffer, string, package, or RefOf reference. * * The only reference allowed here is a direct reference to * a namespace node. */ switch (ObjDesc->Common.Type) { case ACPI_TYPE_PACKAGE: case ACPI_TYPE_STRING: case ACPI_TYPE_BUFFER: case ACPI_TYPE_LOCAL_REFERENCE: /* Valid operand */ break; default: ACPI_ERROR ((AE_INFO, "Needed [Buffer/String/Package/Reference], found [%s] %p", AcpiUtGetObjectTypeName (ObjDesc), ObjDesc)); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } goto NextOperand; case ARGI_COMPLEXOBJ: /* Need a buffer or package or (ACPI 2.0) String */ switch (ObjDesc->Common.Type) { case ACPI_TYPE_PACKAGE: case ACPI_TYPE_STRING: case ACPI_TYPE_BUFFER: /* Valid operand */ break; default: ACPI_ERROR ((AE_INFO, "Needed [Buffer/String/Package], found [%s] %p", AcpiUtGetObjectTypeName (ObjDesc), ObjDesc)); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } goto NextOperand; case ARGI_REGION_OR_BUFFER: /* Used by Load() only */ /* Need an operand of type REGION or a BUFFER (which could be a resolved region field) */ switch (ObjDesc->Common.Type) { case ACPI_TYPE_BUFFER: case ACPI_TYPE_REGION: /* Valid operand */ break; default: ACPI_ERROR ((AE_INFO, "Needed [Region/Buffer], found [%s] %p", AcpiUtGetObjectTypeName (ObjDesc), ObjDesc)); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } goto NextOperand; case ARGI_DATAREFOBJ: /* Used by the Store() operator only */ switch (ObjDesc->Common.Type) { case ACPI_TYPE_INTEGER: case ACPI_TYPE_PACKAGE: case ACPI_TYPE_STRING: case ACPI_TYPE_BUFFER: case ACPI_TYPE_BUFFER_FIELD: case ACPI_TYPE_LOCAL_REFERENCE: case ACPI_TYPE_LOCAL_REGION_FIELD: case ACPI_TYPE_LOCAL_BANK_FIELD: case ACPI_TYPE_LOCAL_INDEX_FIELD: case ACPI_TYPE_DDB_HANDLE: /* Valid operand */ break; default: if (AcpiGbl_EnableInterpreterSlack) { /* * Enable original behavior of Store(), allowing any and all * objects as the source operand. The ACPI spec does not * allow this, however. */ break; } if (TargetOp == AML_DEBUG_OP) { /* Allow store of any object to the Debug object */ break; } ACPI_ERROR ((AE_INFO, "Needed Integer/Buffer/String/Package/Ref/Ddb], found [%s] %p", AcpiUtGetObjectTypeName (ObjDesc), ObjDesc)); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } goto NextOperand; default: /* Unknown type */ ACPI_ERROR ((AE_INFO, "Internal - Unknown ARGI (required operand) type 0x%X", ThisArgType)); return_ACPI_STATUS (AE_BAD_PARAMETER); } /* * Make sure that the original object was resolved to the * required object type (Simple cases only). */ Status = AcpiExCheckObjectType (TypeNeeded, (*StackPtr)->Common.Type, *StackPtr); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } NextOperand: /* * If more operands needed, decrement StackPtr to point * to next operand on stack */ if (GET_CURRENT_ARG_TYPE (ArgTypes)) { StackPtr--; } } ACPI_DUMP_OPERANDS (WalkState->Operands, AcpiPsGetOpcodeName (Opcode), WalkState->NumOperands); return_ACPI_STATUS (Status); }