ShellPkg: AcpiView: Add parser support for SPCR Revision 4

Revision 4 adds fields for UART clock frequency, precise baud rate and ACPI
object namespace string. The revision 4 specification is at
https://learn.microsoft.com/en-us/windows-hardware/drivers/bringup/serial-port-console-redirection-table

Signed-off-by: Sarah Walker <Sarah.Walker2@arm.com>
diff --git a/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Spcr/SpcrParser.c b/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Spcr/SpcrParser.c
index d172a55..db44de1 100644
--- a/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Spcr/SpcrParser.c
+++ b/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Spcr/SpcrParser.c
@@ -18,6 +18,9 @@
 // Local variables

 STATIC ACPI_DESCRIPTION_HEADER_INFO  AcpiHdrInfo;

 

+STATIC UINT16  *NamespaceStringLength;

+STATIC UINT16  *NamespaceStringOffset;

+

 /**

   This function validates the Interrupt Type.

 

@@ -87,31 +90,65 @@
 }

 

 /**

+  This function validates the NameSpace string length.

+

+  @param [in] Ptr     Pointer to the start of the buffer.

+  @param [in] Length  Length of the field.

+  @param [in] Context Pointer to context specific information e.g. this

+                      could be a pointer to the ACPI table header.

+**/

+STATIC

+VOID

+EFIAPI

+ValidateNameSpaceStrLen (

+  IN UINT8   *Ptr,

+  IN UINT32  Length,

+  IN VOID    *Context

+  )

+{

+  UINT16  NameSpaceStrLen;

+

+  NameSpaceStrLen = *(UINT16 *)Ptr;

+

+  if (NameSpaceStrLen < 2) {

+    IncrementErrorCount ();

+    Print (

+      L"\nERROR: NamespaceString Length = %d. If no Namespace device exists, " \

+      L"NamespaceString[] must contain a period '.'",

+      NameSpaceStrLen

+      );

+  }

+}

+

+/**

   An ACPI_PARSER array describing the ACPI SPCR Table.

 **/

 STATIC CONST ACPI_PARSER  SpcrParser[] = {

   PARSE_ACPI_HEADER (&AcpiHdrInfo),

-  { L"Interface Type",             1,   36, L"%d",       NULL,       NULL, NULL,                  NULL },

-  { L"Reserved",                   3,   37, L"%x %x %x", Dump3Chars, NULL, NULL,                  NULL },

-  { L"Base Address",               12,  40, NULL,        DumpGas,    NULL, NULL,                  NULL },

-  { L"Interrupt Type",             1,   52, L"%d",       NULL,       NULL, ValidateInterruptType, NULL },

-  { L"IRQ",                        1,   53, L"%d",       NULL,       NULL, ValidateIrq,           NULL },

-  { L"Global System Interrupt",    4,   54, L"0x%x",     NULL,       NULL, NULL,                  NULL },

-  { L"Baud Rate",                  1,   58, L"%d",       NULL,       NULL, NULL,                  NULL },

-  { L"Parity",                     1,   59, L"%d",       NULL,       NULL, NULL,                  NULL },

-  { L"Stop Bits",                  1,   60, L"%d",       NULL,       NULL, NULL,                  NULL },

-  { L"Flow Control",               1,   61, L"0x%x",     NULL,       NULL, NULL,                  NULL },

-  { L"Terminal Type",              1,   62, L"%d",       NULL,       NULL, NULL,                  NULL },

-  { L"Reserved",                   1,   63, L"%x",       NULL,       NULL, NULL,                  NULL },

+  { L"Interface Type",             1,   36, L"%d",       NULL,       NULL,                            NULL,                    NULL },

+  { L"Reserved",                   3,   37, L"%x %x %x", Dump3Chars, NULL,                            NULL,                    NULL },

+  { L"Base Address",               12,  40, NULL,        DumpGas,    NULL,                            NULL,                    NULL },

+  { L"Interrupt Type",             1,   52, L"%d",       NULL,       NULL,                            ValidateInterruptType,   NULL },

+  { L"IRQ",                        1,   53, L"%d",       NULL,       NULL,                            ValidateIrq,             NULL },

+  { L"Global System Interrupt",    4,   54, L"0x%x",     NULL,       NULL,                            NULL,                    NULL },

+  { L"Baud Rate",                  1,   58, L"%d",       NULL,       NULL,                            NULL,                    NULL },

+  { L"Parity",                     1,   59, L"%d",       NULL,       NULL,                            NULL,                    NULL },

+  { L"Stop Bits",                  1,   60, L"%d",       NULL,       NULL,                            NULL,                    NULL },

+  { L"Flow Control",               1,   61, L"0x%x",     NULL,       NULL,                            NULL,                    NULL },

+  { L"Terminal Type",              1,   62, L"%d",       NULL,       NULL,                            NULL,                    NULL },

+  { L"Reserved",                   1,   63, L"%x",       NULL,       NULL,                            NULL,                    NULL },

 

-  { L"PCI Device ID",              2,   64, L"0x%x",     NULL,       NULL, NULL,                  NULL },

-  { L"PCI Vendor ID",              2,   66, L"0x%x",     NULL,       NULL, NULL,                  NULL },

-  { L"PCI Bus Number",             1,   68, L"0x%x",     NULL,       NULL, NULL,                  NULL },

-  { L"PCI Device Number",          1,   69, L"0x%x",     NULL,       NULL, NULL,                  NULL },

-  { L"PCI Function Number",        1,   70, L"0x%x",     NULL,       NULL, NULL,                  NULL },

-  { L"PCI Flags",                  4,   71, L"0x%x",     NULL,       NULL, NULL,                  NULL },

-  { L"PCI Segment",                1,   75, L"0x%x",     NULL,       NULL, NULL,                  NULL },

-  { L"Reserved",                   4,   76, L"%x",       NULL,       NULL, NULL,                  NULL }

+  { L"PCI Device ID",              2,   64, L"0x%x",     NULL,       NULL,                            NULL,                    NULL },

+  { L"PCI Vendor ID",              2,   66, L"0x%x",     NULL,       NULL,                            NULL,                    NULL },

+  { L"PCI Bus Number",             1,   68, L"0x%x",     NULL,       NULL,                            NULL,                    NULL },

+  { L"PCI Device Number",          1,   69, L"0x%x",     NULL,       NULL,                            NULL,                    NULL },

+  { L"PCI Function Number",        1,   70, L"0x%x",     NULL,       NULL,                            NULL,                    NULL },

+  { L"PCI Flags",                  4,   71, L"0x%x",     NULL,       NULL,                            NULL,                    NULL },

+  { L"PCI Segment",                1,   75, L"0x%x",     NULL,       NULL,                            NULL,                    NULL },

+  { L"UART Clock Frequency",       4,   76, L"%d",       NULL,       NULL,                            NULL,                    NULL },

+  { L"Precise Baud Rate",          4,   80, L"%d",       NULL,       NULL,                            NULL,                    NULL },

+  { L"Namespace String Length",    2,   84, L"%x",       NULL,       (VOID **)&NamespaceStringLength, ValidateNameSpaceStrLen, NULL },

+  { L"Namespace String Offset",    2,   86, L"%x",       NULL,       (VOID **)&NamespaceStringOffset, NULL,                    NULL }

 };

 

 /**

@@ -135,6 +172,9 @@
   IN UINT8    AcpiTableRevision

   )

 {

+  UINT16  Index;

+  UINT16  Offset;

+

   if (!Trace) {

     return;

   }

@@ -148,4 +188,29 @@
     AcpiTableLength,

     PARSER_PARAMS (SpcrParser)

     );

+

+  if (*AcpiHdrInfo.Revision >= EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_REVISION_4) {

+    if ((*NamespaceStringOffset >= AcpiTableLength) ||

+        ((UINT32)(*NamespaceStringOffset + *NamespaceStringLength) > AcpiTableLength))

+    {

+      IncrementErrorCount ();

+      Print (

+        L"ERROR: Invalid Namespace String. AcpiTableLength = %d, NamespaceStringOffset = %d, NamespaceStringLength = %d\n",

+        AcpiTableLength,

+        *NamespaceStringOffset,

+        *NamespaceStringLength

+        );

+      return;

+    }

+

+    Index  = 0;

+    Offset = *NamespaceStringOffset;

+    PrintFieldName (4, L"Namespace String");

+    while ((Index++ < *NamespaceStringLength) &&

+           ((UINT32)Offset < AcpiTableLength))

+    {

+      Print (L"%c", *(Ptr + Offset));

+      Offset++;

+    }

+  }

 }