/** @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_LOCALAMLOBJECTS_FILECODE /** Free Object->Data Frees Object->Data, Nulls pointer, zeros size and marks Object->Completed = FALSE @param [in] Object - Pointer to Object to have Data freed @return EFI_SUCCESS - Object Freed @return - Object free failed **/ EFI_STATUS EFIAPI InternalFreeAmlObjectData ( IN AML_OBJECT_INSTANCE *Object ) { if (Object == NULL) { return EFI_INVALID_PARAMETER; } if (Object->Data != NULL) { FreePool (Object->Data); Object->Data = NULL; Object->DataSize = 0; Object->Completed = FALSE; } return EFI_SUCCESS; } /** Free an Object Removes Object from it's linked list. Frees Object->Data Frees Object @param [in] Object - Pointer to Object to be freed @param [in,out] ListHead - Head of AML Object linked list @return EFI_SUCCESS - Object Freed @return - Object free failed **/ EFI_STATUS EFIAPI InternalFreeAmlObject ( IN AML_OBJECT_INSTANCE **FreeObject, IN OUT LIST_ENTRY *ListHead ) { AML_OBJECT_INSTANCE *Object; if ((FreeObject == NULL) || (ListHead == NULL)) { return EFI_INVALID_PARAMETER; } Object = *FreeObject; if (Object != NULL) { InternalFreeAmlObjectData (Object); if (IsNodeInList (ListHead, &Object->Link)) { RemoveEntryList (&Object->Link); } FreePool (Object); } *FreeObject = NULL; return EFI_SUCCESS; } /** Creates a new AML_OBJECT_INSTANCE. Object->Data will be NULL and Object->DataSize will be 0 Allocates AML_OBJECT_INSTANCE which must be freed by caller @param [out] ReturnObject - Pointer to an Object @return EFI_SUCCESS - Object created and appended to linked list @return - Object creation failed, Object = NULL **/ EFI_STATUS EFIAPI InternalNewAmlObjectNoData ( OUT AML_OBJECT_INSTANCE **ReturnObject ) { AML_OBJECT_INSTANCE *Object; if (ReturnObject == NULL) { return EFI_INVALID_PARAMETER; } *ReturnObject = NULL; // Allocate AML Object Object = AllocateZeroPool (sizeof (AML_OBJECT_INSTANCE)); if (Object == NULL) { DEBUG ((DEBUG_ERROR, "%a: ERROR: Allocate Object Failed\n", __func__)); return EFI_OUT_OF_RESOURCES; } Object->DataSize = 0; Object->Data = NULL; Object->Signature = AML_OBJECT_INSTANCE_SIGNATURE; *ReturnObject = Object; return EFI_SUCCESS; } /** Inserts a new AML_OBJECT_INSTANCE at the end of the linked list. Object->Data will be NULL and Object->DataSize will be 0 Allocates AML_OBJECT_INSTANCE which must be freed by caller @param [out] ReturnObject - Pointer to an Object @param [in,out] ListHead - Head of AML Object linked list @return EFI_SUCCESS - Object created and appended to linked list @return - Object creation failed, Object = NULL **/ EFI_STATUS EFIAPI InternalAppendNewAmlObjectNoData ( OUT AML_OBJECT_INSTANCE **ReturnObject, IN OUT LIST_ENTRY *ListHead ) { EFI_STATUS Status; AML_OBJECT_INSTANCE *Object; if ((ListHead == NULL) || (ReturnObject == NULL)) { return EFI_INVALID_PARAMETER; } Status = InternalNewAmlObjectNoData (&Object); if (!EFI_ERROR (Status)) { InsertTailList (ListHead, &Object->Link); *ReturnObject = Object; } return Status; } /** Inserts a new AML_OBJECT_INSTANCE at the end of the linked list. Using a string Identifier for comparison purposes Allocates AML_OBJECT_INSTANCE which must be freed by caller @param [out] ReturnObject - Pointer to an Object @param [in] Identifier - String Identifier to create object with @param [in,out] ListHead - Head of AML Object linked list @return EFI_SUCCESS - Object created and appended to linked list @return - Object creation failed, Object = NULL **/ EFI_STATUS EFIAPI InternalAppendNewAmlObject ( OUT AML_OBJECT_INSTANCE **ReturnObject, IN CHAR8 *Identifier, IN OUT LIST_ENTRY *ListHead ) { EFI_STATUS Status; AML_OBJECT_INSTANCE *Object; if ((Identifier == NULL) || (ListHead == NULL)) { return EFI_INVALID_PARAMETER; } Object = NULL; Status = InternalAppendNewAmlObjectNoData (&Object, ListHead); if (EFI_ERROR (Status)) { return EFI_OUT_OF_RESOURCES; } // Allocate Identifier Data + NULL termination Object->DataSize = AsciiStrLen (Identifier) + 1; Object->Data = AllocatePool (Object->DataSize); if (Object->Data == NULL) { DEBUG ((DEBUG_ERROR, "%a: ERROR: Allocate Data Identifier=%a\n", __func__, Identifier)); InternalFreeAmlObject (&Object, ListHead); return EFI_OUT_OF_RESOURCES; } CopyMem (Object->Data, Identifier, Object->DataSize); *ReturnObject = Object; return EFI_SUCCESS; } /** Finds AML_OBJECT_INSTANCE given a string Identifier looking backwards in the AML_OBJECT_INSTANCE linked list @param [out] ReturnObject - Pointer to an Object @param [in] Identifier - String Identifier to create object with @param [in] ListHead - Head of AML Object linked list @return EFI_SUCCESS - Object located and returned @return - Object creation failed, Object = NULL **/ EFI_STATUS EFIAPI InternalAmlLocateObjectByIdentifier ( OUT AML_OBJECT_INSTANCE **ReturnObject, IN CHAR8 *Identifier, IN LIST_ENTRY *ListHead ) { LIST_ENTRY *Node; AML_OBJECT_INSTANCE *Object; UINTN IdentifierSize; if ((Identifier == NULL) || (ListHead == NULL)) { return EFI_INVALID_PARAMETER; } Object = NULL; *ReturnObject = NULL; 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->Completed) { // Object to be found cannot be completed yet continue; } else { if ((Object->DataSize != 0) && (Object->DataSize == IdentifierSize) && (CompareMem ( Object->Data, Identifier, MAX (Object->DataSize, IdentifierSize) ) == 0)) { *ReturnObject = Object; return EFI_SUCCESS; } else { DEBUG (( DEBUG_ERROR, "%a: ERROR: First incomplete Object is not %a.\n", __func__, Identifier )); // Object looking for should be the first uncompleted Object. return EFI_NOT_FOUND; } } } while (Node != ListHead); *ReturnObject = NULL; return EFI_NOT_FOUND; } /** Finds all children of the Link and appends them into a single ObjectData buffer of ObjectDataSize Allocates AML_OBJECT_INSTANCE and Data which must be freed by caller @param [out] ReturnObject - Pointer to an Object pointer @param [out] ChildCount - Count of Child Objects collapsed @param [in] Link - Linked List Object entry to collect children @param [in,out] ListHead - Head of Object Linked List @return EFI_SUCCESS - ChildObject created and returned @return - Object creation failed, Object = NULL **/ EFI_STATUS EFIAPI InternalAmlCollapseAndReleaseChildren ( OUT AML_OBJECT_INSTANCE **ReturnObject, OUT UINTN *ChildCount, IN LIST_ENTRY *Link, IN OUT LIST_ENTRY *ListHead ) { EFI_STATUS Status; LIST_ENTRY *Node; AML_OBJECT_INSTANCE *Object; AML_OBJECT_INSTANCE *ChildObject; UINT8 *TempBuffer; Status = EFI_SUCCESS; if ((ReturnObject == NULL) || (ChildCount == NULL) || (Link == NULL) || (ListHead == NULL)) { return EFI_INVALID_PARAMETER; } *ChildCount = 0; Status = InternalNewAmlObjectNoData (&Object); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a: ERROR: allocating Object Data\n", __func__)); goto Done; } // Get first Child Node Node = GetNextNode (ListHead, Link); while (Node != ListHead) { ChildObject = AML_OBJECT_INSTANCE_FROM_LINK (Node); // Expand data buffer to fit existing data + new data TempBuffer = ReallocatePool ( Object->DataSize, Object->DataSize + ChildObject->DataSize, Object->Data ); if (TempBuffer == NULL) { Status = EFI_OUT_OF_RESOURCES; FreePool (Object->Data); Object->Data = NULL; DEBUG ((DEBUG_ERROR, "%a: ERROR: reallocating Object Data\n", __func__)); goto Done; } Object->Data = TempBuffer; // Copy new data at end of buffer CopyMem ( &Object->Data[Object->DataSize], ChildObject->Data, ChildObject->DataSize ); Object->DataSize += ChildObject->DataSize; // Get Next ChildObject Node, then free ChildObject from list Node = GetNextNode (ListHead, Node); InternalFreeAmlObject (&ChildObject, ListHead); *ChildCount = *ChildCount + 1; } Done: if (EFI_ERROR (Status)) { InternalFreeAmlObject (&Object, ListHead); Object = NULL; } *ReturnObject = Object; return Status; }