Re: [PATCH v2 1/4] ArmPlatformPkg: Allow dynamic generation of HEST ACPI table


Sami Mujawar
 

Hi Omkar,

Please find my response marked inline as [SAMI].

Regards,

Sami Mujawar


On 10/07/2021 05:18 PM, Omkar Anand Kulkarni wrote:
Introduce the HEST table generation protocol that allows platforms to
build the table with multiple error source descriptors and install the
table. The protocol provides two interfaces. The first interface allows
for adding multiple error source descriptors into the HEST table. The
second interface can then be used to dynamically install the fully
populated HEST table. This allows multiple drivers and/or libraries to
dynamically register error source descriptors into the HEST table.

Co-authored-by: Thomas Abraham <thomas.abraham@...>
Signed-off-by: Omkar Anand Kulkarni <omkar.kulkarni@...>
---
 ArmPlatformPkg/ArmPlatformPkg.dec               |   4 +
 ArmPlatformPkg/Drivers/Apei/HestDxe/HestDxe.inf |  49 +++
 ArmPlatformPkg/Include/Protocol/HestTable.h     |  71 ++++
 ArmPlatformPkg/Drivers/Apei/HestDxe/HestDxe.c   | 354 ++++++++++++++++++++
 4 files changed, 478 insertions(+)

diff --git a/ArmPlatformPkg/ArmPlatformPkg.dec b/ArmPlatformPkg/ArmPlatformPkg.dec
index 3a25ddcdc8ca..e4afe5da8e11 100644
--- a/ArmPlatformPkg/ArmPlatformPkg.dec
+++ b/ArmPlatformPkg/ArmPlatformPkg.dec
@@ -127,3 +127,7 @@
   gArmPlatformTokenSpaceGuid.PcdPL031RtcPpmAccuracy|300000000|UINT32|0x00000022
 
   gArmPlatformTokenSpaceGuid.PcdWatchdogCount|0x0|UINT32|0x00000033
+
+[Protocols.common]
+  ## Arm Platform HEST table generation protocol
+  gHestTableProtocolGuid = { 0x705bdcd9, 0x8c47, 0x457e, { 0xad, 0x0d, 0xf7, 0x86, 0xf3, 0x4a, 0x0d, 0x63 } }
diff --git a/ArmPlatformPkg/Drivers/Apei/HestDxe/HestDxe.inf b/ArmPlatformPkg/Drivers/Apei/HestDxe/HestDxe.inf
new file mode 100644
index 000000000000..91c7385bf7ff
--- /dev/null
+++ b/ArmPlatformPkg/Drivers/Apei/HestDxe/HestDxe.inf
@@ -0,0 +1,49 @@
+## @file
+#  Dxe driver that creates and publishes the HEST table.
+#
+#  This driver creates HEST header and provides protocol service to append
+#  and install the HEST table.
+#
+#  Copyright (c) 2020 - 2021, ARM Limited. All rights reserved.
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x0001001A
+  BASE_NAME                      = HestDxe
+  FILE_GUID                      = 933099a2-ef71-4e00-82aa-a79b1e0a3b38
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = HestInitialize
+
+[Sources.Common]
+  HestDxe.c
+
+[Packages]
+  ArmPkg/ArmPkg.dec
+  ArmPlatformPkg/ArmPlatformPkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+  Platform/ARM/SgiPkg/SgiPlatform.dec
+
+[LibraryClasses]
+  ArmLib
+  BaseMemoryLib
+  DebugLib
+  UefiDriverEntryPoint
+  UefiLib
+
+[Protocols]
+  gEfiAcpiTableProtocolGuid         ## PROTOCOL ALWAYS_CONSUMED
+  gHestTableProtocolGuid            ## PRODUCES
+
+[FixedPcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId
+  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision
+  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId
+  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision
+  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId
+
+[Depex]
+  TRUE
diff --git a/ArmPlatformPkg/Include/Protocol/HestTable.h b/ArmPlatformPkg/Include/Protocol/HestTable.h
new file mode 100644
index 000000000000..3b2e1f7d9203
--- /dev/null
+++ b/ArmPlatformPkg/Include/Protocol/HestTable.h
@@ -0,0 +1,71 @@
+/** @file
+  Builds and installs the HEST ACPI table.
+
+  Define the protocol interface that allows HEST ACPI table to be created,
+  populated with error record descriptions and installation of the HEST ACPI
+  table.
+
+  Copyright (c) 2020 - 2021, ARM Limited. All rights reserved.
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef HEST_TABLE_H_
+#define HEST_TABLE_H_
+
+#define HEST_TABLE_PROTOCOL_GUID \
+  { \
+    0x705bdcd9, 0x8c47, 0x457e, \
+    { 0xad, 0x0d, 0xf7, 0x86, 0xf3, 0x4a, 0x0d, 0x63 } \
+  }
+
+/**
+  Append HEST error source descriptor protocol service.
+
+  Protocol service used to append newly collected error source descriptors to
+  to an already created HEST table.
+
+  @param[in]  ErrorSourceDescriptorList      List of Error Source Descriptors.
+  @param[in]  ErrorSourceDescriptorListSize  Total Size of Error Source
+                                             Descriptors.
+  @param[in]  ErrorSourceDescriptorCount     Total count of error source
+                                             descriptors.
+
+  @retval  EFI_SUCCESS            Appending the error source descriptors
+                                  successful.
+  @retval  EFI_OUT_OF_RESOURCES   Buffer reallocation failed for the Hest
+                                  table.
+  @retval  EFI_INVALID_PARAMETER  Null ErrorSourceDescriptorList param or
+**/
+typedef
+EFI_STATUS
+(EFIAPI *APPEND_ERROR_SOURCE_DESCRIPTOR) (
+  IN CONST VOID *ErrorSourceDescriptorList,
+  IN UINTN      ErrorSourceDescriptorListSize,
+  IN UINTN      ErrorSourceDescriptorCount
+  );
+
+/**
+  Install HEST table protocol service.
+
+  Installs the HEST table that has been appended with the error source
+  descriptors. The checksum of this table is calculated and updated in
+  the table header. The HEST table is then installed.
+
+  @retval  EFI_SUCCESS  HEST table is installed successfully.
+  @retval  EFI_ABORTED  HEST table is NULL.
+  @retval  Other        Install service call failed.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *INSTALL_HEST_TABLE) (VOID);
+
+//
+// HEST_TABLE_PROTOCOL enables creation and installation of HEST table
+//
+typedef struct {
+  APPEND_ERROR_SOURCE_DESCRIPTOR AppendErrorSourceDescriptors;
+  INSTALL_HEST_TABLE             InstallHestTable;
+} HEST_TABLE_PROTOCOL;
+
+extern EFI_GUID gHestTableProtocolGuid;
+#endif  // HEST_TABLE_H_
diff --git a/ArmPlatformPkg/Drivers/Apei/HestDxe/HestDxe.c b/ArmPlatformPkg/Drivers/Apei/HestDxe/HestDxe.c
new file mode 100644
index 000000000000..b68e1a0c4e48
--- /dev/null
+++ b/ArmPlatformPkg/Drivers/Apei/HestDxe/HestDxe.c
@@ -0,0 +1,354 @@
+/** @file
+  Builds and installs the HEST ACPI table.
+
+  This driver installs a protocol that can be used to create and install a HEST
+  ACPI table. The protocol allows one or more error source producers to add the
+  error source descriptors into the HEST table. It also allows the resulting
+  HEST table to be installed.
+
+  Copyright (c) 2020 - 2021, ARM Limited. All rights reserved.
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Specification Reference:
+    - ACPI 6.3, Table 18-382, Hardware Error Source Table
+**/
+
+#include <IndustryStandard/Acpi.h>
+#include <Library/ArmLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/AcpiSystemDescriptionTable.h>
+#include <Protocol/AcpiTable.h>
+#include <Protocol/HestTable.h>
+
+typedef struct {
+  VOID   *HestTable;        /// Pointer to HEST table.
+  UINT32 CurrentTableSize;  /// Current size of HEST table.
+} HEST_DXE_DRIVER_DATA;
+
+STATIC EFI_ACPI_TABLE_PROTOCOL *mAcpiTableProtocol = NULL;
+STATIC HEST_DXE_DRIVER_DATA mHestDriverData;
+
+/**
+  Helper function to the driver.
+
+  Function that reallocates memory for every new error source descriptor info
+  added.
+
+  @param[in]       OldTableSize  Old memory pool size.
+  @param[in]       NewTableSize  Required memory pool size.
+  @param[in, out]  OldBuffer     Current memory buffer pointer holding the Hest
+                                 table data.
+
+  @return  New pointer to reallocated memory pool.
+**/
+STATIC
+VOID*
+ReallocateHestTableMemory (
+  IN     UINT32 OldTableSize,
+  IN     UINT32 NewTableSize,
+  IN OUT VOID   *OldBuffer
+  )
+{
[SAMI] Have you considered maintaining a linked list of the error sources and serialising the list once InstallHestTable() is called?
+  return ReallocateReservedPool (
+           OldTableSize,
+           NewTableSize,
+           OldBuffer
+           );
[SAMI] Is this wrapper function required? Can ReallocateReservedPool() be used directly instead?
+}
+
+/**
+  Allocate memory for the HEST table header and populate it.
+
+  Helper function for this driver, populates the HEST table header. Called once
+  in the beginning on first invocation of append error source descriptor
+  protocol service.
+
+  @retval  EFI_SUCCESS           On successful creation of HEST header.
+  @retval  EFI_OUT_OF_RESOURCES  If system is out of memory recources.
+**/
+STATIC
+EFI_STATUS
+BuildHestHeader (VOID)
[SAMI] VOID and closing parenthesis should be on a separate line.
+{
+  EFI_ACPI_6_3_HARDWARE_ERROR_SOURCE_TABLE_HEADER HestHeader;
+  UINT64                                          TempOemTableId;
+
+  //
+  // Allocate memory for the HEST table header.
+  //
+  mHestDriverData.HestTable =
+    ReallocateHestTableMemory (
+      0,
+      sizeof (EFI_ACPI_6_3_HARDWARE_ERROR_SOURCE_TABLE_HEADER),
+      NULL
+      );
[SAMI] Is the Relocate version of the function required here, maybe the Alloc version could be used.
- Should EfiReservedMemoryType be used?
    Please see extract from section 2.3.6 AArch64 Platforms of the UEFI 2.9 specification below:
    "Note:Previous EFI specifications allowed ACPI tables loaded at runtime to be in the
     EfiReservedMemoryType and there was no guidance provided for other EFI Configuration
    Tables. EfiReservedMemoryType is not intended to be used by firmware. UEFI 2.0 clarified
    the situation moving forward. "
+  if (mHestDriverData.HestTable == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  mHestDriverData.CurrentTableSize =
+    sizeof (EFI_ACPI_6_3_HARDWARE_ERROR_SOURCE_TABLE_HEADER);
+
+  //
+  // Populate the values of the HEST table header.
+  //
+  HestHeader.Header.Signature =
+    EFI_ACPI_6_3_HARDWARE_ERROR_SOURCE_TABLE_SIGNATURE;
+  HestHeader.Header.Revision =
+    EFI_ACPI_6_3_HARDWARE_ERROR_SOURCE_TABLE_REVISION;
+  CopyMem (
+    &HestHeader.Header.OemId,
+    FixedPcdGetPtr (PcdAcpiDefaultOemId),
+    sizeof (HestHeader.Header.OemId)
+    );
+  TempOemTableId = FixedPcdGet64 (PcdAcpiDefaultOemTableId);
+  CopyMem (
+    &HestHeader.Header.OemTableId,
+    &TempOemTableId,
+    sizeof (HestHeader.Header.OemTableId)
+    );
[SAMI] HestHeader.Header.OemTableId = FixedPcdGet64 (PcdAcpiDefaultOemTableId); ?
+  HestHeader.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
+  HestHeader.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
+  HestHeader.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
+  HestHeader.ErrorSourceCount = 0;
+  CopyMem (mHestDriverData.HestTable, &HestHeader, sizeof (HestHeader));
[SAMI] Is it possible to use a local HEST table pointer to initalise the values instead of initialising a HEST structure and then doing memcopy?
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Append HEST error source descriptor protocol service.
+
+  Protocol service used to append newly collected error source descriptors to
+  to an already created HEST table.
+
+  @param[in]  ErrorSourceDescriptorList      List of Error Source Descriptors.
+  @param[in]  ErrorSourceDescriptorListSize  Total Size of Error Source
+                                             Descriptors.
+  @param[in]  ErrorSourceDescriptorCount     Total count of error source
+                                             descriptors.
+
+  @retval  EFI_SUCCESS            Appending the error source descriptors
+                                  successful.
+  @retval  EFI_OUT_OF_RESOURCES   Buffer reallocation failed for the Hest
+                                  table.
+  @retval  EFI_INVALID_PARAMETER  Null ErrorSourceDescriptorList param or
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+AppendErrorSourceDescriptor (
+  IN CONST VOID *ErrorSourceDescriptorList,
+  IN UINTN      ErrorSourceDescriptorListSize,
+  IN UINTN      ErrorSourceDescriptorCount
+  )
+{
+  EFI_ACPI_6_3_HARDWARE_ERROR_SOURCE_TABLE_HEADER *HestHeaderPtr;
+  EFI_STATUS                                      Status;
+  UINT32                                          NewTableSize;
+  VOID                                            *ErrorDescriptorPtr;
+
+  if ((ErrorSourceDescriptorList == NULL) ||
+      (ErrorSourceDescriptorListSize == 0)) {
+     return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Create a HEST table header if not already created.
+  //
+  if (mHestDriverData.HestTable == NULL) {
+    Status = BuildHestHeader ();
+    if (Status == EFI_OUT_OF_RESOURCES) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "%a: Failed to build HEST header, status: %r\n",
+        __FUNCTION__,
+        Status
+        ));
+      return Status;
+    }
+  }
+
+  //
+  // Resize the existing HEST table buffer to accommodate the incoming error
+  // source descriptors.
+  //
+  NewTableSize = mHestDriverData.CurrentTableSize +
+                 ErrorSourceDescriptorListSize;
+  mHestDriverData.HestTable = ReallocateHestTableMemory (
+                                mHestDriverData.CurrentTableSize,
+                                NewTableSize,
+                                mHestDriverData.HestTable
+                                );
+  if (mHestDriverData.HestTable == NULL) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "%a: Failed to reallocate memory for HEST table\n",
+      __FUNCTION__
+      ));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
[SAMI] As mentioned earlier, would it be possible to maintain a link list instead of relocating the memory?
+  //
+  // Copy the incoming error source descriptors into HEST table.
+  //
+  ErrorDescriptorPtr = (VOID *)mHestDriverData.HestTable +
+                       mHestDriverData.CurrentTableSize;
+  HestHeaderPtr = (EFI_ACPI_6_3_HARDWARE_ERROR_SOURCE_TABLE_HEADER *)
+                  mHestDriverData.HestTable;
+  CopyMem (
+    ErrorDescriptorPtr,
+    ErrorSourceDescriptorList,
+    ErrorSourceDescriptorListSize
+    );
+  mHestDriverData.CurrentTableSize = NewTableSize;
+  HestHeaderPtr->Header.Length = mHestDriverData.CurrentTableSize;
+  HestHeaderPtr->ErrorSourceCount += ErrorSourceDescriptorCount;
+
+  DEBUG ((
+    DEBUG_INFO,
+    "HestDxe: %d Error source descriptor(s) added \n",
+    ErrorSourceDescriptorCount
+    ));
+  return EFI_SUCCESS;
+}
+
+/**
+  Install HEST table protocol service.
+
+  Installs the HEST table that has been appended with the error source
+  descriptors. The checksum of this table is calculated and updated in
+  the table header. The HEST table is then installed.
+
+  @retval  EFI_SUCCESS  HEST table is installed successfully.
+  @retval  EFI_ABORTED  HEST table is NULL.
+  @retval  Other        Install service call failed.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+InstallHestAcpiTable (VOID)
[SAMI] Please update according to coding standard.
+{
+  EFI_ACPI_6_3_HARDWARE_ERROR_SOURCE_TABLE_HEADER *HestHeader;
+  EFI_STATUS                                      Status;
+  UINTN                                           AcpiTableHandle;
+
+  //
+  // Check if we have valid HEST table data. If not, there no hardware error
+  // sources supported by the platform and no HEST table to publish, return.
+  //
+  if (mHestDriverData.HestTable == NULL) {
+    DEBUG ((
+      DEBUG_INFO,
+      "HestDxe: No data available to generate HEST table\n"
+      ));
+    return EFI_SUCCESS;
[SAMI] Can a suitable error code be returned here? EFI_NOT_FOUND?
+  }
+
+  //
+  // Valid data for HEST table found. Update the header checksum and install the
+  // HEST table.
+  //
+  HestHeader = (EFI_ACPI_6_3_HARDWARE_ERROR_SOURCE_TABLE_HEADER *)
+               mHestDriverData.HestTable;
+  HestHeader->Header.Checksum = CalculateCheckSum8 (
+                                  (UINT8 *)HestHeader,
+                                  HestHeader->Header.Length
+                                  );
[SAMI] Checksum calculation is not needed as ACPITableProtocol->InstallAcpiTable() does this internally.
+
+  Status = mAcpiTableProtocol->InstallAcpiTable (
+                                 mAcpiTableProtocol,
+                                 HestHeader,
+                                 HestHeader->Header.Length,
+                                 &AcpiTableHandle
+                                 );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "%a: HEST table installation failed, status: %r\n",
+      __FUNCTION__,
+      Status
+      ));
+    return Status;
+  }
+
+  //
+  // Free the HEST table buffer.
+  //
+  FreePool (mHestDriverData.HestTable);
+  DEBUG ((
+    DEBUG_INFO,
+    "HestDxe: Installed HEST table \n"
+    ));
+  return EFI_SUCCESS;
[SAMI] return Status;
+}
+
+//
+// HEST table generation protocol instance.
+//
+STATIC HEST_TABLE_PROTOCOL mHestProtocol = {
+  AppendErrorSourceDescriptor,
+  InstallHestAcpiTable
+};
[SAMI] HEST is platform and processor architecture independent. Threfore, can this implementation be paced in a common location? MdeModulePkg?
+
+/**
+  The Entry Point for HEST Dxe driver.
+
+  This function installs the HEST table creation and installation protocol
+  services.
+
+  @param[in]  ImageHandle  Handle to the Efi image.
+  @param[in]  SystemTable  A pointer to the Efi System Table.
+
+  @retval EFI_SUCCESS    On successful installation of protocol services and
+                         location the ACPI table protocol.
+  @retval Other          On Failure to locate ACPI table protocol or install
+                         of HEST table generation protocol.
+**/
+EFI_STATUS
+EFIAPI
+HestInitialize (
+  IN EFI_HANDLE       ImageHandle,
+  IN EFI_SYSTEM_TABLE *SystemTable
+  )
+{
+  EFI_HANDLE Handle = NULL;
+  EFI_STATUS Status;
+
+  Status = gBS->LocateProtocol (
+                  &gEfiAcpiTableProtocolGuid,
+                  NULL,
+                  (VOID **)&mAcpiTableProtocol
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "%a: Failed to locate ACPI table protocol, status: %r\n",
+      __FUNCTION__,
+      Status
+      ));
+    return Status;
+  }
+
+  Status = gBS->InstallProtocolInterface (
+                  &Handle,
+                  &gHestTableProtocolGuid,
+                  EFI_NATIVE_INTERFACE,
+                  &mHestProtocol
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "%a: Failed to install HEST table generation protocol status: %r\n",
+      __FUNCTION__,
+      Status
+      ));
+    return Status;
+  }
+
+  return EFI_SUCCESS;
[SAMI] return Status;
+}

Join devel@edk2.groups.io to automatically receive all group messages.