static void AeDoOneOverride ( char *Pathname, char *ValueString, ACPI_OPERAND_OBJECT *ObjDesc, ACPI_WALK_STATE *WalkState) { ACPI_HANDLE Handle; ACPI_STATUS Status; UINT64 Value; AcpiOsPrintf ("Value Override: %s, ", Pathname); /* * Get the namespace node associated with the override * pathname from the init file. */ Status = AcpiGetHandle (NULL, Pathname, &Handle); if (ACPI_FAILURE (Status)) { AcpiOsPrintf ("%s\n", AcpiFormatException (Status)); return; } /* Extract the 64-bit integer */ Status = AcpiUtStrtoul64 (ValueString, (ACPI_STRTOUL_BASE16 | ACPI_STRTOUL_64BIT), &Value); if (ACPI_FAILURE (Status)) { AcpiOsPrintf ("%s %s\n", ValueString, AcpiFormatException (Status)); return; } ObjDesc->Integer.Value = Value; /* * At the point this function is called, the namespace is fully * built and initialized. We can simply store the new object to * the target node. */ AcpiExEnterInterpreter (); Status = AcpiExStore (ObjDesc, Handle, WalkState); AcpiExExitInterpreter (); if (ACPI_FAILURE (Status)) { AcpiOsPrintf ("%s\n", AcpiFormatException (Status)); return; } AcpiOsPrintf ("New value: 0x%8.8X%8.8X\n", ACPI_FORMAT_UINT64 (Value)); }
ACPI_STATUS AcpiExOpcode_1A_0T_1R ( ACPI_WALK_STATE *WalkState) { ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; ACPI_OPERAND_OBJECT *TempDesc; ACPI_OPERAND_OBJECT *ReturnDesc = NULL; ACPI_STATUS Status = AE_OK; UINT32 Type; UINT64 Value; ACPI_FUNCTION_TRACE_STR (ExOpcode_1A_0T_1R, AcpiPsGetOpcodeName (WalkState->Opcode)); /* Examine the AML opcode */ switch (WalkState->Opcode) { case AML_LNOT_OP: /* LNot (Operand) */ ReturnDesc = AcpiUtCreateIntegerObject ((UINT64) 0); if (!ReturnDesc) { Status = AE_NO_MEMORY; goto Cleanup; } /* * Set result to ONES (TRUE) if Value == 0. Note: * ReturnDesc->Integer.Value is initially == 0 (FALSE) from above. */ if (!Operand[0]->Integer.Value) { ReturnDesc->Integer.Value = ACPI_UINT64_MAX; } break; case AML_DECREMENT_OP: /* Decrement (Operand) */ case AML_INCREMENT_OP: /* Increment (Operand) */ /* * Create a new integer. Can't just get the base integer and * increment it because it may be an Arg or Field. */ ReturnDesc = AcpiUtCreateInternalObject (ACPI_TYPE_INTEGER); if (!ReturnDesc) { Status = AE_NO_MEMORY; goto Cleanup; } /* * Since we are expecting a Reference operand, it can be either a * NS Node or an internal object. */ TempDesc = Operand[0]; if (ACPI_GET_DESCRIPTOR_TYPE (TempDesc) == ACPI_DESC_TYPE_OPERAND) { /* Internal reference object - prevent deletion */ AcpiUtAddReference (TempDesc); } /* * Convert the Reference operand to an Integer (This removes a * reference on the Operand[0] object) * * NOTE: We use LNOT_OP here in order to force resolution of the * reference operand to an actual integer. */ Status = AcpiExResolveOperands (AML_LNOT_OP, &TempDesc, WalkState); if (ACPI_FAILURE (Status)) { ACPI_EXCEPTION ((AE_INFO, Status, "While resolving operands for [%s]", AcpiPsGetOpcodeName (WalkState->Opcode))); goto Cleanup; } /* * TempDesc is now guaranteed to be an Integer object -- * Perform the actual increment or decrement */ if (WalkState->Opcode == AML_INCREMENT_OP) { ReturnDesc->Integer.Value = TempDesc->Integer.Value + 1; } else { ReturnDesc->Integer.Value = TempDesc->Integer.Value - 1; } /* Finished with this Integer object */ AcpiUtRemoveReference (TempDesc); /* * Store the result back (indirectly) through the original * Reference object */ Status = AcpiExStore (ReturnDesc, Operand[0], WalkState); break; case AML_OBJECT_TYPE_OP: /* ObjectType (SourceObject) */ /* * Note: The operand is not resolved at this point because we want to * get the associated object, not its value. For example, we don't * want to resolve a FieldUnit to its value, we want the actual * FieldUnit object. */ /* Get the type of the base object */ Status = AcpiExResolveMultiple (WalkState, Operand[0], &Type, NULL); if (ACPI_FAILURE (Status)) { goto Cleanup; } /* Allocate a descriptor to hold the type. */ ReturnDesc = AcpiUtCreateIntegerObject ((UINT64) Type); if (!ReturnDesc) { Status = AE_NO_MEMORY; goto Cleanup; } break; case AML_SIZE_OF_OP: /* SizeOf (SourceObject) */ /* * Note: The operand is not resolved at this point because we want to * get the associated object, not its value. */ /* Get the base object */ Status = AcpiExResolveMultiple ( WalkState, Operand[0], &Type, &TempDesc); if (ACPI_FAILURE (Status)) { goto Cleanup; } /* * The type of the base object must be integer, buffer, string, or * package. All others are not supported. * * NOTE: Integer is not specifically supported by the ACPI spec, * but is supported implicitly via implicit operand conversion. * rather than bother with conversion, we just use the byte width * global (4 or 8 bytes). */ switch (Type) { case ACPI_TYPE_INTEGER: Value = AcpiGbl_IntegerByteWidth; break; case ACPI_TYPE_STRING: Value = TempDesc->String.Length; break; case ACPI_TYPE_BUFFER: /* Buffer arguments may not be evaluated at this point */ Status = AcpiDsGetBufferArguments (TempDesc); Value = TempDesc->Buffer.Length; break; case ACPI_TYPE_PACKAGE: /* Package arguments may not be evaluated at this point */ Status = AcpiDsGetPackageArguments (TempDesc); Value = TempDesc->Package.Count; break; default: ACPI_ERROR ((AE_INFO, "Operand must be Buffer/Integer/String/Package" " - found type %s", AcpiUtGetTypeName (Type))); Status = AE_AML_OPERAND_TYPE; goto Cleanup; } if (ACPI_FAILURE (Status)) { goto Cleanup; } /* * Now that we have the size of the object, create a result * object to hold the value */ ReturnDesc = AcpiUtCreateIntegerObject (Value); if (!ReturnDesc) { Status = AE_NO_MEMORY; goto Cleanup; } break; case AML_REF_OF_OP: /* RefOf (SourceObject) */ Status = AcpiExGetObjectReference ( Operand[0], &ReturnDesc, WalkState); if (ACPI_FAILURE (Status)) { goto Cleanup; } break; case AML_DEREF_OF_OP: /* DerefOf (ObjReference | String) */ /* Check for a method local or argument, or standalone String */ if (ACPI_GET_DESCRIPTOR_TYPE (Operand[0]) == ACPI_DESC_TYPE_NAMED) { TempDesc = AcpiNsGetAttachedObject ( (ACPI_NAMESPACE_NODE *) Operand[0]); if (TempDesc && ((TempDesc->Common.Type == ACPI_TYPE_STRING) || (TempDesc->Common.Type == ACPI_TYPE_LOCAL_REFERENCE))) { Operand[0] = TempDesc; AcpiUtAddReference (TempDesc); } else { Status = AE_AML_OPERAND_TYPE; goto Cleanup; } } else { switch ((Operand[0])->Common.Type) { case ACPI_TYPE_LOCAL_REFERENCE: /* * This is a DerefOf (LocalX | ArgX) * * Must resolve/dereference the local/arg reference first */ switch (Operand[0]->Reference.Class) { case ACPI_REFCLASS_LOCAL: case ACPI_REFCLASS_ARG: /* Set Operand[0] to the value of the local/arg */ Status = AcpiDsMethodDataGetValue ( Operand[0]->Reference.Class, Operand[0]->Reference.Value, WalkState, &TempDesc); if (ACPI_FAILURE (Status)) { goto Cleanup; } /* * Delete our reference to the input object and * point to the object just retrieved */ AcpiUtRemoveReference (Operand[0]); Operand[0] = TempDesc; break; case ACPI_REFCLASS_REFOF: /* Get the object to which the reference refers */ TempDesc = Operand[0]->Reference.Object; AcpiUtRemoveReference (Operand[0]); Operand[0] = TempDesc; break; default: /* Must be an Index op - handled below */ break; } break; case ACPI_TYPE_STRING: break; default: Status = AE_AML_OPERAND_TYPE; goto Cleanup; } } if (ACPI_GET_DESCRIPTOR_TYPE (Operand[0]) != ACPI_DESC_TYPE_NAMED) { if ((Operand[0])->Common.Type == ACPI_TYPE_STRING) { /* * This is a DerefOf (String). The string is a reference * to a named ACPI object. * * 1) Find the owning Node * 2) Dereference the node to an actual object. Could be a * Field, so we need to resolve the node to a value. */ Status = AcpiNsGetNodeUnlocked (WalkState->ScopeInfo->Scope.Node, Operand[0]->String.Pointer, ACPI_NS_SEARCH_PARENT, ACPI_CAST_INDIRECT_PTR ( ACPI_NAMESPACE_NODE, &ReturnDesc)); if (ACPI_FAILURE (Status)) { goto Cleanup; } Status = AcpiExResolveNodeToValue ( ACPI_CAST_INDIRECT_PTR ( ACPI_NAMESPACE_NODE, &ReturnDesc), WalkState); goto Cleanup; } } /* Operand[0] may have changed from the code above */ if (ACPI_GET_DESCRIPTOR_TYPE (Operand[0]) == ACPI_DESC_TYPE_NAMED) { /* * This is a DerefOf (ObjectReference) * Get the actual object from the Node (This is the dereference). * This case may only happen when a LocalX or ArgX is * dereferenced above. */ ReturnDesc = AcpiNsGetAttachedObject ( (ACPI_NAMESPACE_NODE *) Operand[0]); AcpiUtAddReference (ReturnDesc); } else { /* * This must be a reference object produced by either the * Index() or RefOf() operator */ switch (Operand[0]->Reference.Class) { case ACPI_REFCLASS_INDEX: /* * The target type for the Index operator must be * either a Buffer or a Package */ switch (Operand[0]->Reference.TargetType) { case ACPI_TYPE_BUFFER_FIELD: TempDesc = Operand[0]->Reference.Object; /* * Create a new object that contains one element of the * buffer -- the element pointed to by the index. * * NOTE: index into a buffer is NOT a pointer to a * sub-buffer of the main buffer, it is only a pointer to a * single element (byte) of the buffer! * * Since we are returning the value of the buffer at the * indexed location, we don't need to add an additional * reference to the buffer itself. */ ReturnDesc = AcpiUtCreateIntegerObject ((UINT64) TempDesc->Buffer.Pointer[Operand[0]->Reference.Value]); if (!ReturnDesc) { Status = AE_NO_MEMORY; goto Cleanup; } break; case ACPI_TYPE_PACKAGE: /* * Return the referenced element of the package. We must * add another reference to the referenced object, however. */ ReturnDesc = *(Operand[0]->Reference.Where); if (!ReturnDesc) { /* * Element is NULL, do not allow the dereference. * This provides compatibility with other ACPI * implementations. */ return_ACPI_STATUS (AE_AML_UNINITIALIZED_ELEMENT); } AcpiUtAddReference (ReturnDesc); break; default: ACPI_ERROR ((AE_INFO, "Unknown Index TargetType 0x%X in reference object %p", Operand[0]->Reference.TargetType, Operand[0])); Status = AE_AML_OPERAND_TYPE; goto Cleanup; } break; case ACPI_REFCLASS_REFOF: ReturnDesc = Operand[0]->Reference.Object; if (ACPI_GET_DESCRIPTOR_TYPE (ReturnDesc) == ACPI_DESC_TYPE_NAMED) { ReturnDesc = AcpiNsGetAttachedObject ( (ACPI_NAMESPACE_NODE *) ReturnDesc); if (!ReturnDesc) { break; } /* * June 2013: * BufferFields/FieldUnits require additional resolution */ switch (ReturnDesc->Common.Type) { case ACPI_TYPE_BUFFER_FIELD: case ACPI_TYPE_LOCAL_REGION_FIELD: case ACPI_TYPE_LOCAL_BANK_FIELD: case ACPI_TYPE_LOCAL_INDEX_FIELD: Status = AcpiExReadDataFromField ( WalkState, ReturnDesc, &TempDesc); if (ACPI_FAILURE (Status)) { goto Cleanup; } ReturnDesc = TempDesc; break; default: /* Add another reference to the object */ AcpiUtAddReference (ReturnDesc); break; } } break; default: ACPI_ERROR ((AE_INFO, "Unknown class in reference(%p) - 0x%2.2X", Operand[0], Operand[0]->Reference.Class)); Status = AE_TYPE; goto Cleanup; } } break; default: ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X", WalkState->Opcode)); Status = AE_AML_BAD_OPCODE; goto Cleanup; } Cleanup: /* Delete return object on error */ if (ACPI_FAILURE (Status)) { AcpiUtRemoveReference (ReturnDesc); } /* Save return object on success */ else { WalkState->ResultObj = ReturnDesc; } return_ACPI_STATUS (Status); }
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) */ /* Perform "explicit" conversion */ Status = AcpiExConvertToInteger (Operand[0], &ReturnDesc, 0); 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 AcpiExOpcode_3A_1T_1R ( ACPI_WALK_STATE *WalkState) { ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; ACPI_OPERAND_OBJECT *ReturnDesc = NULL; char *Buffer = NULL; ACPI_STATUS Status = AE_OK; UINT64 Index; ACPI_SIZE Length; ACPI_FUNCTION_TRACE_STR (ExOpcode_3A_1T_1R, AcpiPsGetOpcodeName (WalkState->Opcode)); switch (WalkState->Opcode) { case AML_MID_OP: /* Mid (Source[0], Index[1], Length[2], Result[3]) */ /* * Create the return object. The Source operand is guaranteed to be * either a String or a Buffer, so just use its type. */ ReturnDesc = AcpiUtCreateInternalObject ( (Operand[0])->Common.Type); if (!ReturnDesc) { Status = AE_NO_MEMORY; goto Cleanup; } /* Get the Integer values from the objects */ Index = Operand[1]->Integer.Value; Length = (ACPI_SIZE) Operand[2]->Integer.Value; /* * If the index is beyond the length of the String/Buffer, or if the * requested length is zero, return a zero-length String/Buffer */ if (Index >= Operand[0]->String.Length) { Length = 0; } /* Truncate request if larger than the actual String/Buffer */ else if ((Index + Length) > Operand[0]->String.Length) { Length = (ACPI_SIZE) Operand[0]->String.Length - (ACPI_SIZE) Index; } /* Strings always have a sub-pointer, not so for buffers */ switch ((Operand[0])->Common.Type) { case ACPI_TYPE_STRING: /* Always allocate a new buffer for the String */ Buffer = ACPI_ALLOCATE_ZEROED ((ACPI_SIZE) Length + 1); if (!Buffer) { Status = AE_NO_MEMORY; goto Cleanup; } break; case ACPI_TYPE_BUFFER: /* If the requested length is zero, don't allocate a buffer */ if (Length > 0) { /* Allocate a new buffer for the Buffer */ Buffer = ACPI_ALLOCATE_ZEROED (Length); if (!Buffer) { Status = AE_NO_MEMORY; goto Cleanup; } } break; default: /* Should not happen */ Status = AE_AML_OPERAND_TYPE; goto Cleanup; } if (Buffer) { /* We have a buffer, copy the portion requested */ ACPI_MEMCPY (Buffer, Operand[0]->String.Pointer + Index, Length); } /* Set the length of the new String/Buffer */ ReturnDesc->String.Pointer = Buffer; ReturnDesc->String.Length = (UINT32) Length; /* Mark buffer initialized */ ReturnDesc->Buffer.Flags |= AOPOBJ_DATA_VALID; break; default: ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X", WalkState->Opcode)); Status = AE_AML_BAD_OPCODE; goto Cleanup; } /* Store the result in the target */ Status = AcpiExStore (ReturnDesc, Operand[3], WalkState); Cleanup: /* Delete return object on error */ if (ACPI_FAILURE (Status) || WalkState->ResultObj) { AcpiUtRemoveReference (ReturnDesc); WalkState->ResultObj = NULL; } /* Set the return object and exit */ else { WalkState->ResultObj = ReturnDesc; } return_ACPI_STATUS (Status); }
ACPI_STATUS AcpiExLoadOp ( ACPI_OPERAND_OBJECT *ObjDesc, ACPI_OPERAND_OBJECT *Target, ACPI_WALK_STATE *WalkState) { ACPI_OPERAND_OBJECT *DdbHandle; ACPI_TABLE_HEADER *Table; ACPI_TABLE_DESC TableDesc; UINT32 TableIndex; ACPI_STATUS Status; UINT32 Length; ACPI_FUNCTION_TRACE (ExLoadOp); ACPI_MEMSET (&TableDesc, 0, sizeof (ACPI_TABLE_DESC)); /* Source Object can be either an OpRegion or a Buffer/Field */ switch (ObjDesc->Common.Type) { case ACPI_TYPE_REGION: ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Load table from Region %p\n", ObjDesc)); /* Region must be SystemMemory (from ACPI spec) */ if (ObjDesc->Region.SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) { return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } /* * If the Region Address and Length have not been previously evaluated, * evaluate them now and save the results. */ if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) { Status = AcpiDsGetRegionArguments (ObjDesc); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } } /* Get the table header first so we can get the table length */ Table = ACPI_ALLOCATE (sizeof (ACPI_TABLE_HEADER)); if (!Table) { return_ACPI_STATUS (AE_NO_MEMORY); } Status = AcpiExRegionRead (ObjDesc, sizeof (ACPI_TABLE_HEADER), ACPI_CAST_PTR (UINT8, Table)); Length = Table->Length; ACPI_FREE (Table); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } /* Must have at least an ACPI table header */ if (Length < sizeof (ACPI_TABLE_HEADER)) { return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); } /* * The original implementation simply mapped the table, with no copy. * However, the memory region is not guaranteed to remain stable and * we must copy the table to a local buffer. For example, the memory * region is corrupted after suspend on some machines. Dynamically * loaded tables are usually small, so this overhead is minimal. * * The latest implementation (5/2009) does not use a mapping at all. * We use the low-level operation region interface to read the table * instead of the obvious optimization of using a direct mapping. * This maintains a consistent use of operation regions across the * entire subsystem. This is important if additional processing must * be performed in the (possibly user-installed) operation region * handler. For example, AcpiExec and ASLTS depend on this. */ /* Allocate a buffer for the table */ TableDesc.Pointer = ACPI_ALLOCATE (Length); if (!TableDesc.Pointer) { return_ACPI_STATUS (AE_NO_MEMORY); } /* Read the entire table */ Status = AcpiExRegionRead (ObjDesc, Length, ACPI_CAST_PTR (UINT8, TableDesc.Pointer)); if (ACPI_FAILURE (Status)) { ACPI_FREE (TableDesc.Pointer); return_ACPI_STATUS (Status); } TableDesc.Address = ObjDesc->Region.Address; break; case ACPI_TYPE_BUFFER: /* Buffer or resolved RegionField */ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Load table from Buffer or Field %p\n", ObjDesc)); /* Must have at least an ACPI table header */ if (ObjDesc->Buffer.Length < sizeof (ACPI_TABLE_HEADER)) { return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); } /* Get the actual table length from the table header */ Table = ACPI_CAST_PTR (ACPI_TABLE_HEADER, ObjDesc->Buffer.Pointer); Length = Table->Length; /* Table cannot extend beyond the buffer */ if (Length > ObjDesc->Buffer.Length) { return_ACPI_STATUS (AE_AML_BUFFER_LIMIT); } if (Length < sizeof (ACPI_TABLE_HEADER)) { return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); } /* * Copy the table from the buffer because the buffer could be modified * or even deleted in the future */ TableDesc.Pointer = ACPI_ALLOCATE (Length); if (!TableDesc.Pointer) { return_ACPI_STATUS (AE_NO_MEMORY); } ACPI_MEMCPY (TableDesc.Pointer, Table, Length); TableDesc.Address = ACPI_TO_INTEGER (TableDesc.Pointer); break; default: return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } /* Validate table checksum (will not get validated in TbAddTable) */ Status = AcpiTbVerifyChecksum (TableDesc.Pointer, Length); if (ACPI_FAILURE (Status)) { ACPI_FREE (TableDesc.Pointer); return_ACPI_STATUS (Status); } /* Complete the table descriptor */ TableDesc.Length = Length; TableDesc.Flags = ACPI_TABLE_ORIGIN_ALLOCATED; /* Install the new table into the local data structures */ Status = AcpiTbAddTable (&TableDesc, &TableIndex); if (ACPI_FAILURE (Status)) { /* Delete allocated table buffer */ AcpiTbDeleteTable (&TableDesc); return_ACPI_STATUS (Status); } /* * Add the table to the namespace. * * Note: Load the table objects relative to the root of the namespace. * This appears to go against the ACPI specification, but we do it for * compatibility with other ACPI implementations. */ Status = AcpiExAddTable (TableIndex, AcpiGbl_RootNode, &DdbHandle); if (ACPI_FAILURE (Status)) { /* On error, TablePtr was deallocated above */ return_ACPI_STATUS (Status); } /* Store the DdbHandle into the Target operand */ Status = AcpiExStore (DdbHandle, Target, WalkState); if (ACPI_FAILURE (Status)) { (void) AcpiExUnloadTable (DdbHandle); /* TablePtr was deallocated above */ AcpiUtRemoveReference (DdbHandle); return_ACPI_STATUS (Status); } ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Dynamic OEM Table Load:")); AcpiTbPrintTableHeader (0, TableDesc.Pointer); /* Remove the reference by added by AcpiExStore above */ AcpiUtRemoveReference (DdbHandle); /* Invoke table handler if present */ if (AcpiGbl_TableHandler) { (void) AcpiGbl_TableHandler (ACPI_TABLE_EVENT_LOAD, TableDesc.Pointer, AcpiGbl_TableHandlerContext); } return_ACPI_STATUS (Status); }
ACPI_STATUS AcpiExLoadTableOp ( ACPI_WALK_STATE *WalkState, ACPI_OPERAND_OBJECT **ReturnDesc) { ACPI_STATUS Status; ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; ACPI_NAMESPACE_NODE *ParentNode; ACPI_NAMESPACE_NODE *StartNode; ACPI_NAMESPACE_NODE *ParameterNode = NULL; ACPI_OPERAND_OBJECT *DdbHandle; ACPI_TABLE_HEADER *Table; UINT32 TableIndex; ACPI_FUNCTION_TRACE (ExLoadTableOp); /* Validate lengths for the SignatureString, OEMIDString, OEMTableID */ if ((Operand[0]->String.Length > ACPI_NAME_SIZE) || (Operand[1]->String.Length > ACPI_OEM_ID_SIZE) || (Operand[2]->String.Length > ACPI_OEM_TABLE_ID_SIZE)) { return_ACPI_STATUS (AE_BAD_PARAMETER); } /* Find the ACPI table in the RSDT/XSDT */ Status = AcpiTbFindTable (Operand[0]->String.Pointer, Operand[1]->String.Pointer, Operand[2]->String.Pointer, &TableIndex); if (ACPI_FAILURE (Status)) { if (Status != AE_NOT_FOUND) { return_ACPI_STATUS (Status); } /* Table not found, return an Integer=0 and AE_OK */ DdbHandle = AcpiUtCreateIntegerObject ((UINT64) 0); if (!DdbHandle) { return_ACPI_STATUS (AE_NO_MEMORY); } *ReturnDesc = DdbHandle; return_ACPI_STATUS (AE_OK); } /* Default nodes */ StartNode = WalkState->ScopeInfo->Scope.Node; ParentNode = AcpiGbl_RootNode; /* RootPath (optional parameter) */ if (Operand[3]->String.Length > 0) { /* * Find the node referenced by the RootPathString. This is the * location within the namespace where the table will be loaded. */ Status = AcpiNsGetNode (StartNode, Operand[3]->String.Pointer, ACPI_NS_SEARCH_PARENT, &ParentNode); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } } /* ParameterPath (optional parameter) */ if (Operand[4]->String.Length > 0) { if ((Operand[4]->String.Pointer[0] != '\\') && (Operand[4]->String.Pointer[0] != '^')) { /* * Path is not absolute, so it will be relative to the node * referenced by the RootPathString (or the NS root if omitted) */ StartNode = ParentNode; } /* Find the node referenced by the ParameterPathString */ Status = AcpiNsGetNode (StartNode, Operand[4]->String.Pointer, ACPI_NS_SEARCH_PARENT, &ParameterNode); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } } /* Load the table into the namespace */ Status = AcpiExAddTable (TableIndex, ParentNode, &DdbHandle); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } /* Parameter Data (optional) */ if (ParameterNode) { /* Store the parameter data into the optional parameter object */ Status = AcpiExStore (Operand[5], ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, ParameterNode), WalkState); if (ACPI_FAILURE (Status)) { (void) AcpiExUnloadTable (DdbHandle); AcpiUtRemoveReference (DdbHandle); return_ACPI_STATUS (Status); } } Status = AcpiGetTableByIndex (TableIndex, &Table); if (ACPI_SUCCESS (Status)) { ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Dynamic OEM Table Load:")); AcpiTbPrintTableHeader (0, Table); } /* Invoke table handler if present */ if (AcpiGbl_TableHandler) { (void) AcpiGbl_TableHandler (ACPI_TABLE_EVENT_LOAD, Table, AcpiGbl_TableHandlerContext); } *ReturnDesc = DdbHandle; return_ACPI_STATUS (Status); }
ACPI_STATUS AcpiExOpcode_2A_1T_1R ( ACPI_WALK_STATE *WalkState) { ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; ACPI_OPERAND_OBJECT *ReturnDesc = NULL; UINT64 Index; ACPI_STATUS Status = AE_OK; ACPI_SIZE Length = 0; ACPI_FUNCTION_TRACE_STR (ExOpcode_2A_1T_1R, AcpiPsGetOpcodeName (WalkState->Opcode)); /* Execute the opcode */ if (WalkState->OpInfo->Flags & AML_MATH) { /* All simple math opcodes (add, etc.) */ ReturnDesc = AcpiUtCreateInternalObject (ACPI_TYPE_INTEGER); if (!ReturnDesc) { Status = AE_NO_MEMORY; goto Cleanup; } ReturnDesc->Integer.Value = AcpiExDoMathOp (WalkState->Opcode, Operand[0]->Integer.Value, Operand[1]->Integer.Value); goto StoreResultToTarget; } switch (WalkState->Opcode) { case AML_MOD_OP: /* Mod (Dividend, Divisor, RemainderResult (ACPI 2.0) */ ReturnDesc = AcpiUtCreateInternalObject (ACPI_TYPE_INTEGER); if (!ReturnDesc) { Status = AE_NO_MEMORY; goto Cleanup; } /* ReturnDesc will contain the remainder */ Status = AcpiUtDivide (Operand[0]->Integer.Value, Operand[1]->Integer.Value, NULL, &ReturnDesc->Integer.Value); break; case AML_CONCAT_OP: /* Concatenate (Data1, Data2, Result) */ Status = AcpiExDoConcatenate (Operand[0], Operand[1], &ReturnDesc, WalkState); break; case AML_TO_STRING_OP: /* ToString (Buffer, Length, Result) (ACPI 2.0) */ /* * Input object is guaranteed to be a buffer at this point (it may have * been converted.) Copy the raw buffer data to a new object of * type String. */ /* * Get the length of the new string. It is the smallest of: * 1) Length of the input buffer * 2) Max length as specified in the ToString operator * 3) Length of input buffer up to a zero byte (null terminator) * * NOTE: A length of zero is ok, and will create a zero-length, null * terminated string. */ while ((Length < Operand[0]->Buffer.Length) && (Length < Operand[1]->Integer.Value) && (Operand[0]->Buffer.Pointer[Length])) { Length++; } /* Allocate a new string object */ ReturnDesc = AcpiUtCreateStringObject (Length); if (!ReturnDesc) { Status = AE_NO_MEMORY; goto Cleanup; } /* * Copy the raw buffer data with no transform. * (NULL terminated already) */ ACPI_MEMCPY (ReturnDesc->String.Pointer, Operand[0]->Buffer.Pointer, Length); break; case AML_CONCAT_RES_OP: /* ConcatenateResTemplate (Buffer, Buffer, Result) (ACPI 2.0) */ Status = AcpiExConcatTemplate (Operand[0], Operand[1], &ReturnDesc, WalkState); break; case AML_INDEX_OP: /* Index (Source Index Result) */ /* Create the internal return object */ ReturnDesc = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_REFERENCE); if (!ReturnDesc) { Status = AE_NO_MEMORY; goto Cleanup; } /* Initialize the Index reference object */ Index = Operand[1]->Integer.Value; ReturnDesc->Reference.Value = (UINT32) Index; ReturnDesc->Reference.Class = ACPI_REFCLASS_INDEX; /* * At this point, the Source operand is a String, Buffer, or Package. * Verify that the index is within range. */ switch ((Operand[0])->Common.Type) { case ACPI_TYPE_STRING: if (Index >= Operand[0]->String.Length) { Length = Operand[0]->String.Length; Status = AE_AML_STRING_LIMIT; } ReturnDesc->Reference.TargetType = ACPI_TYPE_BUFFER_FIELD; break; case ACPI_TYPE_BUFFER: if (Index >= Operand[0]->Buffer.Length) { Length = Operand[0]->Buffer.Length; Status = AE_AML_BUFFER_LIMIT; } ReturnDesc->Reference.TargetType = ACPI_TYPE_BUFFER_FIELD; break; case ACPI_TYPE_PACKAGE: if (Index >= Operand[0]->Package.Count) { Length = Operand[0]->Package.Count; Status = AE_AML_PACKAGE_LIMIT; } ReturnDesc->Reference.TargetType = ACPI_TYPE_PACKAGE; ReturnDesc->Reference.Where = &Operand[0]->Package.Elements [Index]; break; default: Status = AE_AML_INTERNAL; goto Cleanup; } /* Failure means that the Index was beyond the end of the object */ if (ACPI_FAILURE (Status)) { ACPI_EXCEPTION ((AE_INFO, Status, "Index (0x%X%8.8X) is beyond end of object (length 0x%X)", ACPI_FORMAT_UINT64 (Index), (UINT32) Length)); goto Cleanup; } /* * Save the target object and add a reference to it for the life * of the index */ ReturnDesc->Reference.Object = Operand[0]; AcpiUtAddReference (Operand[0]); /* Store the reference to the Target */ Status = AcpiExStore (ReturnDesc, Operand[2], WalkState); /* Return the reference */ WalkState->ResultObj = ReturnDesc; goto Cleanup; default: ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X", WalkState->Opcode)); Status = AE_AML_BAD_OPCODE; break; } StoreResultToTarget: if (ACPI_SUCCESS (Status)) { /* * Store the result of the operation (which is now in ReturnDesc) into * the Target descriptor. */ Status = AcpiExStore (ReturnDesc, Operand[2], WalkState); if (ACPI_FAILURE (Status)) { goto Cleanup; } if (!WalkState->ResultObj) { WalkState->ResultObj = ReturnDesc; } } Cleanup: /* Delete return object on error */ if (ACPI_FAILURE (Status)) { AcpiUtRemoveReference (ReturnDesc); WalkState->ResultObj = NULL; } return_ACPI_STATUS (Status); }
ACPI_STATUS AcpiExOpcode_2A_2T_1R ( ACPI_WALK_STATE *WalkState) { ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; ACPI_OPERAND_OBJECT *ReturnDesc1 = NULL; ACPI_OPERAND_OBJECT *ReturnDesc2 = NULL; ACPI_STATUS Status; ACPI_FUNCTION_TRACE_STR (ExOpcode_2A_2T_1R, AcpiPsGetOpcodeName (WalkState->Opcode)); /* Execute the opcode */ switch (WalkState->Opcode) { case AML_DIVIDE_OP: /* Divide (Dividend, Divisor, RemainderResult QuotientResult) */ ReturnDesc1 = AcpiUtCreateInternalObject (ACPI_TYPE_INTEGER); if (!ReturnDesc1) { Status = AE_NO_MEMORY; goto Cleanup; } ReturnDesc2 = AcpiUtCreateInternalObject (ACPI_TYPE_INTEGER); if (!ReturnDesc2) { Status = AE_NO_MEMORY; goto Cleanup; } /* Quotient to ReturnDesc1, remainder to ReturnDesc2 */ Status = AcpiUtDivide (Operand[0]->Integer.Value, Operand[1]->Integer.Value, &ReturnDesc1->Integer.Value, &ReturnDesc2->Integer.Value); if (ACPI_FAILURE (Status)) { goto Cleanup; } break; default: ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X", WalkState->Opcode)); Status = AE_AML_BAD_OPCODE; goto Cleanup; } /* Store the results to the target reference operands */ Status = AcpiExStore (ReturnDesc2, Operand[2], WalkState); if (ACPI_FAILURE (Status)) { goto Cleanup; } Status = AcpiExStore (ReturnDesc1, Operand[3], WalkState); if (ACPI_FAILURE (Status)) { goto Cleanup; } Cleanup: /* * Since the remainder is not returned indirectly, remove a reference to * it. Only the quotient is returned indirectly. */ AcpiUtRemoveReference (ReturnDesc2); if (ACPI_FAILURE (Status)) { /* Delete the return object */ AcpiUtRemoveReference (ReturnDesc1); } /* Save return object (the remainder) on success */ else { WalkState->ResultObj = ReturnDesc1; } return_ACPI_STATUS (Status); }
ACPI_STATUS AcpiExLoadTableOp ( ACPI_WALK_STATE *WalkState, ACPI_OPERAND_OBJECT **ReturnDesc) { ACPI_STATUS Status; ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; ACPI_NAMESPACE_NODE *ParentNode; ACPI_NAMESPACE_NODE *StartNode; ACPI_NAMESPACE_NODE *ParameterNode = NULL; ACPI_OPERAND_OBJECT *DdbHandle; UINT32 TableIndex; ACPI_FUNCTION_TRACE (ExLoadTableOp); /* Find the ACPI table in the RSDT/XSDT */ AcpiExExitInterpreter (); Status = AcpiTbFindTable ( Operand[0]->String.Pointer, Operand[1]->String.Pointer, Operand[2]->String.Pointer, &TableIndex); AcpiExEnterInterpreter (); if (ACPI_FAILURE (Status)) { if (Status != AE_NOT_FOUND) { return_ACPI_STATUS (Status); } /* Table not found, return an Integer=0 and AE_OK */ DdbHandle = AcpiUtCreateIntegerObject ((UINT64) 0); if (!DdbHandle) { return_ACPI_STATUS (AE_NO_MEMORY); } *ReturnDesc = DdbHandle; return_ACPI_STATUS (AE_OK); } /* Default nodes */ StartNode = WalkState->ScopeInfo->Scope.Node; ParentNode = AcpiGbl_RootNode; /* RootPath (optional parameter) */ if (Operand[3]->String.Length > 0) { /* * Find the node referenced by the RootPathString. This is the * location within the namespace where the table will be loaded. */ Status = AcpiNsGetNodeUnlocked (StartNode, Operand[3]->String.Pointer, ACPI_NS_SEARCH_PARENT, &ParentNode); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } } /* ParameterPath (optional parameter) */ if (Operand[4]->String.Length > 0) { if ((Operand[4]->String.Pointer[0] != AML_ROOT_PREFIX) && (Operand[4]->String.Pointer[0] != AML_PARENT_PREFIX)) { /* * Path is not absolute, so it will be relative to the node * referenced by the RootPathString (or the NS root if omitted) */ StartNode = ParentNode; } /* Find the node referenced by the ParameterPathString */ Status = AcpiNsGetNodeUnlocked (StartNode, Operand[4]->String.Pointer, ACPI_NS_SEARCH_PARENT, &ParameterNode); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } } /* Load the table into the namespace */ ACPI_INFO (("Dynamic OEM Table Load:")); AcpiExExitInterpreter (); Status = AcpiTbLoadTable (TableIndex, ParentNode); AcpiExEnterInterpreter (); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } Status = AcpiExAddTable (TableIndex, &DdbHandle); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } /* Parameter Data (optional) */ if (ParameterNode) { /* Store the parameter data into the optional parameter object */ Status = AcpiExStore (Operand[5], ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, ParameterNode), WalkState); if (ACPI_FAILURE (Status)) { (void) AcpiExUnloadTable (DdbHandle); AcpiUtRemoveReference (DdbHandle); return_ACPI_STATUS (Status); } } *ReturnDesc = DdbHandle; return_ACPI_STATUS (Status); }