/** @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_AMLASSISTFUNCTIONS_FILECODE
/**
Free all the children AML_OBJECT_INSTANCE(s) of ListHead.
Will not free ListHead nor an Object containing ListHead.
@param[in,out] ListHead - Head of linked list of Objects
@retval EFI_SUCCESS
**/
EFI_STATUS
EFIAPI
AmlFreeObjectList (
IN OUT LIST_ENTRY *ListHead
)
{
LIST_ENTRY *Node;
AML_OBJECT_INSTANCE *Object;
Node = GetNextNode (ListHead, ListHead);
while (Node != ListHead) {
Object = AML_OBJECT_INSTANCE_FROM_LINK (Node);
// Get next node before freeing current Object
Node = GetNextNode (ListHead, Node);
// Free Object
InternalFreeAmlObject (&Object, ListHead);
}
return EFI_SUCCESS;
}
/**
Validate that ACPI table is completed and return Table and Size
@param[in,out] ListHead - Head of linked list of Objects
@param[out] Table - Completed ACPI Table
@param[out] TableSize - Completed ACPI Table size
@retval EFI_SUCCESS
EFI_INVALID_PARAMETER
EFI_DEVICE_ERROR
**/
EFI_STATUS
EFIAPI
AmlGetCompletedTable (
IN OUT LIST_ENTRY *ListHead,
OUT VOID **Table,
OUT UINTN *TableSize
)
{
LIST_ENTRY *Node;
AML_OBJECT_INSTANCE *Object;
if (ListHead == NULL) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: ListHead cannot be NULL\n", __func__));
return EFI_INVALID_PARAMETER;
}
*Table = NULL;
*TableSize = 0;
Node = GetFirstNode (ListHead);
if (!IsNodeAtEnd (ListHead, Node)) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Multiple nodes remain, Likely missed an 'AmlClose' call\n", __func__));
return EFI_DEVICE_ERROR;
} else {
Object = AML_OBJECT_INSTANCE_FROM_LINK (Node);
if (!Object->Completed) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Final node not completed: Likely missed an 'AmlCLose' call\n", __func__));
return EFI_DEVICE_ERROR;
}
*Table = Object->Data;
*TableSize = Object->DataSize;
}
return EFI_SUCCESS;
}
/**
Initialize Table List to work with AmlGenerationLib
Allocates a LIST_ENTRY linked list item and initializes it. Use
AmlReleaseTableList to free resulting table and LIST_ENTRY.
@param[in,out] ListHead - Head of linked list of Objects
@retval EFI_SUCCESS
EFI_INVALID_PARAMETER
EFI_OUT_OF_RESOURCES
**/
EFI_STATUS
EFIAPI
AmlInitializeTableList (
IN OUT LIST_ENTRY **ListHead
)
{
if (ListHead == NULL) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: ListHead = NULL\n", __func__));
return EFI_INVALID_PARAMETER;
}
*ListHead = AllocatePool (sizeof (LIST_ENTRY));
if (*ListHead == NULL) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: Unable to allocate Table List Head\n", __func__));
return EFI_OUT_OF_RESOURCES;
}
InitializeListHead (*ListHead);
return EFI_SUCCESS;
}
/**
Release table List
Releases all elements. Use to free built table and LIST_ENTRY allocated by
AmlInitializeTableList.
@param[in,out] ListHead - Head of linked list of Objects
@retval EFI_SUCCESS
EFI_INVALID_PARAMETER
**/
EFI_STATUS
EFIAPI
AmlReleaseTableList (
IN OUT LIST_ENTRY **ListHead
)
{
if (*ListHead == NULL) {
DEBUG ((DEBUG_ERROR, "%a: ERROR: NULL ListHead passed in\n", __func__));
return EFI_INVALID_PARAMETER;
}
AmlFreeObjectList (*ListHead);
FreePool (*ListHead);
*ListHead = NULL;
return EFI_SUCCESS;
}