Add functions abstracting adding and removing of objects using
the ConfigurationManagerProtocol to TableHelperLib. Also add
helpers for writing component library constructors for component
libraries populating a ConfigurationManager.

Cc: Sami Mujawar <sami.muja...@arm.com>
Cc: Alexei Fedorov <alexei.fedo...@arm.com>
Signed-off-by: Tomas Pilar <to...@nuviainc.com>
---
 .../Include/Library/TableHelperLib.h          | 170 ++++++++
 .../Common/TableHelperLib/TableHelper.c       | 379 +++++++++++++++++-
 .../Common/TableHelperLib/TableHelperLib.inf  |   6 +
 3 files changed, 554 insertions(+), 1 deletion(-)

diff --git a/DynamicTablesPkg/Include/Library/TableHelperLib.h 
b/DynamicTablesPkg/Include/Library/TableHelperLib.h
index e4a8dfa046..0d3d1bbd60 100644
--- a/DynamicTablesPkg/Include/Library/TableHelperLib.h
+++ b/DynamicTablesPkg/Include/Library/TableHelperLib.h
@@ -12,6 +12,176 @@
 #ifndef TABLE_HELPER_LIB_H_
 #define TABLE_HELPER_LIB_H_
 
+#include <Protocol/ConfigurationManagerProtocol.h>
+
+/**
+  Get a unique token that can be used for configuration object
+  cross referencing.
+
+  @retval Unique arbitrary cross reference token.
+**/
+UINTN
+EFIAPI
+GetNewToken();
+
+/**
+  Return the count of objects of a given ObjectId.
+
+  @param[in]  CmObjectId   The id of the desired configuration objects.
+  @param[out] ItemCount    Number of objects with given ObjectId.
+**/
+EFI_STATUS
+EFIAPI
+CfgMgrCountObjects (
+  IN   CONST  CM_OBJECT_ID         CmObjectId,
+  OUT         UINT32               *ItemCount
+  );
+
+/**
+  Get a single object form the configuration manager with the
+  matching ObjectId regardless of any cross reference tokens.
+
+  @param[in]  CmObjectId   The id of the desired configuration object
+  @param[out] Buffer       Buffer containing the payload of the CmObject.
+
+  @retval EFI_SUCCESS      Payload was successfully returned
+  @retval EFI_NOT_FOUND    There was no such object
+  @retval EFI_UNSUPPORTED  ConfigurationManangerProtocol is not installed
+**/
+EFI_STATUS
+EFIAPI
+CfgMgrGetSimpleObject(
+  IN  CONST CM_OBJECT_ID             CmObjectId,
+  OUT         VOID **                Buffer
+  );
+
+/**
+  Prototype for an initialiser function to be used by component
+  libraries that are linked as NULL libraries to a Configuration
+  Manager binary and used to populate said Configuration Manager
+  with objects.
+
+  @param[in] CfgMgrProtocol  The newly installed ConfigurationManagerProtocol
+                             that can be used by the library to populate the
+                             Configuration Manager with objects.
+**/
+typedef EFI_STATUS (EFIAPI *CFG_MGR_COMPONENT_LIB_INIT) (
+  IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CfgMgrProtocol
+  );
+
+/**
+  Register a callback inintialiser to be called when a configuration
+  manager is installed. The initialiser function is expected to
+  populate the newly installed configuration manager with objects when
+  called.
+
+  This helper should be used by component libraries that want to
+  provide configuration objects and are to be linked in as NULL
+  libraries into the configuration manager binary.
+
+  @param[in] InitFunction   An initialiser function that will be called when
+                            a configuration manager becomes available.
+  @retval EFI_OUT_OF_RESOURCES   Failed to allocate necessary memory.
+  @retval EFI_SUCCESS            Registration was successful.
+**/
+EFI_STATUS
+EFIAPI
+RegisterForCfgManager (
+  IN CONST CFG_MGR_COMPONENT_LIB_INIT InitFunction
+  );
+
+/**
+  Remove a configuration object from the configuration manager. If a
+  cross reference token is supplied, only objects referenced by that
+  token will be removed. If a token is not supplied, all objects of the
+  given type will be removed.
+
+  @param[in] CmObjectId   The id of the object that is to be removed.
+  @param[in] Token        Unique cross-reference token of the object to be 
removed.
+
+  @retval EFI_UNSUPPORTED There is no configuration manager installed.
+  @retval EFI_NOT_FOUND   The combination of id and token was not found in the
+                          configuration manager.
+  @retval EFI_SUCCESS     Object was successfully deleted.
+**/
+EFI_STATUS
+EFIAPI
+CfgMgrRemoveObject (
+  IN  CONST CM_OBJECT_ID                                  CmObjectId,
+  IN  CONST CM_OBJECT_TOKEN                               Token OPTIONAL
+  );
+
+/**
+  Add an instance of object to the configuration manager. If an object with
+  the specified object id and token already exists in the manager, append the
+  provided object to the existing list. Otherwise, create a new list with this
+  object being the only member.
+
+  @param[in] CmObjectId The id of the object that is to be added.
+  @param[in] Token      The unique cross-reference token for this object.
+  @param[in] Buffer     The instance of the object being added.
+  @param[in] BufferSize Size of Buffer in bytes.
+
+  @retval EFI_OUT_OF_RESOURCES   Failed to allocate required memory when 
appending data
+  @retval EFI_UNSUPPORTED        There is no Configuration Manager installed
+  @retval EFI_SUCCESS            Object was successfully added to the 
Configuration Manager
+**/
+EFI_STATUS
+EFIAPI
+CfgMgrAddObject (
+  IN  CONST CM_OBJECT_ID                                  CmObjectId,
+  IN  CONST CM_OBJECT_TOKEN                               Token OPTIONAL,
+  IN        VOID *                                        Buffer,
+  IN        UINTN                                         BufferSize
+  );
+
+/**
+  Add multiple objects of the same type/token to the configuration manager.
+  If an object with the specified object id and token already exists in the
+  manager, append the provided objects to the existing list. Otherwise, create
+  a new list.
+
+  @param[in] CmObjectId The id of the object that is to be added.
+  @param[in] Token      The unique cross-reference token for this object.
+  @param[in] Buffer     The instance of the objects being added.
+  @param[in] BufferSize Size of Buffer in bytes.
+  @param[in] ItemCount  Number of instances of object in the Buffer.
+
+  @retval EFI_OUT_OF_RESOURCES   Failed to allocate required memory when 
appending data.
+  @retval EFI_UNSUPPORTED        There is no Configuration Manager installed.
+  @retval EFI_SUCCESS            Object was successfully added to the 
Configuration Manager.
+**/
+EFI_STATUS
+EFIAPI
+CfgMgrAddObjects (
+  IN  CONST CM_OBJECT_ID                                  CmObjectId,
+  IN  CONST CM_OBJECT_TOKEN                               Token OPTIONAL,
+  IN        VOID *                                        Buffer,
+  IN        UINTN                                         BufferSize,
+  IN        UINT32                                        ItemCount
+  );
+
+/**
+  Retrieve an object with a given id from the installed configuration
+  manager. If a token is not specified, returns all objects of given
+  id, regardless of token. The methods unwraps the CmObject abstraction
+  and only returns the payloads.
+
+  @param[in]  CmObjectId   The id of the desired configuration objects.
+  @param[in]  Token        Optional cross reference token. If not supplied, 
all.
+                           objects of the given id are returned.
+  @param[out] Buffer       Buffer containing a number of payloads of CmObjects.
+  @param[out] ItemCount    The count of payloads in Buffer.
+**/
+EFI_STATUS
+EFIAPI
+CfgMgrGetObjects (
+  IN   CONST  CM_OBJECT_ID         CmObjectId,
+  IN   CONST  CM_OBJECT_TOKEN      Token        OPTIONAL,
+  OUT         VOID **              Buffer       OPTIONAL,
+  OUT         UINT32 *             ItemCount    OPTIONAL
+  );
+
 /** The GetCgfMgrInfo function gets the CM_STD_OBJ_CONFIGURATION_MANAGER_INFO
     object from the Configuration Manager.
 
diff --git a/DynamicTablesPkg/Library/Common/TableHelperLib/TableHelper.c 
b/DynamicTablesPkg/Library/Common/TableHelperLib/TableHelper.c
index fc6cf3b088..18c0e95e0d 100644
--- a/DynamicTablesPkg/Library/Common/TableHelperLib/TableHelper.c
+++ b/DynamicTablesPkg/Library/Common/TableHelperLib/TableHelper.c
@@ -6,9 +6,13 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 **/
 
 #include <Protocol/AcpiTable.h>
+
 #include <Library/BaseLib.h>
-#include <Library/DebugLib.h>
 #include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PrintLib.h>
 
 // Module specific include files.
 #include <AcpiTableGenerator.h>
@@ -16,6 +20,378 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 #include <Library/TableHelperLib.h>
 #include <Protocol/ConfigurationManagerProtocol.h>
 
+/**
+  Get a unique token that can be used for configuration object
+  cross referencing.
+
+  @retval Unique arbitrary cross reference token
+**/
+UINTN
+EFIAPI
+GetNewToken()
+{
+  UINTN Token;
+  EFI_STATUS Status = gBS->GetNextMonotonicCount(&Token);
+  if (EFI_ERROR(Status)) {
+    return CM_NULL_TOKEN;
+  }
+
+  return Token;
+}
+
+/**
+  Event callback for executing the registered component library
+  inintialiser with the newly installed ConfigurationManagerProtocol
+  as the only parameter.
+**/
+STATIC
+VOID
+EFIAPI
+ComponentInitEvent (
+  IN EFI_EVENT Event,
+  IN VOID     *Context
+  )
+{
+  ASSERT (Context != NULL);
+
+  CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CfgMgrProtocol;
+  CFG_MGR_COMPONENT_LIB_INIT InitFunction = Context;
+
+  EFI_STATUS Status = gBS->LocateProtocol (
+    &gEdkiiConfigurationManagerProtocolGuid,
+    NULL,
+    (VOID **) &CfgMgrProtocol);
+
+
+  if (EFI_ERROR(Status)) {    // Should never happen
+    gBS->CloseEvent(Event);
+    RegisterForCfgManager(InitFunction);
+    return;
+  }
+
+  InitFunction(CfgMgrProtocol);
+}
+
+/**
+  Register a callback inintialiser to be called when a configuration
+  manager is installed. The initialiser function is expected to
+  populate the newly installed configuration manager with objects when
+  called.
+
+  This helper should be used by component libraries that want to
+  provide configuration objects and are to be linked in as NULL
+  libraries into the configuration manager binary.
+
+  @param[in] InitFunction   An initialiser function that will be called when
+                            a configuration manager becomes available.
+  @retval EFI_OUT_OF_RESOURCES   Failed to allocate necessary memory
+  @retval EFI_SUCCESS            Registration was successful
+**/
+EFI_STATUS
+EFIAPI
+RegisterForCfgManager (
+  CONST CFG_MGR_COMPONENT_LIB_INIT InitFunction
+  )
+{
+  EFI_STATUS Status = EFI_NOT_STARTED;
+  EFI_EVENT InitEvent;
+  VOID *Registration;
+
+  ASSERT(InitFunction != NULL);
+
+  Status = gBS->CreateEvent (
+    EVT_NOTIFY_SIGNAL,
+    TPL_NOTIFY,
+    ComponentInitEvent,
+    InitFunction,
+    &InitEvent);
+
+  if (EFI_ERROR(Status)) {
+    return Status;
+  }
+
+  Status = gBS->RegisterProtocolNotify (
+    &gEdkiiConfigurationManagerProtocolGuid,
+    InitEvent,
+    &Registration);
+
+  if (EFI_ERROR(Status)) {
+    gBS->CloseEvent(InitEvent);
+  }
+
+  return Status;
+}
+
+/**
+  Return the count of objects of a given ObjectId.
+  If there are no objects, ItemCount is set to zero.
+
+  @param[in]  CmObjectId   The id of the desired configuration objects.
+  @param[out] ItemCount    Number of objects with given ObjectId.
+**/
+EFI_STATUS
+EFIAPI
+CfgMgrCountObjects (
+  IN   CONST  CM_OBJECT_ID         CmObjectId,
+  OUT         UINT32               *ItemCount
+  )
+{
+  EFI_STATUS Status = EFI_NOT_STARTED;
+
+  Status = CfgMgrGetObjects (CmObjectId, CM_NULL_TOKEN, NULL, ItemCount);
+  if (Status == EFI_NOT_FOUND) {
+    *ItemCount = 0;
+  }
+
+  return Status;
+}
+
+/**
+  Retrieve an object with a given id from the installed configuration
+  manager. If a token is not specified, returns all objects of given
+  id, regardless of token. The methods unwraps the CmObject abstraction
+  and only returns the payloads.
+
+  If Buffer is not NULL, the data will be returned in allocated memory. The
+  caller must free this memory when they are done with the data.
+
+  If ItemCount is not NULL, the count of items matching the criteria
+  is returned.
+
+  @param[in]  CmObjectId   The id of the desired configuration objects
+  @param[in]  Token        Optional cross reference token. If not supplied, all
+                           objects of the given id are returned.
+  @param[out] Buffer       Buffer containing a number of payloads of CmObjects.
+  @param[out] ItemCount    The count of payloads in Buffer
+**/
+EFI_STATUS
+EFIAPI
+CfgMgrGetObjects (
+  IN   CONST  CM_OBJECT_ID         CmObjectId,
+  IN   CONST  CM_OBJECT_TOKEN      Token        OPTIONAL,
+  OUT         VOID **              Buffer       OPTIONAL,
+  OUT         UINT32 *             ItemCount    OPTIONAL
+  )
+{
+  EDKII_CONFIGURATION_MANAGER_PROTOCOL *CfgMgr;
+  EFI_STATUS Status;
+
+  Status = gBS->LocateProtocol (
+    &gEdkiiConfigurationManagerProtocolGuid, NULL, (VOID **) &CfgMgr);
+  if (EFI_ERROR(Status)) {
+    DEBUG ((DEBUG_ERROR, "ERROR: No Configuration Manager Protocol Found!\n"));
+    return EFI_UNSUPPORTED;
+  }
+
+  CM_OBJ_DESCRIPTOR Object;
+
+  Status = CfgMgr->GetObject(CfgMgr, CmObjectId, Token, &Object);
+  if (EFI_ERROR(Status)) {
+    if (Status != EFI_NOT_FOUND) {
+      DEBUG (
+        (DEBUG_ERROR,
+         "ERROR: FADT: Failed to get <%s> [%r]\n",
+         CmObjectIdName (CmObjectId),
+         Status));
+    }
+
+    return Status;
+  }
+
+  if (Buffer) {
+    *Buffer = AllocateCopyPool (Object.Size, Object.Data);
+    if (Buffer == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+  }
+
+  if (ItemCount) {
+    *ItemCount = Object.Count;
+  }
+
+  if (CfgMgr->Revision >= CREATE_REVISION(1, 1)) {
+    CfgMgr->FreeObject(CfgMgr, &Object);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Get a single object form the configuration manager with the
+  matching ObjectId regardless of any cross reference tokens.
+
+  @param[in]  CmObjectId   The id of the desired configuration object
+  @param[out] Buffer       Buffer containing the payload of the CmObject.
+
+  @retval EFI_SUCCESS      Payload was successfully returned
+  @retval EFI_NOT_FOUND    There was no such object
+  @retval EFI_UNSUPPORTED  ConfigurationManangerProtocol is not installed
+**/
+EFI_STATUS
+EFIAPI
+CfgMgrGetSimpleObject(
+  IN  CONST CM_OBJECT_ID             CmObjectId,
+  OUT         VOID **                Buffer
+  )
+{
+  EFI_STATUS Status;
+
+  Status = CfgMgrGetObjects(CmObjectId, CM_NULL_TOKEN, Buffer, NULL);
+  if (Status == EFI_NOT_FOUND) {
+    DEBUG ((DEBUG_ERROR,
+            "ERROR: Failed to get <%s> [%r]\n",
+            CmObjectIdName (CmObjectId),
+            Status));
+  }
+  return Status;
+}
+
+/**
+  Add an instance of object to the configuration manager. If an object with
+  the specified object id and token already exists in the manager, append the
+  provided object to the existing list. Otherwise, create a new list with this
+  object being the only member.
+
+  @param[in] CmObjectId The id of the object that is to be added
+  @param[in] Token      The unique cross-reference token for this object
+  @param[in] Buffer     The instance of the object being added
+  @param[in] BufferSize Size of Buffer in bytes
+
+  @retval EFI_OUT_OF_RESOURCES   Failed to allocate required memory when 
appending data
+  @retval EFI_UNSUPPORTED        There is no Configuration Manager installed
+  @retval EFI_SUCCESS            Object was successfully added to the 
Configuration Manager
+**/
+EFI_STATUS
+EFIAPI
+CfgMgrAddObject (
+  IN  CONST CM_OBJECT_ID                                  CmObjectId,
+  IN  CONST CM_OBJECT_TOKEN                               Token OPTIONAL,
+  IN        VOID *                                        Buffer,
+  IN        UINTN                                         BufferSize
+  )
+{
+  EFI_STATUS Status;
+  EDKII_CONFIGURATION_MANAGER_PROTOCOL *CfgMgrProtocol;
+  CM_OBJ_DESCRIPTOR CurrentObject = { 0 };
+  CM_OBJ_DESCRIPTOR NewObject;
+
+  ASSERT(Buffer != NULL);
+  ASSERT(BufferSize != 0);
+
+  Status = gBS->LocateProtocol (
+    &gEdkiiConfigurationManagerProtocolGuid, NULL, (VOID **) &CfgMgrProtocol);
+
+  if (EFI_ERROR(Status)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  Status = CfgMgrProtocol->GetObject (
+    CfgMgrProtocol, CmObjectId, Token, &CurrentObject);
+
+  NewObject.ObjectId = CmObjectId;
+  NewObject.Count = 1 + CurrentObject.Count;
+  NewObject.Size = BufferSize +CurrentObject.Size;
+
+  NewObject.Data = AllocateZeroPool(NewObject.Size);
+  if (NewObject.Data == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  CopyMem(NewObject.Data, CurrentObject.Data, CurrentObject.Size); // NOP if 
CurrentObject does not exist
+  CopyMem((UINT8 *) NewObject.Data + CurrentObject.Size, Buffer, BufferSize);
+
+  Status =
+    CfgMgrProtocol->SetObject (CfgMgrProtocol, CmObjectId, Token, &NewObject);
+
+  FreePool (NewObject.Data);
+  return Status;
+}
+
+/**
+  Add multiple objects of the same type/token to the configuration manager.
+  If an object with the specified object id and token already exists in the
+  manager, append the provided objects to the existing list. Otherwise, create
+  a new list.
+
+  @param[in] CmObjectId The id of the object that is to be added.
+  @param[in] Token      The unique cross-reference token for this object.
+  @param[in] Buffer     The instance of the objects being added.
+  @param[in] BufferSize Size of Buffer in bytes.
+  @param[in] ItemCount  Number of instances of object in the Buffer.
+
+  @retval EFI_OUT_OF_RESOURCES   Failed to allocate required memory when 
appending data.
+  @retval EFI_UNSUPPORTED        There is no Configuration Manager installed.
+  @retval EFI_SUCCESS            Object was successfully added to the 
Configuration Manager.
+**/
+EFI_STATUS
+EFIAPI
+CfgMgrAddObjects (
+  IN  CONST CM_OBJECT_ID                                  CmObjectId,
+  IN  CONST CM_OBJECT_TOKEN                               Token OPTIONAL,
+  IN        VOID *                                        Buffer,
+  IN        UINTN                                         BufferSize,
+  IN        UINT32                                        ItemCount
+  )
+{
+  UINTN Index;
+  UINT8 *Cursor = Buffer;
+  UINTN ItemSize = BufferSize / ItemCount;
+  EFI_STATUS Status = EFI_NOT_STARTED;
+
+  for (Index = 0; Index < ItemCount; Index++) {
+    Status = CfgMgrAddObject(CmObjectId, Token, Cursor, ItemSize);
+    if (EFI_ERROR(Status)) {
+      return Status;
+    }
+    Cursor += ItemSize;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Remove a configuration object from the configuration manager. If a
+  cross reference token is supplied, only objects referenced by that
+  token will be removed. If a token is not supplied, all objects of the
+  given type will be removed.
+
+  @param[in] CmObjectId   The id of object that is to be removed
+  @param[in] Token        Unique cross-reference token of the object to be 
removed
+
+  @retval EFI_UNSUPPORTED There is no configuration manager installed
+  @retval EFI_NOT_FOUND   The combination of id and token was not found in the
+                          configuration manager
+  @retval EFI_SUCCESS     Object was successfully deleted
+**/
+EFI_STATUS
+EFIAPI
+CfgMgrRemoveObject (
+  IN  CONST CM_OBJECT_ID                                  CmObjectId,
+  IN  CONST CM_OBJECT_TOKEN                               Token OPTIONAL
+  )
+{
+  EFI_STATUS Status = EFI_NOT_STARTED;
+  EDKII_CONFIGURATION_MANAGER_PROTOCOL *CfgMgrProtocol;
+  CM_OBJ_DESCRIPTOR CurrentObject;
+
+  Status = gBS->LocateProtocol (
+    &gEdkiiConfigurationManagerProtocolGuid, NULL, (VOID **) &CfgMgrProtocol);
+
+  if (EFI_ERROR(Status)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  Status = CfgMgrProtocol->GetObject (
+    CfgMgrProtocol, CmObjectId, Token, &CurrentObject);
+
+  if (EFI_ERROR(Status)) {
+    return Status;
+  }
+
+  return CfgMgrProtocol->SetObject (CfgMgrProtocol, CmObjectId, Token, NULL);
+}
+
+
 /** The GetCgfMgrInfo function gets the CM_STD_OBJ_CONFIGURATION_MANAGER_INFO
     object from the Configuration Manager.
 
@@ -44,6 +420,7 @@ GetCgfMgrInfo (
   ASSERT (CfgMfrInfo != NULL);
 
   *CfgMfrInfo = NULL;
+
   Status = CfgMgrProtocol->GetObject (
                              CfgMgrProtocol,
                              CREATE_CM_STD_OBJECT_ID (EStdObjCfgMgrInfo),
diff --git a/DynamicTablesPkg/Library/Common/TableHelperLib/TableHelperLib.inf 
b/DynamicTablesPkg/Library/Common/TableHelperLib/TableHelperLib.inf
index 26d82e6850..e12380073e 100644
--- a/DynamicTablesPkg/Library/Common/TableHelperLib/TableHelperLib.inf
+++ b/DynamicTablesPkg/Library/Common/TableHelperLib/TableHelperLib.inf
@@ -23,8 +23,14 @@
 
 [LibraryClasses]
   BaseLib
+  BaseMemoryLib
+  DebugLib
+  PrintLib
+  MemoryAllocationLib
+  UefiBootServicesTableLib
 
 [Protocols]
+  gEfiSerialIoProtocolGuid
 
 [Guids]
 
-- 
2.25.1


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#63584): https://edk2.groups.io/g/devel/message/63584
Mute This Topic: https://groups.io/mt/75910569/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to