/** @file
Copyright (C) 2020-2025 Advanced Micro Devices, Inc. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "LocalAmlLib.h"
#include
#define FILECODE LIBRARY_DXEAMLGENERATIONLIB_AMLNAMEDOBJECT_FILECODE
#define METHOD_ARGS_MAX 7
#define MAX_SYNC_LEVEL 0x0F
#define GENERIC_FIELD_IDENTIFIER "FIELD"
/**
Creates a Device (ObjectName, Object)
Object must be created between AmlStart and AmlClose Phase
DefName := DeviceOp PkgLength NameString TermList
NameOp := ExtOpPrefix 0x82
ExtOpPrefix := 0x5B
@param[in] Phase - Either AmlStart or AmlClose
@param[in] String - Object name
@param[in,out] ListHead - Linked list has completed String Object after
AmlClose.
@retval EFI_SUCCESS
@retval Error status
**/
EFI_STATUS
EFIAPI
AmlDevice (
IN AML_FUNCTION_PHASE Phase,
IN CHAR8 *String,
IN OUT LIST_ENTRY *ListHead
)
{
EFI_STATUS Status;
AML_OBJECT_INSTANCE *Object;
AML_OBJECT_INSTANCE *ChildObject;
UINTN ChildCount;
if ((Phase >= AmlInvalid) || (String == NULL) || (ListHead == NULL)) {
return EFI_INVALID_PARAMETER;
}
Status = EFI_DEVICE_ERROR;
Object = NULL;
ChildObject = NULL;
switch (Phase) {
case AmlStart:
Status = InternalAppendNewAmlObject (&Object, String, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Start Device for %a object\n", __func__, String));
goto Done;
}
// Start required PkgLength
Status = AmlPkgLength (AmlStart, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Start PkgLength for %a object\n", __func__, String));
goto Done;
}
// Insert required NameString
Status = AmlOPNameString (String, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Insert NameString for %a object\n", __func__, String));
goto Done;
}
// TermList is too complicated and must be added outside
break;
case AmlClose:
// TermList should be closed already
// Close required PkgLength before finishing Object
Status = AmlPkgLength (AmlClose, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Close PkgLength for %a object\n", __func__, String));
goto Done;
}
Status = InternalAmlLocateObjectByIdentifier (&Object, String, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Locate %a object\n", __func__, String));
goto Done;
}
// Get rid of original Identifier data
InternalFreeAmlObjectData (Object);
// Collect child data and delete children
Status = InternalAmlCollapseAndReleaseChildren (
&ChildObject,
&ChildCount,
&Object->Link,
ListHead
);
if (EFI_ERROR (Status) ||
(ChildObject->Data == NULL) ||
(ChildObject->DataSize == 0))
{
DEBUG ((DEBUG_ERROR, "%a: ERROR: %a child data collection.\n", __func__, String));
goto Done;
}
// Device Op is two bytes
Object->DataSize = ChildObject->DataSize + 2;
Object->Data = AllocatePool (Object->DataSize);
if (Object->Data == NULL) {
Status = EFI_OUT_OF_RESOURCES;
DEBUG ((DEBUG_ERROR, "%a: ERROR: allocate Object->Data for %a\n", __func__, String));
goto Done;
}
Object->Data[0] = AML_EXT_OP;
Object->Data[1] = AML_EXT_DEVICE_OP;
CopyMem (
&Object->Data[2],
ChildObject->Data,
ChildObject->DataSize
);
InternalFreeAmlObject (&ChildObject, ListHead);
Object->Completed = TRUE;
Status = EFI_SUCCESS;
break;
default:
Status = EFI_DEVICE_ERROR;
break;
}
Done:
if (EFI_ERROR (Status)) {
InternalFreeAmlObject (&Object, ListHead);
InternalFreeAmlObject (&ChildObject, ListHead);
}
return Status;
}
/**
Creates an AccessField
AccessField := 0x01 AccessType AccessAttrib
@param[in] AccessType - Access type for field member
@param[in] AccessAttribute - Access attribute for field member
@param[in,out] ListHead - Linked list containing AML objects
@retval EFI_SUCCESS
@retval Error status
**/
EFI_STATUS
EFIAPI
InternalAmlAccessField (
IN EFI_ACPI_FIELD_ACCESS_TYPE_KEYWORDS AccessType,
IN EFI_ACPI_FIELD_ACCESS_ATTRIBUTE_KEYWORDS AccessAttribute,
IN OUT LIST_ENTRY *ListHead
)
{
EFI_STATUS Status;
AML_OBJECT_INSTANCE *Object;
Status = EFI_DEVICE_ERROR;
Object = NULL;
// Start new AML object
Status = InternalAppendNewAmlObjectNoData (&Object, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Start ACCESSFIELD object\n", __func__));
goto Done;
}
Object->Data = AllocateZeroPool (3);
// AML_ACCESSFIELD_OP + AccessType + AccessAttrib
if (Object->Data == NULL) {
Status = EFI_OUT_OF_RESOURCES;
DEBUG ((DEBUG_ERROR, "%a: ERROR: allocate Object->Data for ACCESSFIELD\n", __func__));
goto Done;
}
Object->Data[0] = AML_FIELD_ACCESS_OP;
Object->Data[1] = (UINT8)AccessType;
Object->Data[2] = (UINT8)AccessAttribute;
Object->DataSize = 3;
Object->Completed = TRUE;
Status = EFI_SUCCESS;
Done:
if (EFI_ERROR (Status)) {
InternalFreeAmlObject (&Object, ListHead);
}
return Status;
}
/**
Creates an ExtendedAccessField
ExtendedAccessField := 0x03 AccessType ExtendedAccessAttrib AccessLength
@param[in] AccessType - Access type for field member
@param[in] AccessAttribute - Access attribute for field member
@param[in] AccessLength - Specifies the access length for the field member
@param[in,out] ListHead - Linked list containing AML objects
@retval EFI_SUCCESS
@retval Error status
**/
EFI_STATUS
EFIAPI
InternalAmlExtendedAccessField (
IN EFI_ACPI_FIELD_ACCESS_TYPE_KEYWORDS AccessType,
IN EFI_ACPI_FIELD_ACCESS_ATTRIBUTE_KEYWORDS AccessAttribute,
IN UINT8 AccessLength,
IN OUT LIST_ENTRY *ListHead
)
{
EFI_STATUS Status;
AML_OBJECT_INSTANCE *Object;
Status = EFI_DEVICE_ERROR;
Object = NULL;
// Start new AML object
Status = InternalAppendNewAmlObjectNoData (&Object, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Start EXTENDEDACCESSFIELD object\n", __func__));
goto Done;
}
Object->Data = AllocateZeroPool (4);
// AML_EXTACCESSFIELD_OP + AccessType + AccessAttrib + AccessLength
if (Object->Data == NULL) {
Status = EFI_OUT_OF_RESOURCES;
DEBUG ((DEBUG_ERROR, "%a: ERROR: allocate Object->Data for EXTENDEDACCESSFIELD\n", __func__));
goto Done;
}
Object->Data[0] = AML_FIELD_EXT_ACCESS_OP;
Object->Data[1] = (UINT8)AccessType;
Object->Data[2] = (UINT8)AccessAttribute;
Object->Data[3] = AccessLength;
Object->DataSize = 4;
Object->Completed = TRUE;
Status = EFI_SUCCESS;
Done:
if (EFI_ERROR (Status)) {
InternalFreeAmlObject (&Object, ListHead);
}
return Status;
}
/**
Creates an AccessAs Field Unit
AccessAs (AccessType, AccessAttribute)
AccessAs (AccessType, AccessAttribute (AccessLength))
AccessField := 0x01 AccessType AccessAttrib
AccessType := ByteData // Bits 0:3 - Same as AccessType bits of FieldFlags.
// Bits 4:5 - Reserved
// Bits 7:6 - 0 = AccessAttrib = Normal Access Attributes
// 1 = AccessAttrib = AttribBytes (x)
// 2 = AccessAttrib = AttribRawBytes (x)
// 3 = AccessAttrib = AttribRawProcessBytes (x)
// x' is encoded as bits 0:7 of the AccessAttrib byte.
The description of bits 7:6 is incorrect and if AttribBytes,
AttribRawBytes, or AttribRawProcessBytes are used here, an
ExtendedAccessField is used with the following definitions
ExtendedAccessField := 0x03 AccessType ExtendedAccessAttrib AccessLength
ExtendedAccessAttrib := ByteData // 0x0B AttribBytes
// 0x0E AttribRawBytes
// 0x0F AttribRawProcess
AccessAttrib := ByteData // If AccessType is BufferAcc for the SMB or
// GPIO OpRegions, AccessAttrib can be one of
// the following values:
// 0x02 AttribQuick
// 0x04 AttribSendReceive
// 0x06 AttribByte
// 0x08 AttribWord
// 0x0A AttribBlock
// 0x0C AttribProcessCall
// 0x0D AttribBlockProcessCall
@param[in] AccessType - Access type for field member
@param[in] AccessAttribute - Access attribute for field member
@param[in] AccessLength - Only used if AccessAttribute is AttribBytes,
AttribRawBytes, or AttribRawProcessBytes.
Specifies the access length for the field member
Otherwise, ignored.
@param[in,out] ListHead - Linked list containing AML objects
@retval EFI_SUCCESS
@retval Error status
**/
EFI_STATUS
EFIAPI
AmlOPAccessAs (
IN EFI_ACPI_FIELD_ACCESS_TYPE_KEYWORDS AccessType,
IN EFI_ACPI_FIELD_ACCESS_ATTRIBUTE_KEYWORDS AccessAttribute,
IN UINT8 AccessLength,
IN OUT LIST_ENTRY *ListHead
)
{
EFI_STATUS Status;
// AcessType parameter check
if (AccessType > BufferAcc) {
return EFI_INVALID_PARAMETER;
}
// AccessAttrib parameter checking
if ((AccessAttribute >= AttribNormal) && (AccessAttribute <= AttribBlock)) {
if ((AccessAttribute & 1) == 1) {
return EFI_INVALID_PARAMETER;
}
} else if (AccessAttribute > AttribRawProcessBytes) {
return EFI_INVALID_PARAMETER;
}
// if AccessAttrib requires a length parameter, then an ExtendedAccessField is used
switch (AccessAttribute) {
case AttribBytes:
case AttribRawBytes:
case AttribRawProcessBytes:
Status = InternalAmlExtendedAccessField (AccessType, AccessAttribute, AccessLength, ListHead);
break;
default:
Status = InternalAmlAccessField (AccessType, AccessAttribute, ListHead);
break;
}
return Status;
}
/**
Creates an External Object
External (ObjectName, ObjectType, ReturnType, ParameterTypes)
Note: ReturnType is not used for AML encoding and is therefore not passed in
to this function.
ParameterTypes is only used if the ObjectType is a MethodObj. It
specifies MethodObj's argument types in a list. For the purposes of
this library, we are passing in the the number of input parameters for
that MethodObj.
DefExternal := ExternalOp NameString ObjectType ArgumentCount
ExternalOp := 0x15
ObjectType := ByteData
ArgumentCount := ByteData (0 - 7)
@param[in] Name - Object name
@param[in] ObjectType - Type of object declared
@param[in] NumArgs - Only used if ObjectType is MethodObj.
Specifies the number of input parameters for
that MethodObj.
Otherwise, ignored.
@param[in,out] ListHead - Linked list that has completed External Object
after AmlClose.
@retval EFI_SUCCESS
@retval Error status
**/
EFI_STATUS
EFIAPI
AmlOPExternal (
IN CHAR8 *Name,
IN UINT8 ObjectType,
IN UINT8 NumArgs,
IN OUT LIST_ENTRY *ListHead
)
{
EFI_STATUS Status;
AML_OBJECT_INSTANCE *Object;
AML_OBJECT_INSTANCE *ChildObject;
UINTN ChildCount;
if ((Name == NULL) ||
(NumArgs > METHOD_ARGS_MAX) ||
(ObjectType >= InvalidObj) ||
(ListHead == NULL))
{
return EFI_INVALID_PARAMETER;
}
Status = EFI_DEVICE_ERROR;
Object = NULL;
ChildObject = NULL;
// Start EXTERNAL object
Status = InternalAppendNewAmlObject (&Object, "EXTERNAL", ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Start %a object\n", __func__, Name));
goto Done;
}
// Insert required NameString
Status = AmlOPNameString (Name, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Start %a NameString object\n", __func__, Name));
goto Done;
}
Status = InternalAmlLocateObjectByIdentifier (&Object, "EXTERNAL", ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Locate %a object\n", __func__, Name));
goto Done;
}
// Get rid of original Identifier data
InternalFreeAmlObjectData (Object);
// Collect child data and delete children
Status = InternalAmlCollapseAndReleaseChildren (
&ChildObject,
&ChildCount,
&Object->Link,
ListHead
);
if (EFI_ERROR (Status) ||
(ChildObject->Data == NULL) ||
(ChildObject->DataSize == 0))
{
DEBUG ((DEBUG_ERROR, "%a: ERROR: %a has no child data.\n", __func__, Name));
goto Done;
}
Object->Data = AllocateZeroPool (ChildObject->DataSize + 3);
// AML_EXTERNAL_OP + Name + ObjectType + ArgumentCount
if (Object->Data == NULL) {
Status = EFI_OUT_OF_RESOURCES;
DEBUG ((DEBUG_ERROR, "%a: ERROR: allocate Object->Data for %a\n", __func__, Name));
goto Done;
}
Object->DataSize = 0;
Object->Data[0] = AML_EXTERNAL_OP;
Object->DataSize++;
CopyMem (
&Object->Data[Object->DataSize],
ChildObject->Data,
ChildObject->DataSize
);
Object->DataSize += ChildObject->DataSize;
Object->Data[Object->DataSize] = ObjectType;
Object->DataSize++;
Object->Data[Object->DataSize] = NumArgs;
Object->DataSize++;
InternalFreeAmlObject (&ChildObject, ListHead);
Object->Completed = TRUE;
Status = EFI_SUCCESS;
Done:
if (EFI_ERROR (Status)) {
InternalFreeAmlObject (&ChildObject, ListHead);
InternalFreeAmlObject (&Object, ListHead);
}
return Status;
}
/**
Locates the AML object that holds the cumulative offset term.
This is the node directly after the node designated by
GENERIC_FIELD_IDENTIFIER in Object->Data.
@param[out] ReturnObject - Object that contains the offset term
@param[in,out] ListHead - Linked list that contains the GENERIC_FIELD_IDENTIFIER
@retval EFI_SUCCESS
@retval Error status
**/
EFI_STATUS
EFIAPI
InternalAmlLocateOffsetTerm (
OUT AML_OBJECT_INSTANCE **ReturnObject,
IN OUT LIST_ENTRY *ListHead
)
{
LIST_ENTRY *Node;
AML_OBJECT_INSTANCE *Object;
UINTN IdentifierSize;
CHAR8 *Identifier;
if (ListHead == NULL) {
return EFI_INVALID_PARAMETER;
}
Object = NULL;
*ReturnObject = NULL;
Identifier = GENERIC_FIELD_IDENTIFIER;
IdentifierSize = AsciiStrLen (Identifier) + 1;
// Look Backwards and find Node for this Object
Node = ListHead;
do {
Node = GetPreviousNode (ListHead, Node);
Object = AML_OBJECT_INSTANCE_FROM_LINK (Node);
if ((Object->DataSize != 0) &&
(Object->DataSize == IdentifierSize) &&
(CompareMem (
Object->Data,
Identifier,
MAX (Object->DataSize, IdentifierSize)
) == 0))
{
break;
}
} while (Node != ListHead);
// Check to make sure FIELD is found, otherwise error
if ((Object->DataSize == 0) ||
(Object->DataSize != IdentifierSize) ||
CompareMem (
Object->Data,
Identifier,
(MAX (Object->DataSize, IdentifierSize) != 0)
))
{
return EFI_DEVICE_ERROR;
}
// Have found FIELD
Node = GetNextNode (ListHead, Node);
Object = AML_OBJECT_INSTANCE_FROM_LINK (Node);
*ReturnObject = Object;
return EFI_SUCCESS;
}
/**
Offset (ByteOffset)
Creates a ReservedField if the passed ByteOffset is larger than
the previous bit length value optionally specified by an AmlOPFieldListItem,
or another Offset call. All offsets are defined starting from zero, based at
the starting address of the parent Operation Region.
ReservedField := 0x00 PkgLength
@param[in] ByteLength -Byte offset of the next defined field within
the parent Operation Region
@param[in,out] ListHead - Linked list has completed Offset object
@retval EFI_SUCCESS
@retval Error status
**/
EFI_STATUS
EFIAPI
AmlOPOffset (
IN UINT32 ByteOffset,
IN OUT LIST_ENTRY *ListHead
)
{
AML_OBJECT_INSTANCE *Object;
AML_OBJECT_INSTANCE *OffsetObject;
UINT8 *PkgLength;
UINTN DataLength;
EFI_STATUS Status;
UINT64 InternalOffsetData;
UINT64 BitCount;
if (ListHead == NULL) {
return EFI_INVALID_PARAMETER;
}
InternalOffsetData = 0;
BitCount = LShiftU64 (ByteOffset, 3);
Object = NULL;
OffsetObject = NULL;
PkgLength = NULL;
// Find and read internal offset data
Status = InternalAmlLocateOffsetTerm (&OffsetObject, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Locating internal offset term\n", __func__));
goto Done;
}
InternalOffsetData = *(UINT64 *)OffsetObject->Data;
if (InternalOffsetData > BitCount) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Invalid backwards offset\n", __func__));
Status = EFI_INVALID_PARAMETER;
goto Done;
} else if (InternalOffsetData == BitCount) {
// Do not need to append any reserved fields
Status = EFI_SUCCESS;
goto Done;
}
// update internal offset value to new offset
*(UINT64 *)OffsetObject->Data = BitCount;
// take difference to find how many bits to reserve
BitCount = BitCount - InternalOffsetData;
// Create new object for the offset data, add pkglength encoding
Status = InternalAppendNewAmlObjectNoData (&Object, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: appending new AML object\n", __func__));
goto Done;
}
Status = InternalAmlBitPkgLength ((UINT32)BitCount, &PkgLength, &DataLength);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: internal AML PkgLength\n", __func__));
goto Done;
}
Object->DataSize = DataLength + 1; // add one for Reserved Field Indicator
Object->Data = AllocateZeroPool (Object->DataSize);
if (Object->Data == NULL) {
Status = EFI_OUT_OF_RESOURCES;
DEBUG ((DEBUG_ERROR, "%a: ERROR: allocate Object->Data for Offset\n", __func__));
goto Done;
}
Object->Data[0] = 0;
CopyMem (&Object->Data[1], PkgLength, DataLength); // read internal offset data
Object->Completed = TRUE;
FreePool (PkgLength);
Done:
if (EFI_ERROR (Status)) {
InternalFreeAmlObject (&Object, ListHead);
InternalFreeAmlObject (&OffsetObject, ListHead);
}
return Status;
}
/**
Creates a NamedField or a ReservedField, depending on the
parameters.
To create a NamedField item pass in the NameSeg and Bitlength
as in ASL. To create a ReservedField pass "" as the Name.
Must be used inside a Field or IndexField TermList.
NamedField := NameSeg PkgLength
ReservedField := 0x00 PkgLength
@param[in] Name - Field NameSeg
@param[in] BitLength - Length of field item in bits
@param[in,out] ListHead - Linked list has completed FieldUnitItem
@retval EFI_SUCCESS
@retval Error status
**/
EFI_STATUS
EFIAPI
AmlOPFieldUnit (
IN CHAR8 *Name,
IN UINT32 BitLength,
IN OUT LIST_ENTRY *ListHead
)
{
AML_OBJECT_INSTANCE *Object;
AML_OBJECT_INSTANCE *OffsetObject;
EFI_STATUS Status;
if ((ListHead == NULL) || (Name == NULL)) {
return EFI_INVALID_PARAMETER;
}
Status = EFI_DEVICE_ERROR;
Object = NULL;
OffsetObject = NULL;
if (AsciiStrLen (Name) == 0) {
if (BitLength > 0) {
// Prepend a 0 to the list
Status = InternalAppendNewAmlObjectNoData (&Object, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Unable to append AML object.\n", __func__));
goto Done;
}
Object->Data = AllocateZeroPool (1);
Object->DataSize = 1;
Object->Completed = TRUE;
} else {
Status = EFI_SUCCESS;
goto Done;
}
} else {
// add NameSeg to List
Status = InternalAmlNameSeg (Name, ListHead);
}
if (EFI_ERROR (Status)) {
goto Done;
}
// Locate and update internal Offset term
Status = InternalAmlLocateOffsetTerm (&Object, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Locating offset term for %a object\n", __func__, Name));
goto Done;
}
*(UINT64 *)Object->Data += BitLength; // write
// Add BitLength as a PkgLength term
Status = InternalAppendNewAmlObjectNoData (&Object, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Appending BitLength for %a object\n", __func__, Name));
goto Done;
}
Status = InternalAmlBitPkgLength (BitLength, &Object->Data, &Object->DataSize);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Appending BitLength for %a object\n", __func__, Name));
goto Done;
}
Object->Completed = TRUE;
Done:
if (EFI_ERROR (Status)) {
InternalFreeAmlObject (&Object, ListHead);
InternalFreeAmlObject (&OffsetObject, ListHead);
}
return Status;
}
/**
Creates a Field
Field (RegionName, AccessType, LockRule, UpdateRule) {FieldUnitList}
FieldUnitList must be added between AmlStart and AmlClose phase
DefField := FieldOp PkgLength NameString FieldFlags FieldList
FieldOp := ExtOpPrefix 0x81
@param[in] Phase - Either AmlStart or AmlClose
@param[in] Name - Field NameString
@param[in] AccessType - Access Type for field
@param[in] LockRule - Lock rule for field
@param[in] UpdateRule - Update rule for field
@param[in,out] ListHead - Linked list has completed Field Object after
AmlClose.
@retval EFI_SUCCESS
@retval Error status
**/
EFI_STATUS
EFIAPI
AmlField (
IN AML_FUNCTION_PHASE Phase,
IN CHAR8 *Name,
IN EFI_ACPI_FIELD_ACCESS_TYPE_KEYWORDS AccessType,
IN EFI_ACPI_FIELD_LOCK_RULE_KEYWORDS LockRule,
IN EFI_ACPI_FIELD_UPDATE_RULE_KEYWORDS UpdateRule,
IN OUT LIST_ENTRY *ListHead
)
{
EFI_STATUS Status;
AML_OBJECT_INSTANCE *Object;
AML_OBJECT_INSTANCE *ChildObject;
UINT8 FieldFlags;
UINTN ChildCount;
if ((ListHead == NULL) || (Name == NULL) || (AsciiStrLen (Name) == 0)) {
return EFI_INVALID_PARAMETER;
}
// parameter validation
if ((Phase > AmlClose) || (AccessType > BufferAcc) || (LockRule > Lock) || (UpdateRule > WriteAsZeros)) {
return EFI_INVALID_PARAMETER;
}
Status = EFI_DEVICE_ERROR;
Object = NULL;
ChildObject = NULL;
switch (Phase) {
case AmlStart:
Status = InternalAppendNewAmlObject (&Object, GENERIC_FIELD_IDENTIFIER, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Start Field for %a object\n", __func__, Name));
goto Done;
}
// Insert internal offset counter
Status = InternalAppendNewAmlObjectNoData (&Object, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Unable to append AML object.\n", __func__));
goto Done;
}
Object->DataSize = sizeof (UINT64);
Object->Data = AllocateZeroPool (Object->DataSize);
Object->Completed = TRUE;
if (EFI_ERROR (Status) || (Object->Data == NULL)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Start Field internal offset %a object\n", __func__, Name));
goto Done;
}
// Start required PkgLength
Status = AmlPkgLength (AmlStart, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Start PkgLength for %a object\n", __func__, Name));
goto Done;
}
// Insert required NameString
Status = AmlOPNameString (Name, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Start NameString for %a object\n", __func__, Name));
goto Done;
}
// Add Field Flags
Status = InternalAppendNewAmlObjectNoData (&Object, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Start FIELD_FLAGS for %a object\n", __func__, Name));
goto Done;
}
// Field Flags is one byte
Object->DataSize = 1;
Object->Data = AllocatePool (Object->DataSize);
if (Object->Data == NULL) {
Status = EFI_OUT_OF_RESOURCES;
DEBUG ((DEBUG_ERROR, "%a: ERROR: allocate Object->Data for %a\n", __func__, Name));
goto Done;
}
FieldFlags = (UINT8)((UpdateRule << 5) | (LockRule << 4) | AccessType);
Object->Data[0] = FieldFlags;
Object->Completed = TRUE;
// TermList is too complicated and must be added outside
break;
case AmlClose:
// Required NameString completed in one phase call
// Close required PkgLength before finishing Object
Status = AmlPkgLength (AmlClose, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Close PkgLength for %a object\n", __func__, Name));
goto Done;
}
// Remove internal offset counter
Status = InternalAmlLocateOffsetTerm (&Object, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Locating internal offset term%a\n", __func__, Name));
goto Done;
}
Status = InternalFreeAmlObject (&Object, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: removing offset term%a\n", __func__, Name));
goto Done;
}
// remove original field identifier data
Status = InternalAmlLocateObjectByIdentifier (&Object, GENERIC_FIELD_IDENTIFIER, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Locate %a object\n", __func__, Name));
goto Done;
}
// Get rid of original Identifier data
InternalFreeAmlObjectData (Object);
// Collect child data and delete children
Status = InternalAmlCollapseAndReleaseChildren (
&ChildObject,
&ChildCount,
&Object->Link,
ListHead
);
if (EFI_ERROR (Status) ||
(ChildObject->Data == NULL) ||
(ChildObject->DataSize == 0))
{
DEBUG ((DEBUG_ERROR, "%a: ERROR: %a child data collection.\n", __func__, Name));
goto Done;
}
// Field Op is two bytes
Object->DataSize = ChildObject->DataSize + 2;
Object->Data = AllocatePool (Object->DataSize);
if (Object->Data == NULL) {
Status = EFI_OUT_OF_RESOURCES;
DEBUG ((DEBUG_ERROR, "%a: ERROR: allocate Object->Data for %a\n", __func__, Name));
goto Done;
}
Object->Data[0] = AML_EXT_OP;
Object->Data[1] = AML_EXT_FIELD_OP;
CopyMem (
&Object->Data[2],
ChildObject->Data,
ChildObject->DataSize
);
InternalFreeAmlObject (&ChildObject, ListHead);
Object->Completed = TRUE;
Status = EFI_SUCCESS;
break;
default:
Status = EFI_DEVICE_ERROR;
break;
}
Done:
if (EFI_ERROR (Status)) {
InternalFreeAmlObject (&ChildObject, ListHead);
InternalFreeAmlObject (&Object, ListHead);
}
return Status;
}
/**
Creates a BankField
BankField (RegionName, BankName, BankValue, AccessType, LockRule, UpdateRule) {FieldUnitList}
FieldUnitList must be added between AmlStart and AmlClose phase
DefBankField := BankFieldOp PkgLength NameString NameString BankValue FieldFlags FieldList
BankFieldOp := ExtOpPrefix 0x87
BankValue := TermArg => Integer
@param[in] Phase - Either AmlStart or AmlClose
@param[in] RegionName - Name of host Operation Region
@param[in] BankName - Name of bank selection register
@param[in] BankValue - Bank Selection ID
@param[in] AccessType - Access Type as in Field
@param[in] LockRule - Lock rule as in Field
@param[in] UpdateRule - Update rule as in Field
@param[in,out] ListHead - Linked list has completed BankField Object
@retval EFI_SUCCESS
@retval Error status
**/
EFI_STATUS
EFIAPI
AmlBankField (
IN AML_FUNCTION_PHASE Phase,
IN CHAR8 *RegionName,
IN CHAR8 *BankName,
IN UINT64 BankValue,
IN EFI_ACPI_FIELD_ACCESS_TYPE_KEYWORDS AccessType,
IN EFI_ACPI_FIELD_LOCK_RULE_KEYWORDS LockRule,
IN EFI_ACPI_FIELD_UPDATE_RULE_KEYWORDS UpdateRule,
IN OUT LIST_ENTRY *ListHead
)
{
EFI_STATUS Status;
AML_OBJECT_INSTANCE *Object;
AML_OBJECT_INSTANCE *ChildObject;
UINT8 FieldFlags;
UINTN ChildCount;
if ((ListHead == NULL) || (RegionName == NULL) || (AsciiStrLen (RegionName) == 0) ||
(BankName == NULL) || (AsciiStrLen (BankName) == 0))
{
return EFI_INVALID_PARAMETER;
}
// parameter validation
if ((Phase > AmlClose) || (AccessType > BufferAcc) || (LockRule > Lock) || (UpdateRule > WriteAsZeros)) {
return EFI_INVALID_PARAMETER;
}
Status = EFI_DEVICE_ERROR;
Object = NULL;
ChildObject = NULL;
switch (Phase) {
case AmlStart:
Status = InternalAppendNewAmlObject (&Object, GENERIC_FIELD_IDENTIFIER, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Start BankField for %a object\n", __func__, BankName));
goto Done;
}
// Insert internal offset counter
Status = InternalAppendNewAmlObjectNoData (&Object, ListHead);
Object->DataSize = sizeof (UINT64);
Object->Data = AllocateZeroPool (Object->DataSize);
Object->Completed = TRUE;
if (EFI_ERROR (Status) || (Object->Data == NULL)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Start BankField internal offset %a object\n", __func__, BankName));
goto Done;
}
// Start required PkgLength
Status = AmlPkgLength (AmlStart, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Start PkgLength for %a object\n", __func__, BankName));
goto Done;
}
// Insert required Region NameString
Status = AmlOPNameString (RegionName, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Start NameString for %a object\n", __func__, RegionName));
goto Done;
}
// Insert required Bank NameString
Status = AmlOPNameString (BankName, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Start NameString for %a object\n", __func__, BankName));
goto Done;
}
// Insert required BankValue integer
Status = AmlOPDataInteger (BankValue, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Adding BankValue Integer for %a object\n", __func__, BankName));
goto Done;
}
// Add Field Flags
Status = InternalAppendNewAmlObjectNoData (&Object, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Start FIELD_FLAGS for %a object\n", __func__, BankName));
goto Done;
}
// Field Flags is one byte
Object->DataSize = 1;
Object->Data = AllocatePool (Object->DataSize);
if (Object->Data == NULL) {
Status = EFI_OUT_OF_RESOURCES;
DEBUG ((DEBUG_ERROR, "%a: ERROR: allocate Object->Data for %a\n", __func__, BankName));
goto Done;
}
FieldFlags = (UINT8)((UpdateRule << 5) | (LockRule << 4) | AccessType);
Object->Data[0] = FieldFlags;
Object->Completed = TRUE;
// TermList is too complicated and must be added outside
break;
case AmlClose:
// Required NameStrings completed in one phase call
// Close required PkgLength before finishing Object
Status = AmlPkgLength (AmlClose, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Close PkgLength for %a object\n", __func__, BankName));
goto Done;
}
// Remove internal offset counter
Status = InternalAmlLocateOffsetTerm (&Object, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Locating internal offset term%a\n", __func__, BankName));
goto Done;
}
Status = InternalFreeAmlObject (&Object, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: removing offset term%a\n", __func__, BankName));
goto Done;
}
// remove original field identifier data
Status = InternalAmlLocateObjectByIdentifier (&Object, GENERIC_FIELD_IDENTIFIER, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Locate %a object\n", __func__, BankName));
goto Done;
}
// Get rid of original Identifier data
InternalFreeAmlObjectData (Object);
// Collect child data and delete children
Status = InternalAmlCollapseAndReleaseChildren (
&ChildObject,
&ChildCount,
&Object->Link,
ListHead
);
if (EFI_ERROR (Status) ||
(ChildObject->Data == NULL) ||
(ChildObject->DataSize == 0))
{
DEBUG ((DEBUG_ERROR, "%a: ERROR: %a child data collection.\n", __func__, BankName));
goto Done;
}
// Field Op is two bytes
Object->DataSize = ChildObject->DataSize + 2;
Object->Data = AllocatePool (Object->DataSize);
if (Object->Data == NULL) {
Status = EFI_OUT_OF_RESOURCES;
DEBUG ((DEBUG_ERROR, "%a: ERROR: allocate Object->Data for %a\n", __func__, BankName));
goto Done;
}
Object->Data[0] = AML_EXT_OP;
Object->Data[1] = AML_EXT_BANK_FIELD_OP;
CopyMem (
&Object->Data[2],
ChildObject->Data,
ChildObject->DataSize
);
InternalFreeAmlObject (&ChildObject, ListHead);
Object->Completed = TRUE;
Status = EFI_SUCCESS;
break;
default:
Status = EFI_DEVICE_ERROR;
break;
}
Done:
if (EFI_ERROR (Status)) {
InternalFreeAmlObject (&ChildObject, ListHead);
InternalFreeAmlObject (&Object, ListHead);
}
return Status;
}
/**
Creates an IndexField
IndexField (IndexName, DataName, AccessType, LockRule, UpdateRule) {FieldUnitList}
FieldUnitList must be added between AmlStart and AmlClose phase
DefIndexField := IndexFieldOp PkgLength NameString NameString FieldFlags FieldList
IndexFieldOp := ExtOpPrefix 0x86
@param[in] Phase - Either AmlStart or AmlClose
@param[in] IndexName - Name of Index FieldUnit
@param[in] DataName - Name of Data FieldUnit
@param[in] AccessType - Access Type for the FieldUnit
@param[in] LockRule - Lock rule for the FieldUnit
@param[in] UpdateRule - Update rule for the FieldUnit
@param[in,out] ListHead - Linked list has completed IndexField Object
@retval EFI_SUCCESS
@retval Error status
**/
EFI_STATUS
EFIAPI
AmlIndexField (
IN AML_FUNCTION_PHASE Phase,
IN CHAR8 *IndexName,
IN CHAR8 *DataName,
IN EFI_ACPI_FIELD_ACCESS_TYPE_KEYWORDS AccessType,
IN EFI_ACPI_FIELD_LOCK_RULE_KEYWORDS LockRule,
IN EFI_ACPI_FIELD_UPDATE_RULE_KEYWORDS UpdateRule,
IN OUT LIST_ENTRY *ListHead
)
{
EFI_STATUS Status;
AML_OBJECT_INSTANCE *Object;
AML_OBJECT_INSTANCE *ChildObject;
UINT8 FieldFlags;
UINTN ChildCount;
if ((ListHead == NULL) || (IndexName == NULL) || (AsciiStrLen (IndexName) == 0) ||
(DataName == NULL) || (AsciiStrLen (DataName) == 0))
{
return EFI_INVALID_PARAMETER;
}
// parameter validation
if ((Phase > AmlClose) || (AccessType > BufferAcc) || (LockRule > Lock) || (UpdateRule > WriteAsZeros)) {
return EFI_INVALID_PARAMETER;
}
Status = EFI_DEVICE_ERROR;
Object = NULL;
ChildObject = NULL;
switch (Phase) {
case AmlStart:
Status = InternalAppendNewAmlObject (&Object, GENERIC_FIELD_IDENTIFIER, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Start IndexField for %a object\n", __func__, IndexName));
goto Done;
}
// Insert internal offset counter
Status = InternalAppendNewAmlObjectNoData (&Object, ListHead);
Object->DataSize = sizeof (UINT64);
Object->Data = AllocateZeroPool (Object->DataSize);
Object->Completed = TRUE;
if (EFI_ERROR (Status) || (Object->Data == NULL)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Start IndexField internal offset %a object\n", __func__, IndexName));
goto Done;
}
// Start required PkgLength
Status = AmlPkgLength (AmlStart, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Start PkgLength for %a object\n", __func__, IndexName));
goto Done;
}
// Insert required Index NameString
Status = AmlOPNameString (IndexName, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Start NameString for %a object\n", __func__, IndexName));
goto Done;
}
// Insert required Data NameString
Status = AmlOPNameString (DataName, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Start NameString for %a object\n", __func__, DataName));
goto Done;
}
// Add Field Flags
Status = InternalAppendNewAmlObjectNoData (&Object, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Start FIELD_FLAGS for %a object\n", __func__, IndexName));
goto Done;
}
// Field Flags is one byte
Object->DataSize = 1;
Object->Data = AllocatePool (Object->DataSize);
if (Object->Data == NULL) {
Status = EFI_OUT_OF_RESOURCES;
DEBUG ((DEBUG_ERROR, "%a: ERROR: allocate Object->Data for %a\n", __func__, IndexName));
goto Done;
}
FieldFlags = (UINT8)((UpdateRule << 5) | (LockRule << 4) | AccessType);
Object->Data[0] = FieldFlags;
Object->Completed = TRUE;
// TermList is too complicated and must be added outside
break;
case AmlClose:
// Required NameString completed in one phase call
// Close required PkgLength before finishing Object
Status = AmlPkgLength (AmlClose, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Close PkgLength for %a object\n", __func__, IndexName));
goto Done;
}
// Remove internal offset counter
Status = InternalAmlLocateOffsetTerm (&Object, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Locating internal offset term%a\n", __func__, IndexName));
goto Done;
}
Status = InternalFreeAmlObject (&Object, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: removing offset term%a\n", __func__, IndexName));
goto Done;
}
// remove original field identifier data
Status = InternalAmlLocateObjectByIdentifier (&Object, GENERIC_FIELD_IDENTIFIER, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Locate %a object\n", __func__, IndexName));
goto Done;
}
// Get rid of original Identifier data
InternalFreeAmlObjectData (Object);
// Collect child data and delete children
Status = InternalAmlCollapseAndReleaseChildren (
&ChildObject,
&ChildCount,
&Object->Link,
ListHead
);
if (EFI_ERROR (Status) ||
(ChildObject->Data == NULL) ||
(ChildObject->DataSize == 0))
{
DEBUG ((DEBUG_ERROR, "%a: ERROR: %a child data collection.\n", __func__, IndexName));
goto Done;
}
// Field Op is two bytes
Object->DataSize = ChildObject->DataSize + 2;
Object->Data = AllocatePool (Object->DataSize);
if (Object->Data == NULL) {
Status = EFI_OUT_OF_RESOURCES;
DEBUG ((DEBUG_ERROR, "%a: ERROR: allocate Object->Data for %a\n", __func__, IndexName));
goto Done;
}
Object->Data[0] = AML_EXT_OP;
Object->Data[1] = AML_EXT_INDEX_FIELD_OP;
CopyMem (
&Object->Data[2],
ChildObject->Data,
ChildObject->DataSize
);
InternalFreeAmlObject (&ChildObject, ListHead);
Object->Completed = TRUE;
Status = EFI_SUCCESS;
break;
default:
Status = EFI_DEVICE_ERROR;
break;
}
Done:
if (EFI_ERROR (Status)) {
InternalFreeAmlObject (&ChildObject, ListHead);
InternalFreeAmlObject (&Object, ListHead);
}
return Status;
}
/**
OperationRegion (RegionName, RegionSpace, Offset, Length)
DefOpRegion := OpRegionOp NameString RegionSpace RegionOffset RegionLen
OpRegionOp := ExtOpPrefix 0x80
RegionSpace :=
ByteData // 0x00 SystemMemory
// 0x01 SystemIO
// 0x02 PCI_Config
// 0x03 EmbeddedControl
// 0x04 SMBus
// 0x05 System CMOS
// 0x06 PciBarTarget
// 0x07 IPMI
// 0x08 GeneralPurposeIO
// 0x09 GenericSerialBus
// 0x0A PCC
// 0x80-0xFF: OEM Defined
RegionOffset := TermArg => Integer
RegionLen := TermArg => Integer
@param[in] RegionName - Name for the Operation Region
@param[in] RegionSpace - Region Space type
@param[in] Offset - Offset within the selected RegionSpace at which the
region starts (byte-granular)
@param[in] Length - Length of the region in bytes.
@param[in,out] ListHead - Linked list head
@retval EFI_SUCCESS
@retval Error status
**/
EFI_STATUS
EFIAPI
AmlOPOperationRegion (
IN CHAR8 *RegionName,
IN GENERIC_ADDRESS_SPACE_ID RegionSpace,
IN UINT64 Offset,
IN UINT64 Length,
IN OUT LIST_ENTRY *ListHead
)
{
AML_OBJECT_INSTANCE *Object;
AML_OBJECT_INSTANCE *ChildObject;
UINTN ChildCount;
EFI_STATUS Status;
// Input parameter validation
if ((RegionName == NULL) || (AsciiStrLen (RegionName) == 0) || (ListHead == NULL) ||
((RegionSpace > PCC) && (RegionSpace < 0x80)) || (RegionSpace > 0xFF))
{
return EFI_INVALID_PARAMETER;
}
Object = NULL;
ChildObject = NULL;
Status = EFI_DEVICE_ERROR;
Status = InternalAppendNewAmlObject (&Object, "OPREGION", ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Start OpRegion for %a object\n", __func__, RegionName));
goto Done;
}
Status = AmlOPNameString (RegionName, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Name String for %a object\n", __func__, RegionName));
goto Done;
}
Status = AmlOPByteData ((UINT8)RegionSpace, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Region space byte data for %a object\n", __func__, RegionName));
goto Done;
}
Status = AmlOPDataInteger (Offset, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Offset data integer for %a object\n", __func__, RegionName));
goto Done;
}
Status = AmlOPDataInteger (Length, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Length data integer for %a object\n", __func__, RegionName));
goto Done;
}
Status = InternalAmlLocateObjectByIdentifier (&Object, "OPREGION", ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Locate %a object\n", __func__, RegionName));
goto Done;
}
// Get rid of original Identifier data
InternalFreeAmlObjectData (Object);
// Collect child data and delete children
Status = InternalAmlCollapseAndReleaseChildren (
&ChildObject,
&ChildCount,
&Object->Link,
ListHead
);
if (EFI_ERROR (Status) ||
(ChildObject->Data == NULL) ||
(ChildObject->DataSize == 0))
{
DEBUG ((DEBUG_ERROR, "%a: ERROR: %a child data collection.\n", __func__, RegionName));
goto Done;
}
// OpRegion Opcode is two bytes
Object->DataSize = ChildObject->DataSize + 2;
Object->Data = AllocatePool (Object->DataSize);
if (Object->Data == NULL) {
Status = EFI_OUT_OF_RESOURCES;
DEBUG ((DEBUG_ERROR, "%a: ERROR: allocate Object->Data for %a\n", __func__, RegionName));
goto Done;
}
Object->Data[0] = AML_EXT_OP;
Object->Data[1] = AML_EXT_REGION_OP;
CopyMem (
&Object->Data[2],
ChildObject->Data,
ChildObject->DataSize
);
InternalFreeAmlObject (&ChildObject, ListHead);
Object->Completed = TRUE;
Status = EFI_SUCCESS;
Done:
if (EFI_ERROR (Status)) {
InternalFreeAmlObject (&Object, ListHead);
InternalFreeAmlObject (&ChildObject, ListHead);
}
return Status;
}
/**
Creates a CreateField AML Object and inserts it into the linked list
Syntax:
CreateField ( SourceBuffer, BitIndex, NumBits, FieldName )
DefCreateField := CreateFieldOp SourceBuff BitIndex NumBits NameString
CreateFieldOp := ExtOpPrefix 0x13
ExtOpPrefix := 0x5B
SourceBuff := TermArg => Buffer
BitIndex := TermArg => Integer
NumBits := TermArg -> Integer
@param[in] SourceBuffer, - Buffer to house the new buffer field object
@param[in] BitIndex, - Starting bit index place the new buffer
@param[in] NumBits, - Number of bits to reserve
@param[in] FieldName, - The new buffer field object to be created in SourceBuffer
@param[in,out] ListHead - Linked list has completed CreateField object
@retval EFI_SUCCESS
@retval Error status
**/
EFI_STATUS
EFIAPI
AmlOPCreateField (
IN CHAR8 *SourceBuffer,
IN UINT64 BitIndex,
IN UINT64 NumBits,
IN CHAR8 *FieldName,
IN OUT LIST_ENTRY *ListHead
)
{
EFI_STATUS Status;
AML_OBJECT_INSTANCE *Object;
AML_OBJECT_INSTANCE *ChildObject;
UINTN ChildCount;
ChildObject = NULL;
Object = NULL;
if ((SourceBuffer == NULL) || (FieldName == NULL) || (ListHead == NULL) ||
(AsciiStrLen (SourceBuffer) == 0) || (AsciiStrLen (FieldName) == 0))
{
return EFI_INVALID_PARAMETER;
}
ChildObject = NULL;
Status = InternalAppendNewAmlObject (&Object, "CreateField", ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: CreateField for %a object\n", __func__, FieldName));
goto Done;
}
Status = AmlOPNameString (SourceBuffer, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: NameString for %a object\n", __func__, FieldName));
goto Done;
}
Status = AmlOPDataInteger (BitIndex, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: BitIndex for %a object\n", __func__, FieldName));
goto Done;
}
Status = AmlOPDataInteger (NumBits, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: NumBits for %a object\n", __func__, FieldName));
goto Done;
}
Status = AmlOPNameString (FieldName, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: FieldName for %a object\n", __func__, FieldName));
goto Done;
}
Status = InternalAmlLocateObjectByIdentifier (&Object, "CreateField", ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Locate %a object\n", __func__, FieldName));
goto Done;
}
// Get rid of original Identifier data
InternalFreeAmlObjectData (Object);
// Collect child data and delete children
Status = InternalAmlCollapseAndReleaseChildren (
&ChildObject,
&ChildCount,
&Object->Link,
ListHead
);
if (EFI_ERROR (Status) ||
(ChildObject->Data == NULL) ||
(ChildObject->DataSize == 0))
{
DEBUG ((DEBUG_ERROR, "%a: ERROR: %a child data collection.\n", __func__, FieldName));
goto Done;
}
// CreateFieldOp is two bytes
Object->DataSize = ChildObject->DataSize + 2;
Object->Data = AllocatePool (Object->DataSize);
if (Object->Data == NULL) {
Status = EFI_OUT_OF_RESOURCES;
DEBUG ((DEBUG_ERROR, "%a: ERROR: allocate Object->Data for %a\n", __func__, FieldName));
goto Done;
}
Object->Data[0] = AML_EXT_OP;
Object->Data[1] = AML_EXT_CREATE_FIELD_OP;
CopyMem (
&Object->Data[2],
ChildObject->Data,
ChildObject->DataSize
);
InternalFreeAmlObject (&ChildObject, ListHead);
Object->Completed = TRUE;
Status = EFI_SUCCESS;
Done:
if (EFI_ERROR (Status)) {
InternalFreeAmlObject (&ChildObject, ListHead);
InternalFreeAmlObject (&Object, ListHead);
}
return Status;
}
/**
Internal function used to create a CreateBit|Byte|Word|DWord|QWordField objects
and insert them into the linked list
@param[in] SourceBuffer, - Buffer to insert the new buffer fixed field object
@param[in] Index, - Starting index to place the new buffer
@param[in] FixedFieldName, - Name of the FixedField
@param[in] OpCode, - AML opcode for the Create_Field encoding
@param[in,out] ListHead - Linked list has completed CreateFixedField object
@retval EFI_SUCCESS
@retval Error status
**/
EFI_STATUS
EFIAPI
InternalAmlCreateFixedField (
IN CHAR8 *SourceBuffer,
IN UINT64 Index,
IN CHAR8 *FixedFieldName,
IN UINT8 OpCode,
IN OUT LIST_ENTRY *ListHead
)
{
EFI_STATUS Status;
AML_OBJECT_INSTANCE *Object;
AML_OBJECT_INSTANCE *ChildObject;
UINTN ChildCount;
ChildObject = NULL;
if ((SourceBuffer == NULL) || (FixedFieldName == NULL) || (ListHead == NULL) ||
(AsciiStrLen (SourceBuffer) == 0) || (AsciiStrLen (FixedFieldName) == 0))
{
return EFI_INVALID_PARAMETER;
}
Status = InternalAppendNewAmlObject (&Object, "CreateFixedField", ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: CreateField for %a object\n", __func__, FixedFieldName));
goto Done;
}
// Check if Localx Buffer
if (AsciiStrnCmp (SourceBuffer, "Local", 5) == 0) {
if ((SourceBuffer[5] >= '0') && (SourceBuffer[5] <= '9')) {
Status = AmlOPLocalN ((UINT8)AsciiStrDecimalToUintn (&SourceBuffer[5]), ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: LocalN for %a object\n", __func__, FixedFieldName));
goto Done;
}
}
// Check if Argx Buffer
} else if (AsciiStrnCmp (SourceBuffer, "Arg", 3) == 0) {
if ((SourceBuffer[3] >= '0') && (SourceBuffer[3] <= '9')) {
Status = AmlOpArgN ((UINT8)AsciiStrDecimalToUintn (&SourceBuffer[3]), ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: ArgN for %a object\n", __func__, FixedFieldName));
goto Done;
}
}
} else {
Status = AmlOPNameString (SourceBuffer, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: NameString for %a object\n", __func__, FixedFieldName));
goto Done;
}
}
Status = AmlOPDataInteger (Index, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Index for %a object\n", __func__, FixedFieldName));
goto Done;
}
Status = AmlOPNameString (FixedFieldName, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: FieldName for %a object\n", __func__, FixedFieldName));
goto Done;
}
Status = InternalAmlLocateObjectByIdentifier (&Object, "CreateFixedField", ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Locate %a object\n", __func__, FixedFieldName));
goto Done;
}
// Get rid of original Identifier data
InternalFreeAmlObjectData (Object);
// Collect child data and delete children
Status = InternalAmlCollapseAndReleaseChildren (
&ChildObject,
&ChildCount,
&Object->Link,
ListHead
);
if (EFI_ERROR (Status) ||
(ChildObject->Data == NULL) ||
(ChildObject->DataSize == 0))
{
DEBUG ((DEBUG_ERROR, "%a: ERROR: %a child data collection.\n", __func__, FixedFieldName));
goto Done;
}
// CreateWordFieldOp is one byte
Object->DataSize = ChildObject->DataSize + 1;
Object->Data = AllocatePool (Object->DataSize);
if (Object->Data == NULL) {
Status = EFI_OUT_OF_RESOURCES;
DEBUG ((DEBUG_ERROR, "%a: ERROR: allocate Object->Data for %a\n", __func__, FixedFieldName));
goto Done;
}
Object->Data[0] = OpCode;
CopyMem (
&Object->Data[1],
ChildObject->Data,
ChildObject->DataSize
);
InternalFreeAmlObject (&ChildObject, ListHead);
Object->Completed = TRUE;
Status = EFI_SUCCESS;
Done:
if (EFI_ERROR (Status)) {
InternalFreeAmlObject (&ChildObject, ListHead);
InternalFreeAmlObject (&Object, ListHead);
}
return Status;
}
/**
Creates a CreateBitField AML Object and inserts it into the linked list
Syntax:
CreateBitField (SourceBuffer, BitIndex, BitFieldName)
DefCreateBitField := CreateBitFieldOp SourceBuff BitIndex NameString
CreateBitFieldOp := 0x8D
SourceBuff := TermArg => Buffer
BitIndex := TermArg => Integer
@param[in] SourceBuffer, - Buffer to insert the new buffer bit field object
@param[in] BitIndex, - Starting bit index to place the new buffer
@param[in] BitFieldName, - Name of the BitField
@param[in,out] ListHead - Linked list has completed CreateBitField object
@retval EFI_SUCCESS
@retval Error status
**/
EFI_STATUS
EFIAPI
AmlOPCreateBitField (
IN CHAR8 *SourceBuffer,
IN UINT64 BitIndex,
IN CHAR8 *BitFieldName,
IN OUT LIST_ENTRY *ListHead
)
{
EFI_STATUS Status;
Status = InternalAmlCreateFixedField (SourceBuffer, BitIndex, BitFieldName, AML_CREATE_BIT_FIELD_OP, ListHead);
return Status;
}
/**
Creates a CreateByteField AML Object and inserts it into the linked list
Syntax:
CreateByteField ( SourceBuffer, ByteIndex, ByteFieldName )
DefCreateByteField := CreateByteFieldOp SourceBuff ByteIndex NameString
CreateByteFieldOp := 0x8C
SourceBuff := TermArg => Buffer
ByteIndex := TermArg => Integer
@param[in] SourceBuffer, - Buffer to insert the new buffer byte field object
@param[in] ByteIndex, - Starting byte index to place the new buffer
@param[in] ByteFieldName, - Name of the ByteField
@param[in,out] ListHead - Linked list has completed CreateByteField object
@retval EFI_SUCCESS
@retval Error status
**/
EFI_STATUS
EFIAPI
AmlOPCreateByteField (
IN CHAR8 *SourceBuffer,
IN UINT64 ByteIndex,
IN CHAR8 *ByteFieldName,
IN OUT LIST_ENTRY *ListHead
)
{
EFI_STATUS Status;
Status = InternalAmlCreateFixedField (SourceBuffer, ByteIndex, ByteFieldName, AML_CREATE_BYTE_FIELD_OP, ListHead);
return Status;
}
/**
Creates a CreateDWordField AML Object and inserts it into the linked list
Syntax:
CreateDWordField ( SourceBuffer, ByteIndex, DWordFieldName )
DefCreateDWordField := CreateDWordFieldOp SourceBuff ByteIndex NameString
CreateDWordFieldOp := 0x8A
SourceBuff := TermArg => Buffer
ByteIndex := TermArg => Integer
@param[in] SourceBuffer, - Buffer to insert the new buffer DWord field object
@param[in] ByteIndex, - Starting byte index to place the new buffer
@param[in] DWordFieldName, - Name of the DWordField
@param[in,out] ListHead - Linked list has completed CreateDWordField object
@retval EFI_SUCCESS
@retval Error status
**/
EFI_STATUS
EFIAPI
AmlOPCreateDWordField (
IN CHAR8 *SourceBuffer,
IN UINT64 ByteIndex,
IN CHAR8 *DWordFieldName,
IN OUT LIST_ENTRY *ListHead
)
{
EFI_STATUS Status;
Status = InternalAmlCreateFixedField (SourceBuffer, ByteIndex, DWordFieldName, AML_CREATE_DWORD_FIELD_OP, ListHead);
return Status;
}
/**
Creates a CreateQWordField AML Object and inserts it into the linked list
Syntax:
CreateQWordField ( SourceBuffer, ByteIndex, QWordFieldName )
DefCreateQWordField := CreateQWordFieldOp SourceBuff ByteIndex NameString
CreateQWordFieldOp := 0x8F
SourceBuff := TermArg => Buffer
ByteIndex := TermArg => Integer
@param[in] SourceBuffer, - Buffer to insert the new buffer QWord field object
@param[in] ByteIndex, - Starting byte index to place the new buffer
@param[in] QWordFieldName, - Name of the QWordField
@param[in,out] ListHead - Linked list has completed CreateQWordField object
@retval EFI_SUCCESS
@retval Error status
**/
EFI_STATUS
EFIAPI
AmlOPCreateQWordField (
IN CHAR8 *SourceBuffer,
IN UINT64 ByteIndex,
IN CHAR8 *QWordFieldName,
IN OUT LIST_ENTRY *ListHead
)
{
EFI_STATUS Status;
Status = InternalAmlCreateFixedField (SourceBuffer, ByteIndex, QWordFieldName, AML_CREATE_QWORD_FIELD_OP, ListHead);
return Status;
}
/**
Creates a CreateWordField AML Object and inserts it into the linked list
Syntax:
CreateWordField ( SourceBuffer, ByteIndex, WordFieldName )
DefCreateWordField := CreateWordFieldOp SourceBuff ByteIndex NameString
CreateWordFieldOp := 0x8B
SourceBuff := TermArg => Buffer
ByteIndex := TermArg => Integer
@param[in] SourceBuffer, - Buffer to house the new buffer word field object
@param[in] ByteIndex, - Starting byte index to place the new buffer
@param[in] WordFieldName, - Name of the WordField
@param[in,out] ListHead - Linked list has completed CreateWordField object
@retval EFI_SUCCESS
@retval Error status
**/
EFI_STATUS
EFIAPI
AmlOPCreateWordField (
IN CHAR8 *SourceBuffer,
IN UINT64 ByteIndex,
IN CHAR8 *WordFieldName,
IN OUT LIST_ENTRY *ListHead
)
{
EFI_STATUS Status;
Status = InternalAmlCreateFixedField (SourceBuffer, ByteIndex, WordFieldName, AML_CREATE_WORD_FIELD_OP, ListHead);
return Status;
}
/**
Creates a Method
Method (MethodName, NumArgs, SerializeRule, SyncLevel, ReturnType,
ParameterTypes) {TermList}
TermList must be created between AmlStart and AmlClose Phase
Note: ReturnType and ParameterTypes are not used for AML encoding
and are therefore not passed in to this function.
DefMethod := MethodOp PkgLength NameString MethodFlags TermList
MethodOp := 0x14
MethodFlags := ByteData // bit 0-2: ArgCount (0-7)
// bit 3: SerializeFlag
// 0 NotSerialized
// 1 Serialized
// bit 4-7: SyncLevel (0x00-0x0f)
@param[in] Phase - Either AmlStart or AmlClose
@param[in] Name - Method name
@param[in] NumArgs - Number of arguments passed in to method
@param[in] SerializeRule - Flag indicating whether method is serialized
or not
@param[in] SyncLevel - synchronization level for the method (0 - 15),
use zero for default sync level.
@param[in,out] ListHead - Linked list has completed String Object after
AmlClose.
@retval EFI_SUCCESS
@retval Error status
**/
EFI_STATUS
EFIAPI
AmlMethod (
IN AML_FUNCTION_PHASE Phase,
IN CHAR8 *Name,
IN UINT8 NumArgs,
IN METHOD_SERIALIZE_FLAG SerializeRule,
IN UINT8 SyncLevel,
IN OUT LIST_ENTRY *ListHead
)
{
EFI_STATUS Status;
AML_OBJECT_INSTANCE *Object;
AML_OBJECT_INSTANCE *ChildObject;
UINT8 MethodFlags;
UINTN ChildCount;
if ((Phase >= AmlInvalid) ||
(Name == NULL) ||
(NumArgs > METHOD_ARGS_MAX) ||
(SyncLevel > MAX_SYNC_LEVEL) ||
(SerializeRule >= FlagInvalid) ||
(ListHead == NULL))
{
return EFI_INVALID_PARAMETER;
}
Status = EFI_DEVICE_ERROR;
Object = NULL;
ChildObject = NULL;
switch (Phase) {
case AmlStart:
Status = InternalAppendNewAmlObject (&Object, "Method", ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Start Method for %a object\n", __func__, Name));
goto Done;
}
// Start required PkgLength
Status = AmlPkgLength (AmlStart, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Start PkgLength for %a object\n", __func__, Name));
goto Done;
}
// Insert required NameString
Status = AmlOPNameString (Name, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Start NameString for %a object\n", __func__, Name));
goto Done;
}
// Add Method Flags
Status = InternalAppendNewAmlObject (&Object, "METHOD_FLAGS", ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Start METHOD_FLAGS for %a object\n", __func__, Name));
goto Done;
}
// TermList is too complicated and must be added outside
break;
case AmlClose:
// TermList should be closed already
// Add Method Flags
Status = InternalAmlLocateObjectByIdentifier (&Object, "METHOD_FLAGS", ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: locate METHOD_FLAGS for %a object\n", __func__, Name));
goto Done;
}
// Get rid of original Identifier data
InternalFreeAmlObjectData (Object);
// Collect child data and delete children
Status = InternalAmlCollapseAndReleaseChildren (
&ChildObject,
&ChildCount,
&Object->Link,
ListHead
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: %a METHOD_FLAGS child data collection.\n", __func__, Name));
goto Done;
}
// Method Flags is one byte
Object->DataSize = ChildObject->DataSize + 1;
Object->Data = AllocatePool (Object->DataSize);
if (Object->Data == NULL) {
Status = EFI_OUT_OF_RESOURCES;
DEBUG ((DEBUG_ERROR, "%a: ERROR: allocate Object->Data for %a\n", __func__, Name));
goto Done;
}
MethodFlags = NumArgs & 0x07;
if (SerializeRule) {
MethodFlags |= BIT3;
}
MethodFlags |= (SyncLevel & 0x0F) << 4;
Object->Data[0] = MethodFlags;
CopyMem (
&Object->Data[1],
ChildObject->Data,
ChildObject->DataSize
);
InternalFreeAmlObject (&ChildObject, ListHead);
Object->Completed = TRUE;
// Required NameString completed in one phase call
// Close required PkgLength before finishing Object
Status = AmlPkgLength (AmlClose, ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Close PkgLength for %a object\n", __func__, Name));
goto Done;
}
Status = InternalAmlLocateObjectByIdentifier (&Object, "Method", ListHead);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Locate %a object\n", __func__, Name));
goto Done;
}
// Get rid of original Identifier data
InternalFreeAmlObjectData (Object);
// Collect child data and delete children
Status = InternalAmlCollapseAndReleaseChildren (
&ChildObject,
&ChildCount,
&Object->Link,
ListHead
);
if (EFI_ERROR (Status) ||
(ChildObject->Data == NULL) ||
(ChildObject->DataSize == 0))
{
DEBUG ((DEBUG_ERROR, "%a: ERROR: %a child data collection.\n", __func__, Name));
goto Done;
}
// Method Op is one byte
Object->DataSize = ChildObject->DataSize + 1;
Object->Data = AllocatePool (Object->DataSize);
if (Object->Data == NULL) {
Status = EFI_OUT_OF_RESOURCES;
DEBUG ((DEBUG_ERROR, "%a: ERROR: allocate Object->Data for %a\n", __func__, Name));
goto Done;
}
Object->Data[0] = AML_METHOD_OP;
CopyMem (
&Object->Data[1],
ChildObject->Data,
ChildObject->DataSize
);
InternalFreeAmlObject (&ChildObject, ListHead);
Object->Completed = TRUE;
Status = EFI_SUCCESS;
break;
default:
Status = EFI_DEVICE_ERROR;
break;
}
Done:
if (EFI_ERROR (Status)) {
InternalFreeAmlObject (&ChildObject, ListHead);
InternalFreeAmlObject (&Object, ListHead);
}
return Status;
}