The DynamicTablesPkg allows to generate firmware tables based on information provided by a user or another source of information (a device tree for instance). Some information might be implicitly generated by generators. For instance, for ACPI tables, AML names or Uids are created by generators, but not provided by the user or another source of information. Some generators might need to cross-reference object/generated data that was previous generated for an object by another generator. For instance, there are three different generators creating serial ports in the AML namespace. These 3 generators must ensure not to use an Id which was not already created by another generator. Another example would be a generator needing to reference the AML path of a serial port. As the AML path is dynamically generated, this is currently not possible to do. Add a MetaDataObjLib library to keep track of the meta-data previously generated for an object. Signed-off-by: Pierre Gondois <pierre.gondois@arm.com>
424 lines
12 KiB
C
424 lines
12 KiB
C
/** @file
|
|
Metadata Object Library.
|
|
|
|
Copyright (c) 2025, Arm Limited. All rights reserved.
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
**/
|
|
|
|
#include <Base.h>
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <ConfigurationManagerObject.h>
|
|
|
|
#include "MetadataObj.h"
|
|
|
|
/** Array of METADATA_STATIC_INFO. */
|
|
STATIC METADATA_STATIC_INFO mMetadataStaticInfo[MetadataTypeMax] = {
|
|
// MetadataTypeUid
|
|
{
|
|
sizeof (METADATA_OBJ_UID),
|
|
},
|
|
// MetadataTypeProximityDomain
|
|
{
|
|
sizeof (METADATA_OBJ_PROXIMITY_DOMAIN),
|
|
},
|
|
};
|
|
|
|
/** Initialize the Metadata Root.
|
|
|
|
@param[out] Root If success, Root of the Metadata information.
|
|
|
|
@retval EFI_SUCCESS Success.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_OUT_OF_RESOURCES Out of resources.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
MetadataInitializeHandle (
|
|
OUT METADATA_ROOT_HANDLE *Root
|
|
)
|
|
{
|
|
METADATA_ROOT *OutRoot;
|
|
UINT32 Index;
|
|
|
|
if (Root == NULL) {
|
|
ASSERT (Root != NULL);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
OutRoot = AllocateZeroPool (sizeof (*OutRoot));
|
|
if (OutRoot == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
for (Index = 0; Index < MetadataTypeMax; Index++) {
|
|
InitializeListHead (&OutRoot->MetadataList[Index].List);
|
|
}
|
|
|
|
*Root = OutRoot;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** Free the Metadata Root.
|
|
|
|
@param[in] Root Root of the Metadata information to free.
|
|
|
|
@retval EFI_SUCCESS Success.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_OUT_OF_RESOURCES Out of resources.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
MetadataFreeHandle (
|
|
IN METADATA_ROOT_HANDLE Root
|
|
)
|
|
{
|
|
if (Root == NULL) {
|
|
ASSERT (Root != NULL);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
FreePool (Root);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** Allocate a METADATA_ENTRY.
|
|
|
|
@param[in] Type METADATA_TYPE of the entry to allocate.
|
|
@param[in] Token Token uniquely identifying an entry among other
|
|
objects with the input METADATA_TYPE.
|
|
@param[in] Metadata Metadata to associate to the (Type/Token) pair.
|
|
The data is copied.
|
|
@param[in] MetadataSize Size of the input Metadata.
|
|
@param[out] OutMdEntry If success, contains the created METADATA_ENTRY.
|
|
|
|
@retval EFI_SUCCESS Success.
|
|
@retval EFI_OUT_OF_RESOURCES Out of resources.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
AllocateMetadataEntry (
|
|
IN METADATA_TYPE Type,
|
|
IN CM_OBJECT_TOKEN Token,
|
|
IN VOID *Metadata,
|
|
IN UINT32 MetadataSize,
|
|
OUT METADATA_ENTRY **OutMdEntry
|
|
)
|
|
{
|
|
METADATA_ENTRY *Entry;
|
|
|
|
ASSERT (Type < MetadataTypeMax);
|
|
ASSERT (Token != CM_NULL_TOKEN);
|
|
ASSERT (Metadata != NULL);
|
|
ASSERT (MetadataSize == mMetadataStaticInfo[Type].ExpectedSize);
|
|
ASSERT (OutMdEntry != NULL);
|
|
|
|
Entry = AllocateZeroPool (sizeof (*Entry));
|
|
if (Entry == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
Entry->Type = Type;
|
|
Entry->Token = Token;
|
|
Entry->Metadata = AllocateCopyPool (MetadataSize, Metadata);
|
|
if (Entry->Metadata == NULL) {
|
|
FreePool (Entry);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
InitializeListHead (&Entry->List);
|
|
|
|
*OutMdEntry = Entry;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** Find a METADATA_ENTRY with a matching (Type/Token).
|
|
|
|
@param[in] Root Root of the Metadata information.
|
|
@param[in] Type METADATA_TYPE of the entry to allocate.
|
|
@param[in] Token Token uniquely identifying an entry among other
|
|
objects with the input METADATA_TYPE.
|
|
@param[out] OutMdEntry If success, contains the METADATA_ENTRY with
|
|
a matching (Type/Token).
|
|
|
|
@retval EFI_SUCCESS Success.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_NOT_FOUND Not found.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
MetadataFindEntry (
|
|
IN METADATA_ROOT *Root,
|
|
IN METADATA_TYPE Type,
|
|
IN CM_OBJECT_TOKEN Token,
|
|
OUT METADATA_ENTRY **OutMdEntry
|
|
)
|
|
{
|
|
LIST_ENTRY *ListHead;
|
|
LIST_ENTRY *Link;
|
|
METADATA_ENTRY *Entry;
|
|
|
|
if ((Type >= MetadataTypeMax) ||
|
|
(Token == CM_NULL_TOKEN) ||
|
|
(OutMdEntry == NULL))
|
|
{
|
|
ASSERT (Type < MetadataTypeMax);
|
|
ASSERT (Token != CM_NULL_TOKEN);
|
|
ASSERT (OutMdEntry != NULL);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
ListHead = &Root->MetadataList[Type].List;
|
|
Link = GetFirstNode (ListHead);
|
|
|
|
while (Link != ListHead) {
|
|
Entry = (METADATA_ENTRY *)Link;
|
|
|
|
if (Entry->Token == Token) {
|
|
break;
|
|
}
|
|
|
|
Link = GetNextNode (ListHead, Link);
|
|
}
|
|
|
|
// No matching token.
|
|
if (Link == ListHead) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
*OutMdEntry = Entry;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** Attach some Metadata to a (Type/Token) pair.
|
|
|
|
@param[in] Root Root of the Metadata information.
|
|
@param[in] Type METADATA_TYPE of the entry to allocate.
|
|
@param[in] Token Token uniquely identifying an entry among other
|
|
objects with the input METADATA_TYPE.
|
|
@param[in] Metadata Metadata to associate to the (Type/Token) pair.
|
|
The data is copied.
|
|
@param[in] MetadataSize Size of the input Metadata.
|
|
|
|
@retval EFI_SUCCESS Success.
|
|
@retval EFI_ALREADY_STARTED (Type/Token) pair is already present.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_NOT_FOUND Not found.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
MetadataAdd (
|
|
IN METADATA_ROOT_HANDLE Root,
|
|
IN METADATA_TYPE Type,
|
|
IN CM_OBJECT_TOKEN Token,
|
|
IN VOID *Metadata,
|
|
IN UINT32 MetadataSize
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
METADATA_ENTRY *Entry;
|
|
|
|
if ((Root == NULL) ||
|
|
(Type >= MetadataTypeMax) ||
|
|
(Token == CM_NULL_TOKEN) ||
|
|
(Metadata == NULL) ||
|
|
(MetadataSize != mMetadataStaticInfo[Type].ExpectedSize))
|
|
{
|
|
ASSERT (Root != NULL);
|
|
ASSERT (Type < MetadataTypeMax);
|
|
ASSERT (Token != CM_NULL_TOKEN);
|
|
ASSERT (Metadata != NULL);
|
|
ASSERT (MetadataSize == mMetadataStaticInfo[Type].ExpectedSize);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = MetadataFindEntry (Root, Type, Token, &Entry);
|
|
if (Status == EFI_SUCCESS) {
|
|
// The (Type/Token) pair already exists.
|
|
return EFI_ALREADY_STARTED;
|
|
} else if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
|
|
// Error other than not-found.
|
|
ASSERT_EFI_ERROR (Status);
|
|
return Status;
|
|
}
|
|
|
|
// If not-found, create an new entry.
|
|
Status = AllocateMetadataEntry (Type, Token, Metadata, MetadataSize, &Entry);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT_EFI_ERROR (Status);
|
|
return Status;
|
|
}
|
|
|
|
InsertTailList (&((METADATA_ROOT *)Root)->MetadataList[Type].List, &Entry->List);
|
|
return Status;
|
|
}
|
|
|
|
/** Remove a (Type/Token) pair and its associated Metadata.
|
|
|
|
@param[in] Root Root of the Metadata information.
|
|
@param[in] Type METADATA_TYPE of the entry to remove.
|
|
@param[in] Token Token uniquely identifying an entry among other
|
|
objects with the input METADATA_TYPE.
|
|
|
|
@retval EFI_SUCCESS Success.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_NOT_FOUND Not found.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
MetadataRemove (
|
|
IN METADATA_ROOT_HANDLE Root,
|
|
IN METADATA_TYPE Type,
|
|
IN CM_OBJECT_TOKEN Token
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
METADATA_ENTRY *Entry;
|
|
|
|
if ((Root == NULL) ||
|
|
(Type >= MetadataTypeMax) ||
|
|
(Token == CM_NULL_TOKEN))
|
|
{
|
|
ASSERT (Root != NULL);
|
|
ASSERT (Type < MetadataTypeMax);
|
|
ASSERT (Token != CM_NULL_TOKEN);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = MetadataFindEntry (Root, Type, Token, &Entry);
|
|
if (EFI_ERROR (Status)) {
|
|
ASSERT_EFI_ERROR (Status);
|
|
return Status;
|
|
}
|
|
|
|
RemoveEntryList (&Entry->List);
|
|
if (Entry->Metadata != NULL) {
|
|
FreePool (Entry->Metadata);
|
|
}
|
|
|
|
FreePool (Entry);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** Get the Metadata associated with an (Type/Token).
|
|
|
|
@param[in] Root Root of the Metadata information.
|
|
@param[in] Type METADATA_TYPE of the entry to get.
|
|
@param[in] Token Token uniquely identifying an entry among other
|
|
objects with the input METADATA_TYPE.
|
|
@param[out] Metadata If success, contains the Metadata associated to the
|
|
input (Type/Token).
|
|
@param[in] MetadataSize Size of the input Metadata.
|
|
|
|
@retval EFI_SUCCESS Success.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_NOT_FOUND Not found.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
MetadataGet (
|
|
IN METADATA_ROOT_HANDLE Root,
|
|
IN METADATA_TYPE Type,
|
|
IN CM_OBJECT_TOKEN Token,
|
|
OUT VOID *Metadata,
|
|
IN UINT32 MetadataSize
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
METADATA_ENTRY *Entry;
|
|
|
|
if ((Root == NULL) ||
|
|
(Type >= MetadataTypeMax) ||
|
|
(Token == CM_NULL_TOKEN) ||
|
|
(Metadata == NULL) ||
|
|
(MetadataSize != mMetadataStaticInfo[Type].ExpectedSize))
|
|
{
|
|
ASSERT (Root != NULL);
|
|
ASSERT (Type < MetadataTypeMax);
|
|
ASSERT (Token != CM_NULL_TOKEN);
|
|
ASSERT (Metadata != NULL);
|
|
ASSERT (MetadataSize != mMetadataStaticInfo[Type].ExpectedSize);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = MetadataFindEntry (Root, Type, Token, &Entry);
|
|
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
|
|
// Error other than not-found.
|
|
ASSERT_EFI_ERROR (Status);
|
|
return Status;
|
|
} else if (Status == EFI_NOT_FOUND) {
|
|
return Status;
|
|
}
|
|
|
|
CopyMem (Metadata, Entry->Metadata, MetadataSize);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** Iterate over the existing Metadata with the same Type.
|
|
|
|
@param[in] Root Root of the Metadata information.
|
|
@param[in] Type METADATA_TYPE to iterate over.
|
|
@param[in] PrevHandle MetadataIterate () returns the Metadata handle
|
|
following PrevHandle.
|
|
If PrevHandle==NULL, the first Handle of the type
|
|
is returned.
|
|
If PrevHandle is the last Handle of the type,
|
|
NULL is returned.
|
|
@param[out] Metadata Metadata of the current Handle.
|
|
@param[in] MetadataSize Size of the input Metadata.
|
|
|
|
@return METADATA_HANDLE The Metadata handle following PrevHandle.
|
|
**/
|
|
METADATA_HANDLE
|
|
EFIAPI
|
|
MetadataIterate (
|
|
IN METADATA_ROOT_HANDLE Root,
|
|
IN METADATA_TYPE Type,
|
|
IN METADATA_HANDLE PrevHandle,
|
|
OUT VOID *Metadata,
|
|
IN UINT32 MetadataSize
|
|
)
|
|
{
|
|
METADATA_ENTRY *Entry;
|
|
LIST_ENTRY *ListHead;
|
|
LIST_ENTRY *Link;
|
|
|
|
if ((Root == NULL) ||
|
|
(Type >= MetadataTypeMax) ||
|
|
(Metadata == NULL) ||
|
|
(MetadataSize != mMetadataStaticInfo[Type].ExpectedSize))
|
|
{
|
|
ASSERT (Root != NULL);
|
|
ASSERT (Type < MetadataTypeMax);
|
|
ASSERT (Metadata != NULL);
|
|
ASSERT (MetadataSize == mMetadataStaticInfo[Type].ExpectedSize);
|
|
return NULL;
|
|
}
|
|
|
|
ListHead = &((METADATA_ROOT *)Root)->MetadataList[Type].List;
|
|
|
|
if (PrevHandle == NULL) {
|
|
Link = GetFirstNode (ListHead);
|
|
} else {
|
|
Link = GetNextNode (ListHead, (LIST_ENTRY *)PrevHandle);
|
|
}
|
|
|
|
// End of the list.
|
|
if (Link == ListHead) {
|
|
Link = NULL;
|
|
}
|
|
|
|
Entry = (METADATA_ENTRY *)Link;
|
|
|
|
if ((Entry != NULL) && (Entry->Metadata != NULL)) {
|
|
CopyMem (Metadata, Entry->Metadata, mMetadataStaticInfo[Type].ExpectedSize);
|
|
}
|
|
|
|
return (METADATA_HANDLE)Link;
|
|
}
|