Files
EDK2-fork/DynamicTablesPkg/Library/Common/MetadataObjLib/MetadataObj.c
Pierre Gondois 1b7d687dc6 DynamicTablesPkg: Add MetaDataObjLib library
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>
2025-06-11 12:24:35 +00:00

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;
}