summaryrefslogtreecommitdiffstats
path: root/DynamicTablesPkg/Library/Common/DynamicPlatRepoLib/DynamicPlatRepo.c
diff options
context:
space:
mode:
Diffstat (limited to 'DynamicTablesPkg/Library/Common/DynamicPlatRepoLib/DynamicPlatRepo.c')
-rw-r--r--DynamicTablesPkg/Library/Common/DynamicPlatRepoLib/DynamicPlatRepo.c521
1 files changed, 521 insertions, 0 deletions
diff --git a/DynamicTablesPkg/Library/Common/DynamicPlatRepoLib/DynamicPlatRepo.c b/DynamicTablesPkg/Library/Common/DynamicPlatRepoLib/DynamicPlatRepo.c
new file mode 100644
index 0000000000..bc713f30b2
--- /dev/null
+++ b/DynamicTablesPkg/Library/Common/DynamicPlatRepoLib/DynamicPlatRepo.c
@@ -0,0 +1,521 @@
+/** @file
+ Dynamic Platform Info Repository
+
+ Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Glossary:
+ - Cm or CM - Configuration Manager
+ - Obj or OBJ - Object
+**/
+
+#include <Protocol/ConfigurationManagerProtocol.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include "CmObjectTokenFixer.h"
+#include "DynamicPlatRepoInternal.h"
+#include "TokenGenerator.h"
+
+/** Allocate a CM_OBJ_NODE.
+
+ @param [in] CmObjDesc CmObj to wrap in a node.
+ All the fields of the CmObj (Data field included),
+ are copied.
+ @param [in] Token Token to assign to this CmObj/node.
+ @param [out] ObjNode Allocated ObjNode.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_OUT_OF_RESOURCES An allocation has failed.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AllocCmObjNode (
+ IN CONST CM_OBJ_DESCRIPTOR *CmObjDesc,
+ IN CM_OBJECT_TOKEN Token,
+ OUT CM_OBJ_NODE **ObjNode
+ )
+{
+ CM_OBJ_NODE *Node;
+ CM_OBJ_DESCRIPTOR *Desc;
+
+ if ((CmObjDesc == NULL) || (ObjNode == NULL)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Node = AllocateZeroPool (sizeof (CM_OBJ_NODE));
+ if (Node == NULL) {
+ ASSERT (0);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ // Initialise the list head.
+ InitializeListHead (&Node->Link);
+ Node->Token = Token;
+ Desc = &Node->CmObjDesc;
+ Desc->ObjectId = CmObjDesc->ObjectId;
+ Desc->Size = CmObjDesc->Size;
+ Desc->Count = CmObjDesc->Count;
+
+ // Allocate and copy the CmObject Data.
+ Desc->Data = AllocateCopyPool (CmObjDesc->Size, CmObjDesc->Data);
+ if (Desc->Data == NULL) {
+ FreePool (Node);
+ ASSERT (0);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *ObjNode = Node;
+ return EFI_SUCCESS;
+}
+
+/** Free a CM_OBJ_NODE.
+
+ @param [in] ObjNode ObjNode to free.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+FreeCmObjNode (
+ IN CM_OBJ_NODE *ObjNode
+ )
+{
+ CM_OBJ_DESCRIPTOR *Desc;
+
+ if (ObjNode == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Unlink Node
+ RemoveEntryList (&ObjNode->Link);
+
+ Desc = &ObjNode->CmObjDesc;
+ if (Desc->Data != NULL) {
+ FreePool (Desc->Data);
+ }
+
+ FreePool (ObjNode);
+ return EFI_SUCCESS;
+}
+
+/** Add an object to the dynamic platform repository.
+
+ @param [in] This This dynamic platform repository.
+ @param [in] CmObjDesc CmObj to add. The data is copied.
+ @param [out] Token If not NULL, token allocated to this CmObj.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_OUT_OF_RESOURCES An allocation has failed.
+**/
+EFI_STATUS
+EFIAPI
+DynPlatRepoAddObject (
+ IN DYNAMIC_PLATFORM_REPOSITORY_INFO *This,
+ IN CONST CM_OBJ_DESCRIPTOR *CmObjDesc,
+ OUT CM_OBJECT_TOKEN *Token OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ CM_OBJ_NODE *ObjNode;
+ CM_OBJECT_ID ArmNamespaceObjId;
+ CM_OBJECT_TOKEN NewToken;
+
+ // The dynamic repository must be able to receive objects.
+ if ((This == NULL) ||
+ (CmObjDesc == NULL) ||
+ (This->RepoState != DynRepoTransient))
+ {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Check the CmObjDesc:
+ // - only Arm objects are supported for now.
+ // - only EArmObjCmRef objects can be added as arrays.
+ ArmNamespaceObjId = GET_CM_OBJECT_ID (CmObjDesc->ObjectId);
+ if ((CmObjDesc->Size == 0) ||
+ (CmObjDesc->Count == 0) ||
+ (ArmNamespaceObjId >= EArmObjMax) ||
+ ((CmObjDesc->Count > 1) && (ArmNamespaceObjId != EArmObjCmRef)) ||
+ (GET_CM_NAMESPACE_ID (CmObjDesc->ObjectId) != EObjNameSpaceArm))
+ {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Generate a token.
+ NewToken = GenerateToken ();
+
+ // Create an ObjNode.
+ Status = AllocCmObjNode (CmObjDesc, NewToken, &ObjNode);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // Fixup self-token if necessary.
+ Status = FixupCmObjectSelfToken (&ObjNode->CmObjDesc, NewToken);
+ if (EFI_ERROR (Status)) {
+ FreeCmObjNode (ObjNode);
+ ASSERT (0);
+ return Status;
+ }
+
+ // Add to link list.
+ InsertTailList (&This->ArmCmObjList[ArmNamespaceObjId], &ObjNode->Link);
+ This->ObjectCount += 1;
+
+ if (Token != NULL) {
+ *Token = NewToken;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/** Group lists of CmObjNode from the ArmNameSpace to one array.
+
+ @param [in] This This dynamic platform repository.
+ @param [in] ArmObjIndex Index in EARM_OBJECT_ID
+ (must be < EArmObjMax).
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_BUFFER_TOO_SMALL Buffer too small.
+ @retval EFI_OUT_OF_RESOURCES An allocation has failed.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GroupCmObjNodes (
+ IN DYNAMIC_PLATFORM_REPOSITORY_INFO *This,
+ IN UINT32 ArmObjIndex
+ )
+{
+ EFI_STATUS Status;
+ UINTN Count;
+ UINTN Size;
+ UINT32 CmObjId;
+ UINT8 *GroupedData;
+ UINT8 *Data;
+ CM_OBJ_DESCRIPTOR *CmObjDesc;
+ LIST_ENTRY *ListHead;
+ LIST_ENTRY *Link;
+
+ if ((This == NULL) ||
+ (ArmObjIndex >= EArmObjMax))
+ {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Count = 0;
+ Size = 0;
+ CmObjId = CREATE_CM_ARM_OBJECT_ID (ArmObjIndex);
+ ListHead = &This->ArmCmObjList[ArmObjIndex];
+ Link = GetFirstNode (ListHead);
+
+ // Compute the total count and size of the CmObj in the list.
+ while (Link != ListHead) {
+ CmObjDesc = &((CM_OBJ_NODE *)Link)->CmObjDesc;
+
+ if (CmObjDesc->ObjectId != CmObjId) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((CmObjDesc->Count != 1) && (ArmObjIndex != EArmObjCmRef)) {
+ // We expect each descriptor to contain an individual object.
+ // EArmObjCmRef objects are counted as groups, so +1 as well.
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Count++;
+ Size += CmObjDesc->Size;
+
+ // Next Link
+ Link = GetNextNode (ListHead, Link);
+ } // while
+
+ if (Count == 0) {
+ // No objects found.
+ return EFI_SUCCESS;
+ }
+
+ GroupedData = AllocateZeroPool (Size);
+ if (GroupedData == NULL) {
+ ASSERT (0);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ // Copy the Object Data and add to the TokenMapper.
+ Data = GroupedData;
+ Link = GetFirstNode (ListHead);
+ while (Link != ListHead) {
+ CmObjDesc = &((CM_OBJ_NODE *)Link)->CmObjDesc;
+ CopyMem (Data, CmObjDesc->Data, CmObjDesc->Size);
+
+ // Add the object to the Token Mapper.
+ // Note: The CmObject Data field of objects in the Token Mapper point
+ // to the memory in the GroupedData array.
+ Status = TokenMapperAddObject (
+ &This->TokenMapper,
+ ((CM_OBJ_NODE *)Link)->Token,
+ CmObjDesc->ObjectId,
+ CmObjDesc->Size,
+ Data
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (GroupedData);
+ return Status;
+ }
+
+ Data += CmObjDesc->Size;
+ Link = GetNextNode (ListHead, Link);
+ } // while
+
+ CmObjDesc = &This->ArmCmObjArray[ArmObjIndex];
+ CmObjDesc->ObjectId = CmObjId;
+ CmObjDesc->Size = Size;
+ CmObjDesc->Count = Count;
+ CmObjDesc->Data = GroupedData;
+
+ return Status;
+}
+
+/** Finalise the dynamic repository.
+
+ Finalising means:
+ - Preventing any further objects from being added.
+ - Allowing to get objects from the dynamic repository
+ (not possible before a call to this function).
+
+ @param [in] This This dynamic platform repository.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_ALREADY_STARTED Instance already initialised.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_BUFFER_TOO_SMALL Buffer too small.
+ @retval EFI_OUT_OF_RESOURCES An allocation has failed.
+**/
+EFI_STATUS
+EFIAPI
+DynamicPlatRepoFinalise (
+ IN DYNAMIC_PLATFORM_REPOSITORY_INFO *This
+ )
+{
+ EFI_STATUS Status;
+ UINTN ArmObjIndex;
+
+ if ((This == NULL) ||
+ (This->RepoState != DynRepoTransient))
+ {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Prevent any further objects from being added.
+ This->RepoState = DynRepoFinalized;
+
+ // Initialise the token mapper.
+ Status = TokenMapperInitialise (&This->TokenMapper, This->ObjectCount);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ return Status;
+ }
+
+ // For each CM_OBJECT_ID:
+ // - Convert the list of nodes to an array
+ // (the array is wrapped in a CmObjDesc).
+ // - Add the Token/CmObj binding to the token mapper.
+ for (ArmObjIndex = 0; ArmObjIndex < EArmObjMax; ArmObjIndex++) {
+ Status = GroupCmObjNodes (This, ArmObjIndex);
+ if (EFI_ERROR (Status)) {
+ ASSERT (0);
+ // Free the TokenMapper.
+ // Ignore the returned Status since we already failed.
+ TokenMapperShutdown (&This->TokenMapper);
+ return Status;
+ }
+ } // for
+
+ return EFI_SUCCESS;
+}
+
+/** Get a CmObj from the dynamic repository.
+
+ @param [in] This Pointer to the Dynamic Platform Repository.
+ @param [in] CmObjectId The Configuration Manager Object ID.
+ @param [in] Token An optional token identifying the object. If
+ unused this must be CM_NULL_TOKEN.
+ @param [in, out] CmObjDesc Pointer to the Configuration Manager Object
+ descriptor describing the requested Object.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND The required object information is not found.
+**/
+EFI_STATUS
+EFIAPI
+DynamicPlatRepoGetObject (
+ IN DYNAMIC_PLATFORM_REPOSITORY_INFO *This,
+ IN CM_OBJECT_ID CmObjectId,
+ IN CM_OBJECT_TOKEN Token OPTIONAL,
+ IN OUT CM_OBJ_DESCRIPTOR *CmObjDesc
+ )
+{
+ EFI_STATUS Status;
+ CM_OBJ_DESCRIPTOR *Desc;
+ CM_OBJECT_ID ArmNamespaceObjId;
+
+ if ((This == NULL) ||
+ (CmObjDesc == NULL) ||
+ (This->RepoState != DynRepoFinalized))
+ {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ArmNamespaceObjId = GET_CM_OBJECT_ID (CmObjectId);
+ if (ArmNamespaceObjId >= EArmObjMax) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Token != CM_NULL_TOKEN) {
+ // Search in the Token Mapper and return the object.
+ Status = TokenMapperGetObject (
+ &This->TokenMapper,
+ Token,
+ CmObjectId,
+ CmObjDesc
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ if (ArmNamespaceObjId == EArmObjCmRef) {
+ // EArmObjCmRef object must be requested using a valid token.
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Desc = &This->ArmCmObjArray[ArmNamespaceObjId];
+
+ // Nothing here.
+ if (Desc->Count == 0) {
+ return EFI_NOT_FOUND;
+ } else {
+ // Return the full array.
+ CmObjDesc->ObjectId = Desc->ObjectId;
+ CmObjDesc->Size = Desc->Size;
+ CmObjDesc->Data = Desc->Data;
+ CmObjDesc->Count = Desc->Count;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/** Initialize the dynamic platform repository.
+
+ @param [out] DynPlatRepo If success, contains the initialised dynamic
+ platform repository.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_OUT_OF_RESOURCES An allocation has failed.
+**/
+EFI_STATUS
+EFIAPI
+DynamicPlatRepoInit (
+ OUT DYNAMIC_PLATFORM_REPOSITORY_INFO **DynPlatRepo
+ )
+{
+ UINTN Index;
+ DYNAMIC_PLATFORM_REPOSITORY_INFO *Repo;
+
+ if (DynPlatRepo == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Repo = AllocateZeroPool (sizeof (DYNAMIC_PLATFORM_REPOSITORY_INFO));
+ if (Repo == NULL) {
+ ASSERT (0);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ // Initialise the CmObject List.
+ for (Index = 0; Index < EArmObjMax; Index++) {
+ InitializeListHead (&Repo->ArmCmObjList[Index]);
+ }
+
+ Repo->ObjectCount = 0;
+ Repo->RepoState = DynRepoTransient;
+
+ *DynPlatRepo = Repo;
+
+ return EFI_SUCCESS;
+}
+
+/** Shutdown the dynamic platform repository.
+
+ Free all the memory allocated for the dynamic platform repository.
+
+ @param [in] DynPlatRepo The dynamic platform repository.
+
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_SUCCESS Success.
+**/
+EFI_STATUS
+EFIAPI
+DynamicPlatRepoShutdown (
+ IN DYNAMIC_PLATFORM_REPOSITORY_INFO *DynPlatRepo
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ LIST_ENTRY *ListHead;
+ CM_OBJ_DESCRIPTOR *CmObjDesc;
+ VOID *Data;
+
+ if (DynPlatRepo == NULL) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Free the list of objects.
+ for (Index = 0; Index < EArmObjMax; Index++) {
+ // Free all the nodes with this object Id.
+ ListHead = &DynPlatRepo->ArmCmObjList[Index];
+ while (!IsListEmpty (ListHead)) {
+ FreeCmObjNode ((CM_OBJ_NODE *)GetFirstNode (ListHead));
+ } // while
+ } // for
+
+ // Free the arrays.
+ CmObjDesc = DynPlatRepo->ArmCmObjArray;
+ for (Index = 0; Index < EArmObjMax; Index++) {
+ Data = CmObjDesc[Index].Data;
+ if (Data != NULL) {
+ FreePool (Data);
+ }
+ } // for
+
+ // Free the TokenMapper
+ Status = TokenMapperShutdown (&DynPlatRepo->TokenMapper);
+ ASSERT_EFI_ERROR (Status);
+ FreePool (DynPlatRepo);
+ return Status;
+}