--- /dev/null
+/** @file\r
+ ERST table parser\r
+\r
+ Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.\r
+ Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+ @par Reference(s):\r
+ - ACPI 6.5 Specification - August 2022\r
+**/\r
+\r
+#include <IndustryStandard/Acpi.h>\r
+#include <Library/UefiLib.h>\r
+#include "AcpiParser.h"\r
+#include "AcpiTableParser.h"\r
+\r
+// Local variables\r
+STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo;\r
+STATIC UINT32 *InstructionEntryCount;\r
+\r
+/**\r
+ An array of strings describing the Erst actions\r
+**/\r
+STATIC CONST CHAR16 *ErstActionTable[] = {\r
+ L"BEGIN_WRITE_OPERATION",\r
+ L"BEGIN_READ_OPERATION",\r
+ L"BEGIN_CLEAR_OPERATION",\r
+ L"END_OPERATION",\r
+ L"SET_RECORD_OFFSET",\r
+ L"EXECUTE_OPERATION",\r
+ L"CHECK_BUSY_STATUS",\r
+ L"GET_COMMAND_STATUS",\r
+ L"GET_RECORD_IDENTIFIER",\r
+ L"SET_RECORD_IDENTIFIER",\r
+ L"GET_RECORD_COUNT",\r
+ L"BEGIN_DUMMY_WRITE_OPERATION",\r
+ L"RESERVED",\r
+ L"GET_ERROR_LOG_ADDRESS_RANGE",\r
+ L"GET_ERROR_LOG_ADDRESS_RANGE_LENGTH",\r
+ L"GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES",\r
+ L"GET_EXECUTE_OPERATION_TIMINGS"\r
+};\r
+\r
+/**\r
+ An array of strings describing the Erst instructions\r
+**/\r
+STATIC CONST CHAR16 *ErstInstructionTable[] = {\r
+ L"READ_REGISTER",\r
+ L"READ_REGISTER_VALUE",\r
+ L"WRITE_REGISTER",\r
+ L"WRITE_REGISTER_VALUE",\r
+ L"NOOP",\r
+ L"LOAD_VAR1",\r
+ L"LOAD_VAR2",\r
+ L"STORE_VAR1",\r
+ L"ADD",\r
+ L"SUBTRACT",\r
+ L"ADD_VALUE",\r
+ L"SUBTRACT_VALUE",\r
+ L"STALL",\r
+ L"STALL_WHILE_TRUE",\r
+ L"SKIP_NEXT_INSTRUCTION_IF_TRUE",\r
+ L"GOTO",\r
+ L"SET_SRC_ADDRESS_BASE",\r
+ L"SET_DST_ADDRESS_BASE",\r
+ L"MOVE_DATA"\r
+};\r
+\r
+/**\r
+ Validate Erst action.\r
+\r
+ @param [in] Ptr Pointer to the start of the field data.\r
+ @param [in] Context Pointer to context specific information e.g. this\r
+ could be a pointer to the ACPI table header.\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+ValidateErstAction (\r
+ IN UINT8 *Ptr,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ if (*Ptr > EFI_ACPI_6_4_ERST_GET_EXECUTE_OPERATION_TIMINGS) {\r
+ IncrementErrorCount ();\r
+ Print (L"\nError: 0x%02x is not a valid action encoding", *Ptr);\r
+ }\r
+}\r
+\r
+/**\r
+ Validate Erst instruction.\r
+\r
+ @param [in] Ptr Pointer to the start of the field data.\r
+ @param [in] Context Pointer to context specific information e.g. this\r
+ could be a pointer to the ACPI table header.\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+ValidateErstInstruction (\r
+ IN UINT8 *Ptr,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ if (*Ptr > EFI_ACPI_6_4_ERST_MOVE_DATA) {\r
+ IncrementErrorCount ();\r
+ Print (L"\nError: 0x%02x is not a valid instruction encoding", *Ptr);\r
+ }\r
+}\r
+\r
+/**\r
+ Validate Erst flags.\r
+\r
+ @param [in] Ptr Pointer to the start of the field data.\r
+ @param [in] Context Pointer to context specific information e.g. this\r
+ could be a pointer to the ACPI table header.\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+ValidateErstFlags (\r
+ IN UINT8 *Ptr,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ if ((*Ptr & 0xfe) != 0) {\r
+ IncrementErrorCount ();\r
+ Print (L"\nError: Reserved Flag bits not set to 0");\r
+ }\r
+}\r
+\r
+/**\r
+ Looks up and prints the string corresponding to the index.\r
+\r
+ @param [in] Table Lookup table.\r
+ @param [in] Index Entry to print.\r
+ @param [in] NumEntries Number of valid entries in the table.\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+FormatByte (\r
+ IN CONST CHAR16 *Table[],\r
+ IN UINT8 Index,\r
+ IN UINT8 NumEntries\r
+ )\r
+{\r
+ CONST CHAR16 *String;\r
+\r
+ if (Index < NumEntries) {\r
+ String = Table[Index];\r
+ } else {\r
+ String = L"**INVALID**";\r
+ }\r
+\r
+ Print (\r
+ L"0x%02x (%s)",\r
+ Index,\r
+ String\r
+ );\r
+}\r
+\r
+/**\r
+ Prints the Erst Action.\r
+\r
+ @param [in] Format Optional format string for tracing the data.\r
+ @param [in] Ptr Pointer to the Action byte.\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+DumpErstAction (\r
+ IN CONST CHAR16 *Format OPTIONAL,\r
+ IN UINT8 *Ptr\r
+ )\r
+{\r
+ FormatByte (ErstActionTable, *Ptr, ARRAY_SIZE (ErstActionTable));\r
+}\r
+\r
+/**\r
+ Prints the Erst Instruction.\r
+\r
+ @param [in] Format Optional format string for tracing the data.\r
+ @param [in] Ptr Pointer to the Instruction byte.\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+DumpErstInstruction (\r
+ IN CONST CHAR16 *Format OPTIONAL,\r
+ IN UINT8 *Ptr\r
+ )\r
+{\r
+ FormatByte (ErstInstructionTable, *Ptr, ARRAY_SIZE (ErstInstructionTable));\r
+}\r
+\r
+/**\r
+ An ACPI_PARSER array describing the ACPI ERST Table.\r
+**/\r
+STATIC CONST ACPI_PARSER ErstParser[] = {\r
+ PARSE_ACPI_HEADER (&AcpiHdrInfo),\r
+ { L"Serialization Header Size", 4, 36, L"0x%x", NULL, NULL, NULL, NULL },\r
+ { L"Reserved", 4, 40, L"0x%x", NULL, NULL, NULL, NULL },\r
+ { L"Instruction Entry Count", 4, 44, L"0x%x", NULL, (VOID **)&InstructionEntryCount, NULL, NULL }\r
+};\r
+\r
+/**\r
+ An ACPI_PARSER array describing the Serialization Instruction Entry structure.\r
+**/\r
+STATIC CONST ACPI_PARSER SerializationInstructionEntryParser[] = {\r
+ { L"Serialization Action", 1, 0, L"0x%x", DumpErstAction, NULL, ValidateErstAction, NULL },\r
+ { L"Instruction", 1, 1, L"0x%x", DumpErstInstruction, NULL, ValidateErstInstruction, NULL },\r
+ { L"Flags", 1, 2, L"0x%x", NULL, NULL, ValidateErstFlags, NULL },\r
+ { L"Reserved", 1, 3, L"0x%x", NULL, NULL, NULL, NULL },\r
+ { L"Register Region", 12, 4, NULL, DumpGas, NULL, NULL, NULL },\r
+ { L"Value", 8, 16, L"0x%llx", NULL, NULL, NULL, NULL },\r
+ { L"Mask", 8, 24, L"0x%llx", NULL, NULL, NULL, NULL }\r
+};\r
+\r
+/**\r
+ This function parses the ACPI ERST table.\r
+ When trace is enabled this function parses the ERST table and\r
+ traces the ACPI table fields.\r
+\r
+ This function also performs validation of the ACPI table fields.\r
+\r
+ @param [in] Trace If TRUE, trace the ACPI fields.\r
+ @param [in] Ptr Pointer to the start of the buffer.\r
+ @param [in] AcpiTableLength Length of the ACPI table.\r
+ @param [in] AcpiTableRevision Revision of the ACPI table.\r
+**/\r
+VOID\r
+EFIAPI\r
+ParseAcpiErst (\r
+ IN BOOLEAN Trace,\r
+ IN UINT8 *Ptr,\r
+ IN UINT32 AcpiTableLength,\r
+ IN UINT8 AcpiTableRevision\r
+ )\r
+{\r
+ UINT32 Offset;\r
+\r
+ if (!Trace) {\r
+ return;\r
+ }\r
+\r
+ Offset = ParseAcpi (\r
+ Trace,\r
+ 0,\r
+ "ERST",\r
+ Ptr,\r
+ AcpiTableLength,\r
+ PARSER_PARAMS (ErstParser)\r
+ );\r
+\r
+ if (sizeof (EFI_ACPI_6_4_ERST_SERIALIZATION_INSTRUCTION_ENTRY)*(*InstructionEntryCount) != (AcpiTableLength - Offset)) {\r
+ IncrementErrorCount ();\r
+ Print (\r
+ L"ERROR: Invalid InstructionEntryCount. " \\r
+ L"Count = %d. Offset = %d. AcpiTableLength = %d.\n",\r
+ *InstructionEntryCount,\r
+ Offset,\r
+ AcpiTableLength\r
+ );\r
+ return;\r
+ }\r
+\r
+ while (Offset < AcpiTableLength) {\r
+ Offset += ParseAcpi (\r
+ Trace,\r
+ 2,\r
+ "Serialization Action",\r
+ Ptr + Offset,\r
+ (AcpiTableLength - Offset),\r
+ PARSER_PARAMS (SerializationInstructionEntryParser)\r
+ );\r
+ }\r
+}\r