| /** @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; | |
| } |