mirror of
https://github.com/tianocore/edk2
synced 2026-08-27 00:23:19 -04:00
Clean up all metadata entries when freeing a metadata handle in MetadataFreeHandle. Signed-off-by: Oleksandr Tymoshenko <ovt@google.com>
441 lines
12 KiB
C
441 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] RootHandle 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 RootHandle
|
|
)
|
|
{
|
|
METADATA_ROOT *Root;
|
|
METADATA_ENTRY *Entry;
|
|
UINT32 Index;
|
|
|
|
Root = (METADATA_ROOT *)RootHandle;
|
|
|
|
if (Root == NULL) {
|
|
ASSERT (Root != NULL);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
for (Index = 0; Index < MetadataTypeMax; Index++) {
|
|
while (!IsListEmpty (&Root->MetadataList[Index].List)) {
|
|
Entry = (METADATA_ENTRY *)GetFirstNode (&Root->MetadataList[Index].List);
|
|
RemoveEntryList (&Entry->List);
|
|
if (Entry->Metadata != NULL) {
|
|
FreePool (Entry->Metadata);
|
|
}
|
|
|
|
FreePool (Entry);
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|