blob: 20b06099469c2769ca4d538b85ed32b1dbe8bc74 [file] [log] [blame]
/** @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;
}