Add a new parser for the Error Injection Table (EINJ).

The EINJ table provides machinism through which OSPM
can inject hardware errors to the platform without requiring platform
specific OSPM software.

Cc: Zhiguang Liu <zhiguang....@intel.com>
Cc: Dandan Bi <dandan...@intel.com>
Cc: Liming Gao <gaolim...@byosoft.com.cn>
Cc: Zhichao Gao <zhichao....@intel.com>
Cc: Sami Mujawar <sami.muja...@arm.com>
Cc: Pierre Gondois <pierre.gond...@arm.com>
Signed-off-by: levi.yun <yeoreum....@arm.com>
---
 ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf | 
  1 +
 ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.h                    | 
 21 ++
 ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Einj/EinjParser.c       | 
358 ++++++++++++++++++++
 ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.c   | 
  1 +
 4 files changed, 381 insertions(+)

diff --git 
a/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf 
b/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf
index 
e62366116cb7d90c9202c6f0fd17b3306efd7800..9c2e2b703d267fb3ed9d631469d907106e7d4278
 100644
--- 
a/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf
+++ 
b/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf
@@ -33,6 +33,7 @@ [Sources.common]
   Parsers/Bgrt/BgrtParser.c
   Parsers/Dbg2/Dbg2Parser.c
   Parsers/Dsdt/DsdtParser.c
+  Parsers/Einj/EinjParser.c
   Parsers/Erst/ErstParser.c
   Parsers/Facs/FacsParser.c
   Parsers/Fadt/FadtParser.c
diff --git a/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.h 
b/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.h
index 
6468fe5d8cddf02d67f2d4705369064046c4a9a1..b41f110f6aa18f4f6806c849737f0b540a11152f
 100644
--- a/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.h
+++ b/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.h
@@ -616,6 +616,27 @@ ParseAcpiDsdt (
   IN UINT8    AcpiTableRevision
   );
 
+/**
+  This function parses the EINJ table.
+  When trace is enabled this function parses the EINJ table and
+  traces the ACPI table fields.
+
+  This function also performs validation of the ACPI table fields.
+
+  @param [in] Trace              If TRUE, trace the ACPI fields.
+  @param [in] Ptr                Pointer to the start of the buffer.
+  @param [in] AcpiTableLength    Length of the ACPI table.
+  @param [in] AcpiTableRevision  Revision of the ACPI table.
+**/
+VOID
+EFIAPI
+ParseAcpiEinj (
+  IN BOOLEAN  Trace,
+  IN UINT8    *Ptr,
+  IN UINT32   AcpiTableLength,
+  IN UINT8    AcpiTableRevision
+  );
+
 /**
   This function parses the ACPI ERST table.
   When trace is enabled this function parses the ERST table and
diff --git 
a/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Einj/EinjParser.c 
b/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Einj/EinjParser.c
new file mode 100644
index 
0000000000000000000000000000000000000000..508b082f908d76dc46e6ce92d9b4aa6c15998f95
--- /dev/null
+++ b/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Einj/EinjParser.c
@@ -0,0 +1,358 @@
+/** @file
+  EINJ table parser
+
+  Copyright (c) 2024, Arm Limited.
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Specification Reference:
+    - ACPI 6.5, Table 18.3.2 ACPI Error Source
+**/
+
+#include <IndustryStandard/Acpi.h>
+#include <Library/UefiLib.h>
+
+#include "AcpiParser.h"
+#include "AcpiTableParser.h"
+#include "AcpiView.h"
+
+STATIC ACPI_DESCRIPTION_HEADER_INFO  mAcpiHdrInfo;
+STATIC UINT32                        *mEinjInjectionHdrSize;
+STATIC UINT32                        *mEinjInjectionEntryCnt;
+
+STATIC CONST CHAR16  *InstNameTable[] = {
+  L"READ_REGISTER",
+  L"READ_REGISTER_VALUE",
+  L"WRITE_REGISTER",
+  L"WRITE_REGISTER_VALUE",
+  L"NOOP",
+};
+
+/**
+  This function validates the flags field in the EINJ injection header.
+
+  @param [in] Ptr     Pointer to the start of the field data.
+  @param [in] Context Pointer to context specific information e.g. this
+                      could be a pointer to the ACPI table header.
+**/
+STATIC
+VOID
+EFIAPI
+ValidateInjectionFlags (
+  IN UINT8  *Ptr,
+  IN VOID   *Context
+  )
+{
+  UINT8  Flags;
+
+  Flags = *(UINT8 *)Ptr;
+
+  if (Flags != 0) {
+    IncrementErrorCount ();
+    Print (L"\nERROR: Injection Flags must be zero...");
+  }
+}
+
+/**
+  An ACPI_PARSER array describing the ACPI EINJ Table.
+**/
+STATIC CONST ACPI_PARSER  EinjParser[] = {
+  PARSE_ACPI_HEADER (&mAcpiHdrInfo),
+  { L"Injection Header Size",       4,  36, L"%d",   NULL, (VOID 
**)&mEinjInjectionHdrSize,
+    NULL,                           NULL },
+  { L"Injection Flags",             1,  40, L"0x%x", NULL, NULL,               
             ValidateInjectionFlags,NULL },
+  { L"Reserved",                    3,  41, NULL,    NULL, NULL,               
             NULL,  NULL },
+  { L"Injection Entry Count",       4,  44, L"%d",   NULL, (VOID 
**)&mEinjInjectionEntryCnt,
+    NULL,                           NULL },
+  /// Injection Action Table.
+  /// ...
+};
+
+/**
+  This function validates the injection action field in
+  the EINJ injection instruction entry.
+
+  @param [in] Ptr     Pointer to the start of the field data.
+  @param [in] Context Pointer to context specific information e.g. this
+                      could be a pointer to the ACPI table header.
+**/
+STATIC
+VOID
+EFIAPI
+ValidateInjectionAction (
+  IN UINT8  *Ptr,
+  IN VOID   *Context
+  )
+{
+  UINT8  InjectionAction;
+  UINT8  MaxInjectionAction;
+
+  InjectionAction = *(UINT8 *)Ptr;
+
+  /**
+   * EFI_ACPI_6_5_EINJ_TRIGGER_ERROR is only used Trigger Action Table
+   * not used in Injection Action Table in EINJ.
+   * Cf ACPI 6.5 Table 18.24 - Error Injection Table
+   * Cf ACPI 6.5 Table 18.36 - Trigger Error Action
+   */
+  if (*mAcpiHdrInfo.Revision < EFI_ACPI_6_5_ERROR_INJECTION_TABLE_REVISION) {
+    MaxInjectionAction = EFI_ACPI_6_5_EINJ_GET_EXECUTE_OPERATION_TIMINGS;
+  } else {
+    MaxInjectionAction = EFI_ACPI_6_5_EINJ_EINJV2_GET_ERROR_TYPE;
+  }
+
+  if ((InjectionAction < EFI_ACPI_6_5_EINJ_BEGIN_INJECTION_OPERATION) ||
+      (InjectionAction > MaxInjectionAction))
+  {
+    IncrementErrorCount ();
+    Print (L"\nERROR: Invalid Injection Action(0x%x)...", InjectionAction);
+  }
+}
+
+/**
+  This function validates the instruction field in
+  the EINJ injection instruction entry.
+
+  @param [in] Ptr     Pointer to the start of the field data.
+  @param [in] Context Pointer to context specific information e.g. this
+                      could be a pointer to the ACPI table header.
+**/
+STATIC
+VOID
+EFIAPI
+ValidateInstruction (
+  IN UINT8  *Ptr,
+  IN VOID   *Context
+  )
+{
+  UINT8  Inst;
+
+  Inst = *Ptr;
+
+  if (*mAcpiHdrInfo.Revision <= EFI_ACPI_6_5_ERROR_INJECTION_TABLE_REVISION) {
+    if (Inst > EFI_ACPI_6_5_EINJ_NOOP) {
+      IncrementErrorCount ();
+      Print (L"\nERROR: Invalid Instruction(0x%x)...", Inst);
+    }
+  }
+}
+
+/**
+  This function validates the register region field in
+  the EINJ injection instruction entry.
+
+  @param [in] Ptr     Pointer to the start of the field data.
+  @param [in] Context Pointer to context specific information e.g. this
+                      could be a pointer to the ACPI table header.
+**/
+STATIC
+VOID
+EFIAPI
+ValidateRegisterRegion (
+  IN UINT8  *Ptr,
+  IN VOID   *Context
+  )
+{
+  EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE  *RegisterRegion;
+
+  RegisterRegion = (EFI_ACPI_6_5_GENERIC_ADDRESS_STRUCTURE *)Ptr;
+
+  if ((RegisterRegion->AddressSpaceId != EFI_ACPI_6_5_SYSTEM_MEMORY) &&
+      (RegisterRegion->AddressSpaceId != EFI_ACPI_6_5_SYSTEM_IO))
+  {
+    IncrementErrorCount ();
+    Print (L"\nERROR: Register Region Must be SYSTEM_MEMORY or SYSTEM_IO...");
+  }
+}
+
+/**
+  Dumps the injection action fields in injection instruction entry.
+
+  @param [in] Format  Optional format string for tracing the data.
+  @param [in] Ptr     Pointer to the start of the buffer.
+**/
+STATIC
+VOID
+EFIAPI
+DumpInjectionInstAction (
+  IN CONST CHAR16  *Format OPTIONAL,
+  IN UINT8         *Ptr
+  )
+{
+  UINT8         InjectionAction;
+  CONST CHAR16  *ActionName;
+
+  InjectionAction = *Ptr;
+
+  switch (InjectionAction) {
+    case EFI_ACPI_6_5_EINJ_BEGIN_INJECTION_OPERATION:
+      ActionName = L"BEGIN_INJECTION_OPERATION";
+      break;
+    case EFI_ACPI_6_5_EINJ_GET_TRIGGER_ERROR_ACTION_TABLE:
+      ActionName = L"GET_TRIGGER_ERROR_ACTION_TABLE";
+      break;
+    case EFI_ACPI_6_5_EINJ_SET_ERROR_TYPE:
+      ActionName = L"SET_ERROR_TYPE";
+      break;
+    case EFI_ACPI_6_5_EINJ_GET_ERROR_TYPE:
+      ActionName = L"GET_ERROR_TYPE";
+      break;
+    case EFI_ACPI_6_5_EINJ_END_OPERATION:
+      ActionName = L"END_OPERATION";
+      break;
+    case EFI_ACPI_6_5_EINJ_EXECUTE_OPERATION:
+      ActionName = L"EXECUTE_OPERATION";
+      break;
+    case EFI_ACPI_6_5_EINJ_CHECK_BUSY_STATUS:
+      ActionName = L"CHECK_BUSY_STATUS";
+      break;
+    case EFI_ACPI_6_5_EINJ_GET_COMMAND_STATUS:
+      ActionName = L"GET_COMMAND_STATUS";
+      break;
+    case EFI_ACPI_6_5_EINJ_SET_ERROR_TYPE_WITH_ADDRESS:
+      ActionName = L"SET_ERROR_TYPE_WITH_ADDRESS";
+      break;
+    case EFI_ACPI_6_5_EINJ_GET_EXECUTE_OPERATION_TIMINGS:
+      ActionName = L"GET_EXECUTE_OPERATION_TIMINGS";
+      break;
+    case EFI_ACPI_6_5_EINJ_EINJV2_SET_ERROR_TYPE:
+      ActionName = L"EINJV2_SET_ERROR_TYPE";
+      break;
+    case EFI_ACPI_6_5_EINJ_EINJV2_GET_ERROR_TYPE:
+      ActionName = L"EINJV2_GET_ERROR_TYPE";
+      break;
+    case EFI_ACPI_6_5_EINJ_TRIGGER_ERROR:
+      ActionName = L"TRIGGER_ERROR";
+      break;
+    default:
+      IncrementErrorCount ();
+      ActionName = L"UNKNOWN";
+  }
+
+  Print (L"%s(0x%x)", ActionName, InjectionAction);
+}
+
+/**
+  Dumps the instruction fields in injection instruction entry.
+
+  @param [in] Format  Optional format string for tracing the data.
+  @param [in] Ptr     Pointer to the start of the buffer.
+**/
+STATIC
+VOID
+EFIAPI
+DumpInstruction (
+  IN CONST CHAR16  *Format OPTIONAL,
+  IN UINT8         *Ptr
+  )
+{
+  UINT8         Inst;
+  CONST CHAR16  *InstName;
+
+  Inst = *Ptr;
+
+  if (Inst < ARRAY_SIZE (InstNameTable)) {
+    InstName = InstNameTable[Inst];
+  } else {
+    IncrementErrorCount ();
+    InstName = L"UNKNOWN";
+  }
+
+  Print (L"%s(0x%x)", InstName, Inst);
+}
+
+/**
+  An ACPI_PARSER array describing the EINJ Injection instruction entry.
+**/
+STATIC CONST ACPI_PARSER  EinjInjectionInstEntryParser[] = {
+  { L"Injection Action", 1,  0,  NULL,    DumpInjectionInstAction, NULL,
+    ValidateInjectionAction, NULL },
+  { L"Instruction",      1,  1,  NULL,    DumpInstruction,         NULL,
+    ValidateInstruction, NULL },
+  { L"Flags",            1,  2,  L"0x%x", NULL,                    NULL,NULL,  
NULL },
+  { L"Reserved",         1,  3,  NULL,    NULL,                    NULL,NULL,  
NULL },
+  { L"Register Region",  12, 4,  NULL,    DumpGas,                 NULL,
+    ValidateRegisterRegion, NULL },
+  { L"Value",            8,  16, L"0x%x", NULL,                    NULL,NULL,  
NULL },
+  { L"Mask",             8,  24, L"0x%x", NULL,                    NULL,NULL,  
NULL },
+};
+
+/**
+  This function parses the EINJ table.
+  When trace is enabled this function parses the EINJ table and
+  traces the ACPI table fields.
+
+  This function also performs validation of the ACPI table fields.
+
+  @param [in] Trace              If TRUE, trace the ACPI fields.
+  @param [in] Ptr                Pointer to the start of the buffer.
+  @param [in] AcpiTableLength    Length of the ACPI table.
+  @param [in] AcpiTableRevision  Revision of the ACPI table.
+**/
+VOID
+EFIAPI
+ParseAcpiEinj (
+  IN BOOLEAN  Trace,
+  IN UINT8    *Ptr,
+  IN UINT32   AcpiTableLength,
+  IN UINT8    AcpiTableRevision
+  )
+{
+  UINT32  Offset;
+  UINT8   *InjInstEntryPtr;
+  UINT32  InjInstEntrySize;
+
+  if (!Trace) {
+    return;
+  }
+
+  Offset = ParseAcpi (
+             TRUE,
+             0,
+             "EINJ",
+             Ptr,
+             AcpiTableLength,
+             PARSER_PARAMS (EinjParser)
+             );
+
+  // Validate Error Source Descriptors Count.
+  if ((mEinjInjectionHdrSize == NULL) || (*mEinjInjectionHdrSize != Offset)) {
+    IncrementErrorCount ();
+    Print (L"ERROR: Invalid Injection Header...\n");
+    return;
+  }
+
+  if ((mEinjInjectionEntryCnt == NULL) || (*mEinjInjectionEntryCnt == 0)) {
+    IncrementErrorCount ();
+    Print (L"ERROR: Injection Instruction Entry should be presented...\n");
+    return;
+  }
+
+  InjInstEntrySize = sizeof (EFI_ACPI_6_5_EINJ_INJECTION_INSTRUCTION_ENTRY);
+
+  if ((*mEinjInjectionEntryCnt * InjInstEntrySize) != (AcpiTableLength - 
Offset)) {
+    IncrementErrorCount ();
+    Print (
+      L"ERROR: Incorrect count for Injection Instruction Entry.\n" \
+      L"       Injection Entry Count= %d.\n" \
+      L"       Present Count= %d.\n",
+      *mEinjInjectionEntryCnt,
+      (AcpiTableLength - Offset) / InjInstEntrySize
+      );
+  }
+
+  while (Offset < AcpiTableLength) {
+    InjInstEntryPtr = Ptr + Offset;
+
+    // Get Injection Instruction Entry.
+    ParseAcpi (
+      TRUE,
+      2,
+      "Injection Instruction Entry",
+      InjInstEntryPtr,
+      AcpiTableLength - Offset,
+      PARSER_PARAMS (EinjInjectionInstEntryParser)
+      );
+
+    Offset += InjInstEntrySize;
+  } // while
+}
diff --git 
a/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.c 
b/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.c
index 
0bdf068fe07614727e690897d9c76a5686be18b5..4a90372d81ff1eb2caeb3a477d058d08ffc1bdbf
 100644
--- a/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.c
+++ b/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.c
@@ -54,6 +54,7 @@ ACPI_TABLE_PARSER  ParserList[] = {
   { EFI_ACPI_6_2_DEBUG_PORT_2_TABLE_SIGNATURE,                                 
                          ParseAcpiDbg2 },
   { EFI_ACPI_6_2_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE,
     ParseAcpiDsdt },
+  { EFI_ACPI_6_5_ERROR_INJECTION_TABLE_SIGNATURE,                              
                          ParseAcpiEinj },
   { EFI_ACPI_6_4_ERROR_RECORD_SERIALIZATION_TABLE_SIGNATURE,                   
                          ParseAcpiErst },
   { EFI_ACPI_6_3_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE,                    
                          ParseAcpiFacs },
   { EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE,                       
                          ParseAcpiFadt },
--
Guid("CE165669-3EF3-493F-B85D-6190EE5B9759")



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#118818): https://edk2.groups.io/g/devel/message/118818
Mute This Topic: https://groups.io/mt/106019474/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-


Reply via email to