Date   

[PATCH v2 2/2] ShellPkg/Acpiview: AEST Parser

Sami Mujawar
 

From: Marc Moisson-Franckhauser <marc.moisson-franckhauser@arm.com>

Add a new parser for the Arm Error Source Table (AEST) described in
the ACPI for the Armv8 RAS Extensions 1.1 Platform Design Document,
dated 28 September 2020.
(https://developer.arm.com/documentation/den0085/0101/)

AEST enables kernel-first handling of errors in a system that supports
the Armv8 RAS extensions. It covers Armv8.2+ RAS extensions for PEs
and the RAS system architecture for non-PE system components.

Signed-off-by: Marc Moisson-Franckhauser <marc.moisson-franckhauser@arm.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
---

Notes:
v2:
- Minor update to include ArmErrorSourceTable.h to obtain [SAMI]
the AEST signature macro definition.

ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.h | 21 +
ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiTableParser.h | 4 +-
ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Aest/AestParser.c | 755 ++++++++++++++++++++
ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.c | 4 +-
ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf | 3 +-
ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.uni | 3 +-
6 files changed, 785 insertions(+), 5 deletions(-)

diff --git a/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.h b/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.h
index f81ccac7e118378aa185db4b625e5bcd75f78347..41acd77b1890b6f8efea823843d43220dea63f67 100644
--- a/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.h
+++ b/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.h
@@ -462,6 +462,27 @@ ParseAcpiHeader (
);

/**
+ This function parses the ACPI AEST table.
+ When trace is enabled this function parses the AEST 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
+ParseAcpiAest (
+ IN BOOLEAN Trace,
+ IN UINT8* Ptr,
+ IN UINT32 AcpiTableLength,
+ IN UINT8 AcpiTableRevision
+ );
+
+/**
This function parses the ACPI BGRT table.
When trace is enabled this function parses the BGRT table and
traces the ACPI table fields.
diff --git a/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiTableParser.h b/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiTableParser.h
index 4f92596b90a6ee422d8d0959881015ffd3de4da0..0ebf79fb653ae3a8190273aee452723c6213eb58 100644
--- a/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiTableParser.h
+++ b/ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiTableParser.h
@@ -1,7 +1,7 @@
/** @file
Header file for ACPI table parser

- Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.
+ Copyright (c) 2016 - 2020, Arm Limited. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/

@@ -11,7 +11,7 @@
/**
The maximum number of ACPI table parsers.
*/
-#define MAX_ACPI_TABLE_PARSERS 16
+#define MAX_ACPI_TABLE_PARSERS 32

/** An invalid/NULL signature value.
*/
diff --git a/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Aest/AestParser.c b/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Aest/AestParser.c
new file mode 100644
index 0000000000000000000000000000000000000000..7aa8c8fd2167822f4f5e0f6e4067195aac510e5c
--- /dev/null
+++ b/ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Aest/AestParser.c
@@ -0,0 +1,755 @@
+/** @file
+ AEST table parser
+
+ Copyright (c) 2020, Arm Limited.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - ACPI for the Armv8 RAS Extensions 1.1 Platform Design Document,
+ dated 28 September 2020.
+ (https://developer.arm.com/documentation/den0085/0101/)
+**/
+
+#include <Library/PrintLib.h>
+#include <Library/UefiLib.h>
+#include <IndustryStandard/ArmErrorSourceTable.h>
+#include "AcpiParser.h"
+#include "AcpiView.h"
+#include "AcpiViewConfig.h"
+
+// Local variables
+STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo;
+STATIC UINT8* AestNodeType;
+STATIC UINT16* AestNodeLength;
+STATIC UINT32* NodeDataOffset;
+STATIC UINT32* NodeInterfaceOffset;
+STATIC UINT32* NodeInterruptArrayOffset;
+STATIC UINT32* NodeInterruptCount;
+STATIC UINT32* ProcessorId;
+STATIC UINT8* ProcessorFlags;
+STATIC UINT8* ProcessorResourceType;
+
+/**
+ Validate Processor Flags.
+
+ @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
+ValidateProcessorFlags (
+ IN UINT8* Ptr,
+ IN VOID* Context
+ )
+{
+ // If the global or shared node flag is set then the ACPI Processor ID
+ // field must be set to 0 and ignored.
+ if (((*Ptr & 0x3) != 0) && (*ProcessorId != 0)) {
+ IncrementErrorCount ();
+ Print (L"\nERROR: 'ACPI Processor ID' field must be set to 0 for global"
+ L" or shared nodes.");
+ }
+}
+
+/**
+ Validate GIC Interface Type.
+
+ @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
+ValidateGicInterfaceType (
+ IN UINT8* Ptr,
+ IN VOID* Context
+ )
+{
+ UINT32 GicInterfaceType;
+
+ GicInterfaceType = *(UINT32*)Ptr;
+ if (GicInterfaceType > 3) {
+ IncrementErrorCount ();
+ Print (L"\nError: Invalid GIC Interface type %d", GicInterfaceType);
+ }
+}
+
+/**
+ Validate Interface Type.
+
+ @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
+ValidateInterfaceType (
+ IN UINT8* Ptr,
+ IN VOID* Context
+ )
+{
+ if (*Ptr > 1) {
+ IncrementErrorCount ();
+ Print (L"\nError: Interface type should be 0 or 1");
+ }
+}
+
+/**
+ Validate Interrupt Type.
+
+ @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
+ValidateInterruptType (
+ IN UINT8* Ptr,
+ IN VOID* Context
+ )
+{
+ if (*Ptr > 1) {
+ IncrementErrorCount ();
+ Print (L"\nError: Interrupt type should be 0 or 1");
+ }
+}
+
+/**
+ Validate interrupt flags.
+
+ @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
+ValidateInterruptFlags (
+ IN UINT8* Ptr,
+ IN VOID* Context
+ )
+{
+ if ((*Ptr & 0xfe) != 0) {
+ IncrementErrorCount ();
+ Print (L"\nError: Reserved Flag bits not set to 0");
+ }
+}
+
+/**
+ Dumps 16 bytes of data.
+
+ @param [in] Format Optional format string for tracing the data.
+ @param [in] Ptr Pointer to the start of the buffer.
+**/
+VOID
+EFIAPI
+DumpVendorSpecificData (
+ IN CONST CHAR16* Format OPTIONAL,
+ IN UINT8* Ptr
+ )
+{
+ Print (
+ L"%02X %02X %02X %02X %02X %02X %02X %02X\n",
+ Ptr[0],
+ Ptr[1],
+ Ptr[2],
+ Ptr[3],
+ Ptr[4],
+ Ptr[5],
+ Ptr[6],
+ Ptr[7]
+ );
+
+ Print (
+ L"%*a %02X %02X %02X %02X %02X %02X %02X %02X",
+ OUTPUT_FIELD_COLUMN_WIDTH,
+ "",
+ Ptr[8],
+ Ptr[9],
+ Ptr[10],
+ Ptr[11],
+ Ptr[12],
+ Ptr[13],
+ Ptr[14],
+ Ptr[15]
+ );
+}
+
+/**
+ An ACPI_PARSER array describing the ACPI AEST Table.
+**/
+STATIC CONST ACPI_PARSER AestParser[] = {
+ PARSE_ACPI_HEADER (&AcpiHdrInfo)
+};
+
+/**
+ An ACPI_PARSER array describing the AEST Node Header.
+**/
+STATIC CONST ACPI_PARSER AestNodeHeaderParser[] = {
+ {L"Type", 1, 0, L"%d", NULL, (VOID**)&AestNodeType, NULL, NULL},
+ {L"Length", 2, 1, L"%d", NULL, (VOID**)&AestNodeLength, NULL, NULL},
+ {L"Reserved", 1, 3, L"0x%x", NULL, NULL, NULL, NULL},
+ {L"Node Data Offset", 4, 4, L"%d", NULL, (VOID**)&NodeDataOffset, NULL, NULL},
+ {L"Node Interface Offset", 4, 8, L"%d", NULL,
+ (VOID**)&NodeInterfaceOffset, NULL, NULL},
+ {L"Node Interrupt Array Offset", 4, 12, L"%d", NULL,
+ (VOID**)&NodeInterruptArrayOffset, NULL, NULL},
+ {L"Node Interrupt Count", 4, 16, L"%d", NULL,
+ (VOID**)&NodeInterruptCount, NULL, NULL},
+ {L"Timestamp Rate", 8, 20, L"%ld", NULL, NULL, NULL, NULL},
+ {L"Reserved1", 8, 28, L"0x%lx", NULL, NULL, NULL, NULL},
+ {L"Error Injection Countdown Rate", 8, 36, L"%ld", NULL, NULL, NULL, NULL}
+ // Node specific data...
+ // Node interface...
+ // Node interrupt array...
+};
+
+/**
+ An ACPI_PARSER array describing the Processor error node specific data.
+**/
+STATIC CONST ACPI_PARSER AestProcessorStructure[] = {
+ {L"ACPI Processor ID", 4, 0, L"0x%x", NULL, (VOID**)&ProcessorId, NULL, NULL},
+ {L"Resource Type", 1, 4, L"%d", NULL, (VOID**)&ProcessorResourceType, NULL,
+ NULL},
+ {L"Reserved", 1, 5, L"0x%x", NULL, NULL, NULL, NULL},
+ {L"Flags", 1, 6, L"0x%x", NULL, (VOID**)&ProcessorFlags,
+ ValidateProcessorFlags, NULL},
+ {L"Revision", 1, 7, L"%d", NULL, NULL, NULL, NULL},
+ {L"Processor Affinity Level Indicator", 8, 8, L"0x%lx", NULL, NULL, NULL,
+ NULL},
+ // Resource specific data...
+};
+
+/**
+ An ACPI_PARSER array describing the processor cache resource substructure.
+**/
+STATIC CONST ACPI_PARSER AestProcessorCacheResourceSubstructure[] = {
+ {L"Cache reference ID", 4, 0, L"0x%x", NULL, NULL, NULL, NULL},
+ {L"Reserved", 4, 4, L"%d", NULL, NULL, NULL, NULL}
+};
+
+/**
+ An ACPI_PARSER array describing the processor TLB resource substructure.
+**/
+STATIC CONST ACPI_PARSER AestProcessorTlbResourceSubstructure[] = {
+ {L"TLB reference ID", 4, 0, L"0x%x", NULL, NULL, NULL, NULL},
+ {L"Reserved", 4, 4, L"%d", NULL, NULL, NULL, NULL}
+};
+
+/**
+ An ACPI_PARSER array describing the processor generic resource substructure.
+**/
+STATIC CONST ACPI_PARSER AestProcessorGenericResourceSubstructure[] = {
+ {L"Vendor-defined data", 4, 0, L"%x", NULL, NULL, NULL, NULL}
+};
+
+/**
+ An ACPI_PARSER array describing the memory controller structure.
+**/
+STATIC CONST ACPI_PARSER AestMemoryControllerStructure[] = {
+ {L"Proximity Domain", 4, 0, L"0x%x", NULL, NULL, NULL, NULL}
+};
+
+/**
+ An ACPI_PARSER array describing the SMMU structure.
+**/
+STATIC CONST ACPI_PARSER AestSmmuStructure[] = {
+ {L"IORT Node reference ID", 4, 0, L"0x%x", NULL, NULL, NULL, NULL},
+ {L"SubComponent reference ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL}
+};
+
+/**
+ An ACPI_PARSER array describing the vendor-defined structure.
+**/
+STATIC CONST ACPI_PARSER AestVendorDefinedStructure[] = {
+ {L"Hardware ID", 4, 0, L"0x%x", NULL, NULL, NULL, NULL},
+ {L"Unique ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL},
+ {L"Vendor-specific data", 16, 8, NULL, DumpVendorSpecificData, NULL, NULL}
+};
+
+/**
+ An ACPI_PARSER array describing the GIC structure.
+**/
+STATIC CONST ACPI_PARSER AestGicStructure[] = {
+ {L"GIC Interface Type", 4, 0, L"0x%x", NULL, NULL, ValidateGicInterfaceType,
+ NULL},
+ {L"GIC Interface reference ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL}
+};
+
+/**
+ An ACPI_PARSER array describing the node interface.
+**/
+STATIC CONST ACPI_PARSER AestNodeInterface[] = {
+ {L"Interface Type", 1, 0, L"%d", NULL, NULL, ValidateInterfaceType, NULL},
+ {L"Reserved", 3, 1, L"%x %x %x", Dump3Chars, NULL, NULL, NULL},
+ {L"Flags", 4, 4, L"0x%x", NULL, NULL, NULL, NULL},
+ {L"Base Address", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL},
+ {L"Start Error Record Index", 4, 16, L"0x%x", NULL, NULL, NULL, NULL},
+ {L"Number of Error Records", 4, 20, L"0x%x", NULL, NULL, NULL, NULL},
+ {L"Error Records Implemented", 8, 24, L"0x%lx", NULL, NULL, NULL, NULL},
+ {L"Error Records Support", 8, 32, L"0x%lx", NULL, NULL, NULL, NULL},
+ {L"Addressing mode", 8, 40, L"0x%lx", NULL, NULL, NULL, NULL}
+};
+
+/**
+ An ACPI_PARSER array describing the node interrupts.
+**/
+STATIC CONST ACPI_PARSER AestNodeInterrupt[] = {
+ {L"Interrupt Type", 1, 0, L"%d", NULL, NULL, ValidateInterruptType, NULL},
+ {L"Reserved", 2, 1, L"0x%x", NULL, NULL, NULL, NULL},
+ {L"Interrupt Flags", 1, 3, L"0x%x", NULL, NULL, ValidateInterruptFlags, NULL},
+ {L"Interrupt GSIV", 4, 4, L"0x%x", NULL, NULL, NULL, NULL},
+ {L"ID", 1, 8, L"0x%x", NULL, NULL, NULL, NULL},
+ {L"Reserved1", 3, 9, L"%x %x %x", Dump3Chars, NULL, NULL, NULL}
+};
+
+/**
+ Parses the Processor Error Node structure along with its resource
+ specific data.
+
+ @param [in] Ptr Pointer to the start of the Processor node.
+ @param [in] Length Maximum length of the Processor node.
+**/
+STATIC
+VOID
+DumpProcessorNode (
+ IN UINT8* Ptr,
+ IN UINT32 Length
+ )
+{
+ UINT32 Offset;
+
+ Offset = ParseAcpi (
+ TRUE,
+ 2,
+ "Processor",
+ Ptr,
+ Length,
+ PARSER_PARAMS (AestProcessorStructure)
+ );
+
+ // Check if the values used to control the parsing logic have been
+ // successfully read.
+ if ((ProcessorId == NULL) ||
+ (ProcessorResourceType == NULL) ||
+ (ProcessorFlags == NULL)) {
+ IncrementErrorCount ();
+ Print (
+ L"ERROR: Insufficient Processor Error Node length. Length = %d.\n",
+ Length
+ );
+ return;
+ }
+
+ switch (*ProcessorResourceType) {
+ case EFI_ACPI_AEST_PROCESSOR_RESOURCE_TYPE_CACHE:
+ ParseAcpi (
+ TRUE,
+ 2,
+ "Cache Resource",
+ Ptr + Offset,
+ Length - Offset,
+ PARSER_PARAMS (AestProcessorCacheResourceSubstructure)
+ );
+ break;
+ case EFI_ACPI_AEST_PROCESSOR_RESOURCE_TYPE_TLB:
+ ParseAcpi (
+ TRUE,
+ 2,
+ "TLB Resource",
+ Ptr + Offset,
+ Length - Offset,
+ PARSER_PARAMS (AestProcessorTlbResourceSubstructure)
+ );
+ break;
+ case EFI_ACPI_AEST_PROCESSOR_RESOURCE_TYPE_GENERIC:
+ ParseAcpi (
+ TRUE,
+ 2,
+ "Generic Resource",
+ Ptr + Offset,
+ Length - Offset,
+ PARSER_PARAMS (AestProcessorGenericResourceSubstructure)
+ );
+ break;
+ default:
+ IncrementErrorCount ();
+ Print (L"ERROR: Invalid Processor Resource Type.");
+ return;
+ } // switch
+}
+
+/**
+ Parses the Memory Controller node.
+
+ @param [in] Ptr Pointer to the start of the Memory Controller node.
+ @param [in] Length Maximum length of the Memory Controller node.
+**/
+STATIC
+VOID
+DumpMemoryControllerNode (
+ IN UINT8* Ptr,
+ IN UINT32 Length
+ )
+{
+ ParseAcpi (
+ TRUE,
+ 2,
+ "Memory Controller",
+ Ptr,
+ Length,
+ PARSER_PARAMS (AestMemoryControllerStructure)
+ );
+}
+
+/**
+ Parses the SMMU node.
+
+ @param [in] Ptr Pointer to the start of the SMMU node.
+ @param [in] Length Maximum length of the SMMU node.
+**/
+STATIC
+VOID
+DumpSmmuNode (
+ IN UINT8* Ptr,
+ IN UINT32 Length
+ )
+{
+ ParseAcpi (
+ TRUE,
+ 2,
+ "SMMU",
+ Ptr,
+ Length,
+ PARSER_PARAMS (AestSmmuStructure)
+ );
+}
+
+/**
+ Parses the Vendor-defined structure.
+
+ @param [in] Ptr Pointer to the start of the Vendor-defined node.
+ @param [in] Length Maximum length of the Vendor-defined node.
+**/
+STATIC
+VOID
+DumpVendorDefinedNode (
+ IN UINT8* Ptr,
+ IN UINT32 Length
+ )
+{
+ ParseAcpi (
+ TRUE,
+ 2,
+ "Vendor-defined",
+ Ptr,
+ Length,
+ PARSER_PARAMS (AestVendorDefinedStructure)
+ );
+}
+
+/**
+ Parses the GIC node.
+
+ @param [in] Ptr Pointer to the start of the GIC node.
+ @param [in] Length Maximum length of the GIC node.
+**/
+STATIC
+VOID
+DumpGicNode (
+ IN UINT8* Ptr,
+ IN UINT32 Length
+ )
+{
+ ParseAcpi (
+ TRUE,
+ 2,
+ "GIC",
+ Ptr,
+ Length,
+ PARSER_PARAMS (AestGicStructure)
+ );
+}
+
+/**
+ Parses the Node Interface structure.
+
+ @param [in] Ptr Pointer to the start of the Node Interface Structure.
+ @param [in] Length Maximum length of the Node Interface Structure.
+**/
+STATIC
+VOID
+DumpNodeInterface (
+ IN UINT8* Ptr,
+ IN UINT32 Length
+ )
+{
+ ParseAcpi (
+ TRUE,
+ 2,
+ "Node Interface",
+ Ptr,
+ Length,
+ PARSER_PARAMS (AestNodeInterface)
+ );
+}
+
+/**
+ Parses the Node Interrupts Structure.
+
+ @param [in] Ptr Pointer to the start of the Node Interrupt array.
+ @param [in] Length Maximum length of the Node Interrupt array.
+ @param [in] InterruptCount Number if interrupts in the Node Interrupts array.
+**/
+STATIC
+VOID
+DumpNodeInterrupts (
+ IN UINT8* Ptr,
+ IN UINT32 Length,
+ IN UINT32 InterruptCount
+ )
+{
+ UINT32 Offset;
+ UINT32 Index;
+ CHAR8 Buffer[64];
+
+ if (Length < (InterruptCount * sizeof (EFI_ACPI_AEST_INTERRUPT_STRUCT))) {
+ IncrementErrorCount ();
+ Print (
+ L"ERROR: Node not long enough for Interrupt Array.\n"\
+ L" Length left = %d, Required = %d, Interrupt Count = %d\n",
+ Length,
+ (InterruptCount * sizeof (EFI_ACPI_AEST_INTERRUPT_STRUCT)),
+ InterruptCount
+ );
+ return;
+ }
+
+ Offset = 0;
+ for (Index = 0; Index < InterruptCount; Index++) {
+ AsciiSPrint (
+ Buffer,
+ sizeof (Buffer),
+ "Node Interrupt [%d]",
+ Index
+ );
+
+ Offset += ParseAcpi (
+ TRUE,
+ 4,
+ Buffer,
+ Ptr + Offset,
+ Length - Offset,
+ PARSER_PARAMS (AestNodeInterrupt)
+ );
+ } //for
+}
+
+/**
+ Parses a single AEST Node Structure.
+
+ @param [in] Ptr Pointer to the start of the Node.
+ @param [in] Length Maximum length of the Node.
+ @param [in] NodeType AEST node type.
+ @param [in] DataOffset Offset to the node data.
+ @param [in] InterfaceOffset Offset to the node interface data.
+ @param [in] InterruptArrayOffset Offset to the node interrupt array.
+ @param [in] InterruptCount Number of interrupts.
+**/
+STATIC
+VOID
+DumpAestNodeStructure (
+ IN UINT8* Ptr,
+ IN UINT32 Length,
+ IN UINT8 NodeType,
+ IN UINT32 DataOffset,
+ IN UINT32 InterfaceOffset,
+ IN UINT32 InterruptArrayOffset,
+ IN UINT32 InterruptCount
+ )
+{
+ UINT32 Offset;
+ UINT32 RemainingLength;
+ UINT8* NodeDataPtr;
+
+ Offset = ParseAcpi (
+ TRUE,
+ 2,
+ "Node Structure",
+ Ptr,
+ Length,
+ PARSER_PARAMS (AestNodeHeaderParser)
+ );
+
+ if ((Offset > DataOffset) || (DataOffset > Length)) {
+ IncrementErrorCount ();
+ Print (
+ L"ERROR: Invalid Node Data Offset: %d.\n"\
+ L" It should be between %d and %d.\n",
+ DataOffset,
+ Offset,
+ Length
+ );
+ }
+
+ if ((Offset > InterfaceOffset) || (InterfaceOffset > Length)) {
+ IncrementErrorCount ();
+ Print (
+ L"ERROR: Invalid Node Interface Offset: %d.\n"\
+ L" It should be between %d and %d.\n",
+ InterfaceOffset,
+ Offset,
+ Length
+ );
+ }
+
+ if ((Offset > InterruptArrayOffset) || (InterruptArrayOffset > Length)) {
+ IncrementErrorCount ();
+ Print (
+ L"ERROR: Invalid Node Interrupt Array Offset: %d.\n"\
+ L" It should be between %d and %d.\n",
+ InterruptArrayOffset,
+ Offset,
+ Length
+ );
+ }
+
+ // Parse Node Data Field.
+ NodeDataPtr = Ptr + DataOffset;
+ RemainingLength = Length - DataOffset;
+ switch (NodeType) {
+ case EFI_ACPI_AEST_NODE_TYPE_PROCESSOR:
+ DumpProcessorNode (NodeDataPtr, RemainingLength);
+ break;
+ case EFI_ACPI_AEST_NODE_TYPE_MEMORY:
+ DumpMemoryControllerNode (NodeDataPtr, RemainingLength);
+ break;
+ case EFI_ACPI_AEST_NODE_TYPE_SMMU:
+ DumpSmmuNode (NodeDataPtr, RemainingLength);
+ break;
+ case EFI_ACPI_AEST_NODE_TYPE_VENDOR_DEFINED:
+ DumpVendorDefinedNode (NodeDataPtr, RemainingLength);
+ break;
+ case EFI_ACPI_AEST_NODE_TYPE_GIC:
+ DumpGicNode (NodeDataPtr, RemainingLength);
+ break;
+ default:
+ IncrementErrorCount ();
+ Print (L"ERROR: Invalid Error Node Type.\n");
+ return;
+ } // switch
+
+ // Parse the Interface Field.
+ DumpNodeInterface (
+ Ptr + InterfaceOffset,
+ Length - InterfaceOffset
+ );
+
+ // Parse the Node Interrupt Array.
+ DumpNodeInterrupts (
+ Ptr + InterruptArrayOffset,
+ Length - InterruptArrayOffset,
+ InterruptCount
+ );
+
+ return;
+}
+
+/**
+ This function parses the ACPI AEST table.
+ When trace is enabled this function parses the AEST 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
+ParseAcpiAest (
+ IN BOOLEAN Trace,
+ IN UINT8* Ptr,
+ IN UINT32 AcpiTableLength,
+ IN UINT8 AcpiTableRevision
+ )
+{
+ UINT32 Offset;
+ UINT8* NodePtr;
+
+ if (!Trace) {
+ return;
+ }
+
+ Offset = ParseAcpi (
+ TRUE,
+ 0,
+ "AEST",
+ Ptr,
+ AcpiTableLength,
+ PARSER_PARAMS (AestParser)
+ );
+
+ while (Offset < AcpiTableLength) {
+ NodePtr = Ptr + Offset;
+
+ ParseAcpi (
+ FALSE,
+ 0,
+ NULL,
+ NodePtr,
+ AcpiTableLength - Offset,
+ PARSER_PARAMS (AestNodeHeaderParser)
+ );
+
+ // Check if the values used to control the parsing logic have been
+ // successfully read.
+ if ((AestNodeType == NULL) ||
+ (AestNodeLength == NULL) ||
+ (NodeDataOffset == NULL) ||
+ (NodeInterfaceOffset == NULL) ||
+ (NodeInterruptArrayOffset == NULL) ||
+ (NodeInterruptCount == NULL)) {
+ IncrementErrorCount ();
+ Print (
+ L"ERROR: Insufficient length left for Node Structure.\n"\
+ L" Length left = %d.\n",
+ AcpiTableLength - Offset
+ );
+ return;
+ }
+
+ // Validate AEST Node length
+ if ((*AestNodeLength == 0) ||
+ ((Offset + (*AestNodeLength)) > AcpiTableLength)) {
+ IncrementErrorCount ();
+ Print (
+ L"ERROR: Invalid AEST Node length. " \
+ L"Length = %d. Offset = %d. AcpiTableLength = %d.\n",
+ *AestNodeLength,
+ Offset,
+ AcpiTableLength
+ );
+ return;
+ }
+
+ DumpAestNodeStructure (
+ NodePtr,
+ *AestNodeLength,
+ *AestNodeType,
+ *NodeDataOffset,
+ *NodeInterfaceOffset,
+ *NodeInterruptArrayOffset,
+ *NodeInterruptCount
+ );
+
+ Offset += *AestNodeLength;
+ } // while
+}
diff --git a/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.c b/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.c
index d2f26ff89f12e596702281c38ab0de3729aa68e4..502bdcf30be50579bc5a4de30b71dc8a44fd55ae 100644
--- a/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.c
+++ b/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.c
@@ -1,12 +1,13 @@
/** @file
Main file for 'acpiview' Shell command function.

- Copyright (c) 2016 - 2020, ARM Limited. All rights reserved.<BR>
+ Copyright (c) 2016 - 2020, Arm Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/

#include <Guid/ShellLibHiiGuid.h>
#include <IndustryStandard/Acpi.h>
+#include <IndustryStandard/ArmErrorSourceTable.h>

#include <Library/BaseMemoryLib.h>
#include <Library/HiiLib.h>
@@ -46,6 +47,7 @@ STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
STATIC
CONST
ACPI_TABLE_PARSER ParserList[] = {
+ {EFI_ACPI_6_3_ARM_ERROR_SOURCE_TABLE_SIGNATURE, ParseAcpiAest},
{EFI_ACPI_6_2_BOOT_GRAPHICS_RESOURCE_TABLE_SIGNATURE, ParseAcpiBgrt},
{EFI_ACPI_6_2_DEBUG_PORT_2_TABLE_SIGNATURE, ParseAcpiDbg2},
{EFI_ACPI_6_2_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE,
diff --git a/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf b/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf
index 91459f9ec632635ee453c5ef46f67445cd9eee0c..d89cfbba0da833d5c945ebeb0b462fa52504a865 100644
--- a/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf
+++ b/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf
@@ -1,7 +1,7 @@
## @file
# Provides Shell 'acpiview' command functions
#
-# Copyright (c) 2016 - 2020, ARM Limited. All rights reserved.<BR>
+# Copyright (c) 2016 - 2020, Arm Limited. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
@@ -27,6 +27,7 @@ [Sources.common]
AcpiView.h
AcpiViewConfig.c
AcpiViewConfig.h
+ Parsers/Aest/AestParser.c
Parsers/Bgrt/BgrtParser.c
Parsers/Dbg2/Dbg2Parser.c
Parsers/Dsdt/DsdtParser.c
diff --git a/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.uni b/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.uni
index 7cd43d0518fd0a23dc547a5cab0d08b62602a113..9dbffcd7c534fa9039668cfbe79f75d3a94c9b28 100644
--- a/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.uni
+++ b/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.uni
@@ -1,6 +1,6 @@
// /**
//
-// Copyright (c) 2016 - 2020, ARM Limited. All rights reserved.<BR>
+// Copyright (c) 2016 - 2020, Arm Limited. All rights reserved.<BR>
// SPDX-License-Identifier: BSD-2-Clause-Patent
//
// Module Name:
@@ -78,6 +78,7 @@
" other than AcpiTable header. The actual header can refer to the ACPI spec\r\n"
" 6.2\r\n"
" Extra A. Particular types:\r\n"
+" AEST - Arm Error Source Table\r\n"
" APIC - Multiple APIC Description Table (MADT)\r\n"
" BGRT - Boot Graphics Resource Table\r\n"
" DBG2 - Debug Port Table 2\r\n"
--
'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)'


[PATCH v2 1/2] MdePkg/IndustryStandard: AEST Table definition

Sami Mujawar
 

From: Marc Moisson-Franckhauser <marc.moisson-franckhauser@arm.com>

Add definition for the Arm Error Source Table (AEST) described in
the ACPI for the Armv8 RAS Extensions 1.1 Platform Design Document,
dated 28 September 2020.
(https://developer.arm.com/documentation/den0085/0101/)

Signed-off-by: Marc Moisson-Franckhauser <marc.moisson-franckhauser@arm.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
---

Notes:
v2:
- AEST is not defined in ACPI 6.3 spec and should not be [Liming]
added to Acpi63.h and for structure definition and its
field, its comment starts with /// or //.
- Moved AEST table signature to ArmErrorSourceTable.h and [SAMI]
updated structure and field documenting style to match
coding convention.
Ref: https://edk2.groups.io/g/devel/message/66151

MdePkg/Include/IndustryStandard/ArmErrorSourceTable.h | 357 ++++++++++++++++++++
1 file changed, 357 insertions(+)

diff --git a/MdePkg/Include/IndustryStandard/ArmErrorSourceTable.h b/MdePkg/Include/IndustryStandard/ArmErrorSourceTable.h
new file mode 100644
index 0000000000000000000000000000000000000000..369b03a50b65a7f6d0012eec9898a14dcd61976d
--- /dev/null
+++ b/MdePkg/Include/IndustryStandard/ArmErrorSourceTable.h
@@ -0,0 +1,357 @@
+/** @file
+ Arm Error Source Table as described in the
+ 'ACPI for the Armv8 RAS Extensions 1.1' Specification.
+
+ Copyright (c) 2020 Arm Limited.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - ACPI for the Armv8 RAS Extensions 1.1 Platform Design Document,
+ dated 28 September 2020.
+ (https://developer.arm.com/documentation/den0085/0101/)
+
+ @par Glossary
+ - Ref : Reference
+ - Id : Identifier
+**/
+
+#ifndef ARM_ERROR_SOURCE_TABLE_H_
+#define ARM_ERROR_SOURCE_TABLE_H_
+
+///
+/// "AEST" Arm Error Source Table
+///
+#define EFI_ACPI_6_3_ARM_ERROR_SOURCE_TABLE_SIGNATURE SIGNATURE_32('A', 'E', 'S', 'T')
+
+#define EFI_ACPI_ARM_ERROR_SOURCE_TABLE_REVISION 1
+
+#pragma pack(1)
+
+///
+/// Arm Error Source Table definition.
+///
+typedef struct {
+ EFI_ACPI_DESCRIPTION_HEADER Header;
+} EFI_ACPI_ARM_ERROR_SOURCE_TABLE;
+
+///
+/// AEST Node structure.
+///
+typedef struct {
+ /// Node type:
+ /// 0x00 - Processor error node
+ /// 0x01 - Memory error node
+ /// 0x02 - SMMU error node
+ /// 0x03 - Vendor-defined error node
+ /// 0x04 - GIC error node
+ UINT8 Type;
+
+ /// Length of structure in bytes.
+ UINT16 Length;
+
+ /// Reserved - Must be zero.
+ UINT8 Reserved;
+
+ /// Offset from the start of the node to node-specific data.
+ UINT32 DataOffset;
+
+ /// Offset from the start of the node to the node interface structure.
+ UINT32 InterfaceOffset;
+
+ /// Offset from the start of the node to node interrupt array.
+ UINT32 InterruptArrayOffset;
+
+ /// Number of entries in the interrupt array.
+ UINT32 InterruptArrayCount;
+
+ // Generic node data
+
+ /// The timestamp frequency of the counter in Hz.
+ UINT64 TimestampRate;
+
+ /// Reserved - Must be zero.
+ UINT64 Reserved1;
+
+ /// The rate in Hz at which the Error Generation Counter decrements.
+ UINT64 ErrorInjectionCountdownRate;
+} EFI_ACPI_AEST_NODE_STRUCT;
+
+// AEST Node type definitions
+#define EFI_ACPI_AEST_NODE_TYPE_PROCESSOR 0x0
+#define EFI_ACPI_AEST_NODE_TYPE_MEMORY 0x1
+#define EFI_ACPI_AEST_NODE_TYPE_SMMU 0x2
+#define EFI_ACPI_AEST_NODE_TYPE_VENDOR_DEFINED 0x3
+#define EFI_ACPI_AEST_NODE_TYPE_GIC 0x4
+
+///
+/// AEST Node Interface structure.
+///
+typedef struct {
+ /// Interface type:
+ /// 0x0 - System register (SR)
+ /// 0x1 - Memory mapped (MMIO)
+ UINT8 Type;
+
+ /// Reserved - Must be zero.
+ UINT8 Reserved[3];
+
+ /// AEST node interface flags.
+ UINT32 Flags;
+
+ /// Base address of error group that contains the error node.
+ UINT64 BaseAddress;
+
+ /// Zero-based index of the first standard error record that
+ /// belongs to this node.
+ UINT32 StartErrorRecordIndex;
+
+ /// Number of error records in this node including both
+ /// implemented and unimplemented records.
+ UINT32 NumberErrorRecords;
+
+ /// A bitmap indicating the error records within this
+ /// node that are implemented in the current system.
+ UINT64 ErrorRecordImplemented;
+
+ /// A bitmap indicating the error records within this node that
+ /// support error status reporting through the ERRGSR register.
+ UINT64 ErrorRecordStatusReportingSupported;
+
+ /// A bitmap indicating the addressing mode used by each error
+ /// record within this node to populate the ERR<n>_ADDR register.
+ UINT64 AddressingMode;
+} EFI_ACPI_AEST_INTERFACE_STRUCT;
+
+// AEST Interface node type definitions.
+#define EFI_ACPI_AEST_INTERFACE_TYPE_SR 0x0
+#define EFI_ACPI_AEST_INTERFACE_TYPE_MMIO 0x1
+
+// AEST node interface flag definitions.
+#define EFI_ACPI_AEST_INTERFACE_FLAG_PRIVATE 0
+#define EFI_ACPI_AEST_INTERFACE_FLAG_SHARED BIT0
+#define EFI_ACPI_AEST_INTERFACE_FLAG_CLEAR_MISCX BIT1
+
+///
+/// AEST Node Interrupt structure.
+///
+typedef struct {
+ /// Interrupt type:
+ /// 0x0 - Fault Handling Interrupt
+ /// 0x1 - Error Recovery Interrupt
+ UINT8 InterruptType;
+
+ /// Reserved - Must be zero.
+ UINT8 Reserved[2];
+
+ /// Interrupt flags
+ /// Bits [31:1]: Must be zero.
+ /// Bit 0:
+ /// 0b - Interrupt is edge-triggered
+ /// 1b - Interrupt is level-triggered
+ UINT8 InterruptFlags;
+
+ /// GSIV of interrupt, if interrupt is an SPI or a PPI.
+ UINT32 InterruptGsiv;
+
+ /// If MSI is supported, then this field must be set to the
+ /// Identifier field of the IORT ITS Group node.
+ UINT8 ItsGroupRefId;
+
+ /// Reserved - must be zero.
+ UINT8 Reserved1[3];
+} EFI_ACPI_AEST_INTERRUPT_STRUCT;
+
+// AEST Interrupt node - interrupt type defintions.
+#define EFI_ACPI_AEST_INTERRUPT_TYPE_FAULT_HANDLING 0x0
+#define EFI_ACPI_AEST_INTERRUPT_TYPE_ERROR_RECOVERY 0x1
+
+// AEST Interrupt node - interrupt flag defintions.
+#define EFI_ACPI_AEST_INTERRUPT_FLAG_TRIGGER_TYPE_EDGE 0
+#define EFI_ACPI_AEST_INTERRUPT_FLAG_TRIGGER_TYPE_LEVEL BIT0
+
+///
+/// Cache Processor Resource structure.
+///
+typedef struct {
+ /// Reference to the cache structure in the PPTT table.
+ UINT32 CacheRefId;
+
+ /// Reserved
+ UINT32 Reserved;
+} EFI_ACPI_AEST_PROCESSOR_CACHE_RESOURCE_STRUCT;
+
+///
+/// TLB Processor Resource structure.
+///
+typedef struct {
+ /// TLB level from perspective of current processor.
+ UINT32 TlbRefId;
+
+ /// Reserved
+ UINT32 Reserved;
+} EFI_ACPI_AEST_PROCESSOR_TLB_RESOURCE_STRUCT;
+
+///
+/// Processor Generic Resource structure.
+///
+typedef struct {
+ /// Vendor-defined supplementary data.
+ UINT32 Data;
+} EFI_ACPI_AEST_PROCESSOR_GENERIC_RESOURCE_STRUCT;
+
+///
+/// AEST Processor Resource union.
+///
+typedef union {
+ /// Processor Cache resource.
+ EFI_ACPI_AEST_PROCESSOR_CACHE_RESOURCE_STRUCT Cache;
+
+ /// Processor TLB resource.
+ EFI_ACPI_AEST_PROCESSOR_TLB_RESOURCE_STRUCT Tlb;
+
+ /// Processor Generic resource.
+ EFI_ACPI_AEST_PROCESSOR_GENERIC_RESOURCE_STRUCT Generic;
+} EFI_ACPI_AEST_PROCESSOR_RESOURCE;
+
+///
+/// AEST Processor structure.
+///
+typedef struct {
+ /// AEST Node header
+ EFI_ACPI_AEST_NODE_STRUCT NodeHeader;
+
+ /// Processor ID of node.
+ UINT32 AcpiProcessorId;
+
+ /// Resource type of the processor node.
+ /// 0x0 - Cache
+ /// 0x1 - TLB
+ /// 0x2 - Generic
+ UINT8 ResourceType;
+
+ /// Reserved - must be zero.
+ UINT8 Reserved;
+
+ /// Processor structure flags.
+ UINT8 Flags;
+
+ /// Processor structure revision.
+ UINT8 Revision;
+
+ /// Processor affinity descriptor for the resource that this
+ /// error node pertains to.
+ UINT64 ProcessorAffinityLevelIndicator;
+
+ /// Processor resource
+ EFI_ACPI_AEST_PROCESSOR_RESOURCE Resource;
+
+ // Node Interface
+ // EFI_ACPI_AEST_INTERFACE_STRUCT NodeInterface;
+
+ // Node Interrupt Array
+ // EFI_ACPI_AEST_INTERRUPT_STRUCT NodeInterruptArray[n];
+} EFI_ACPI_AEST_PROCESSOR_STRUCT;
+
+// AEST Processor resource type definitions.
+#define EFI_ACPI_AEST_PROCESSOR_RESOURCE_TYPE_CACHE 0x0
+#define EFI_ACPI_AEST_PROCESSOR_RESOURCE_TYPE_TLB 0x1
+#define EFI_ACPI_AEST_PROCESSOR_RESOURCE_TYPE_GENERIC 0x2
+
+// AEST Processor flag definitions.
+#define EFI_ACPI_AEST_PROCESSOR_FLAG_GLOBAL BIT0
+#define EFI_ACPI_AEST_PROCESSOR_FLAG_SHARED BIT1
+
+///
+/// Memory Controller structure.
+///
+typedef struct {
+ /// AEST Node header
+ EFI_ACPI_AEST_NODE_STRUCT NodeHeader;
+
+ /// SRAT proximity domain.
+ UINT32 ProximityDomain;
+
+ // Node Interface
+ // EFI_ACPI_AEST_INTERFACE_STRUCT NodeInterface;
+
+ // Node Interrupt Array
+ // EFI_ACPI_AEST_INTERRUPT_STRUCT NodeInterruptArray[n];
+} EFI_ACPI_AEST_MEMORY_CONTROLLER_STRUCT;
+
+///
+/// SMMU structure.
+///
+typedef struct {
+ /// AEST Node header
+ EFI_ACPI_AEST_NODE_STRUCT NodeHeader;
+
+ /// Reference to the IORT table node that describes this SMMU.
+ UINT32 SmmuRefId;
+
+ /// Reference to the IORT table node that is associated with the
+ /// sub-component within this SMMU.
+ UINT32 SubComponentRefId;
+
+ // Node Interface
+ // EFI_ACPI_AEST_INTERFACE_STRUCT NodeInterface;
+
+ // Node Interrupt Array
+ // EFI_ACPI_AEST_INTERRUPT_STRUCT NodeInterruptArray[n];
+} EFI_ACPI_AEST_SMMU_STRUCT;
+
+///
+/// Vendor-Defined structure.
+///
+typedef struct {
+ /// AEST Node header
+ EFI_ACPI_AEST_NODE_STRUCT NodeHeader;
+
+ /// ACPI HID of the component.
+ UINT32 HardwareId;
+
+ /// The ACPI Unique identifier of the component.
+ UINT32 UniqueId;
+
+ /// Vendor-specific data, for example to identify this error source.
+ UINT8 VendorData[16];
+
+ // Node Interface
+ // EFI_ACPI_AEST_INTERFACE_STRUCT NodeInterface;
+
+ // Node Interrupt Array
+ // EFI_ACPI_AEST_INTERRUPT_STRUCT NodeInterruptArray[n];
+} EFI_ACPI_AEST_VENDOR_DEFINED_STRUCT;
+
+///
+/// GIC structure.
+///
+typedef struct {
+ /// AEST Node header
+ EFI_ACPI_AEST_NODE_STRUCT NodeHeader;
+
+ /// Type of GIC interface that is associated with this error node.
+ /// 0x0 - GIC CPU (GICC)
+ /// 0x1 - GIC Distributor (GICD)
+ /// 0x2 - GIC Resistributor (GICR)
+ /// 0x3 - GIC ITS (GITS)
+ UINT32 InterfaceType;
+
+ /// Identifier for the interface instance.
+ UINT32 GicInterfaceRefId;
+
+ // Node Interface
+ // EFI_ACPI_AEST_INTERFACE_STRUCT NodeInterface;
+
+ // Node Interrupt Array
+ // EFI_ACPI_AEST_INTERRUPT_STRUCT NodeInterruptArray[n];
+} EFI_ACPI_AEST_GIC_STRUCT;
+
+// AEST GIC interface type definitions.
+#define EFI_ACPI_AEST_GIC_INTERFACE_TYPE_GICC 0x0
+#define EFI_ACPI_AEST_GIC_INTERFACE_TYPE_GICD 0x1
+#define EFI_ACPI_AEST_GIC_INTERFACE_TYPE_GICR 0x2
+#define EFI_ACPI_AEST_GIC_INTERFACE_TYPE_GITS 0x3
+
+#pragma pack()
+
+#endif // ARM_ERROR_SOURCE_TABLE_H_
--
'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)'


[PATCH v2 0/2] Add AEST parser support to Acpiview

Sami Mujawar
 

Arm Error Source Table (AEST) enables kernel-first handling of
errors in a system that supports the Armv8 RAS extensions. AEST
is described in the ACPI for the Armv8 RAS Extensions 1.1,
Platform Design Document, dated 28 September 2020.
(https://developer.arm.com/documentation/den0085/0101/)

This v2 patch series:
- adds AEST parser support to Acpiview.
- addresses the review feedback for v1 series.

The changes can be seen at:
https://github.com/samimujawar/edk2/tree/1429_aest_parser_v2

Marc Moisson-Franckhauser (2):
MdePkg/IndustryStandard: AEST Table definition
ShellPkg/Acpiview: AEST Parser

MdePkg/Include/IndustryStandard/ArmErrorSourceTable.h | 357 +++++++++
ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.h | 21 +
ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiTableParser.h | 4 +-
ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Aest/AestParser.c | 755 ++++++++++++++++++++
ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.c | 4 +-
ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf | 3 +-
ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.uni | 3 +-
7 files changed, 1142 insertions(+), 5 deletions(-)
create mode 100644 MdePkg/Include/IndustryStandard/ArmErrorSourceTable.h
create mode 100644 ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Aest/AestParser.c

--
'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)'


[PATCH] MdeModulePkg/XhciDxe: Retry device slot init on failure

Jeff Brasen
 

From: Jon Hunter <jonathanh@nvidia.com>

With some super-speed USB mass storage devices it has been observed
that a USB transaction error may occur when attempting the set the
device address during enumeration.

According the the xHCI specification (section 4.6.5) ...

"A USB Transaction ErrorCompletion Code for an Address Device Command
may be due to a Stall response from a device. Software should issue a
Disable Slot Commandfor the Device Slot then an Enable Slot Command
to recover from this error."

To fix this, retry the device slot initialization if it fails due to a
device error.

Signed-off-by: Jeff Brasen <jbrasen@nvidia.com>
---
MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c | 71 ++++++++++++++----------
1 file changed, 42 insertions(+), 29 deletions(-)

diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c b/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
index 9cb115363c..1a16864205 100644
--- a/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
+++ b/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
@@ -1717,9 +1717,11 @@ XhcPollPortStatusChange (
EFI_STATUS Status;
UINT8 Speed;
UINT8 SlotId;
+ UINT8 Retries;
USB_DEV_ROUTE RouteChart;

Status = EFI_SUCCESS;
+ Retries = 1;

if ((PortState->PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) {
return EFI_SUCCESS;
@@ -1739,40 +1741,51 @@ XhcPollPortStatusChange (
RouteChart.Route.TierNum = ParentRouteChart.Route.TierNum + 1;
}

- SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);
- if (SlotId != 0) {
- if (Xhc->HcCParams.Data.Csz == 0) {
- Status = XhcDisableSlotCmd (Xhc, SlotId);
- } else {
- Status = XhcDisableSlotCmd64 (Xhc, SlotId);
- }
- }
-
- if (((PortState->PortStatus & USB_PORT_STAT_ENABLE) != 0) &&
- ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) != 0)) {
- //
- // Has a device attached, Identify device speed after port is enabled.
- //
- Speed = EFI_USB_SPEED_FULL;
- if ((PortState->PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {
- Speed = EFI_USB_SPEED_LOW;
- } else if ((PortState->PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0) {
- Speed = EFI_USB_SPEED_HIGH;
- } else if ((PortState->PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {
- Speed = EFI_USB_SPEED_SUPER;
- }
- //
- // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.
- //
+ do {
SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);
- if ((SlotId == 0) && ((PortState->PortChangeStatus & USB_PORT_STAT_C_RESET) != 0)) {
+ if (SlotId != 0) {
if (Xhc->HcCParams.Data.Csz == 0) {
- Status = XhcInitializeDeviceSlot (Xhc, ParentRouteChart, Port, RouteChart, Speed);
+ Status = XhcDisableSlotCmd (Xhc, SlotId);
} else {
- Status = XhcInitializeDeviceSlot64 (Xhc, ParentRouteChart, Port, RouteChart, Speed);
+ Status = XhcDisableSlotCmd64 (Xhc, SlotId);
}
}
- }
+
+ if (((PortState->PortStatus & USB_PORT_STAT_ENABLE) != 0) &&
+ ((PortState->PortStatus & USB_PORT_STAT_CONNECTION) != 0)) {
+ //
+ // Has a device attached, Identify device speed after port is enabled.
+ //
+ Speed = EFI_USB_SPEED_FULL;
+ if ((PortState->PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) {
+ Speed = EFI_USB_SPEED_LOW;
+ } else if ((PortState->PortStatus & USB_PORT_STAT_HIGH_SPEED) != 0) {
+ Speed = EFI_USB_SPEED_HIGH;
+ } else if ((PortState->PortStatus & USB_PORT_STAT_SUPER_SPEED) != 0) {
+ Speed = EFI_USB_SPEED_SUPER;
+ }
+ //
+ // Execute Enable_Slot cmd for attached device, initialize device context and assign device address.
+ //
+ SlotId = XhcRouteStringToSlotId (Xhc, RouteChart);
+ if ((SlotId == 0) && ((PortState->PortChangeStatus & USB_PORT_STAT_C_RESET) != 0)) {
+ if (Xhc->HcCParams.Data.Csz == 0) {
+ Status = XhcInitializeDeviceSlot (Xhc, ParentRouteChart, Port, RouteChart, Speed);
+ } else {
+ Status = XhcInitializeDeviceSlot64 (Xhc, ParentRouteChart, Port, RouteChart, Speed);
+ }
+ }
+ }
+
+ //
+ // According to the xHCI specification (section 4.6.5), "a USB Transaction
+ // Error Completion Code for an Address Device Command may be due to a Stall
+ // response from a device. Software should issue a Disable Slot Command for
+ // the Device Slot then an Enable Slot Command to recover from this error."
+ // Therefore, retry the device slot initialization if it fails due to a
+ // device error.
+ //
+ } while ((Status == EFI_DEVICE_ERROR) && (Retries--));

return Status;
}
--
2.25.1


Re: [PATCH edk2-platforms v1 1/2] Drivers/OpTeeRpmb: Add an OP-TEE backed RPMB driver

Ilias Apalodimas
 

Hi Sughosh

On Wed, Oct 21, 2020 at 05:05:33PM +0530, Sughosh Ganu wrote:
+
[...]
+#ifndef __OPTEE_RPMB_FV_
+#define __OPTEE_RPMB_FV_
+
+/* SVC Args */
+#define SP_SVC_RPMB_READ 0xC4000066
+#define SP_SVC_RPMB_WRITE 0xC4000067
+#define SP_SVC_GET_UART 0xC4000068
+
+#define FILENAME "EFI_VARS"
+
+#define NBLOCKS (3 * 16) // EFI Vars, FTW working, FTW spare
+#define BLOCK_SIZE SIZE_4KB
+#define FLASH_SIGNATURE SIGNATURE_32('r', 'p', 'm', 'b')
+#define INSTANCE_FROM_FVB_THIS(a) CR(a, MEM_INSTANCE, FvbProtocol, \
+ FLASH_SIGNATURE)
+enum _RPMB_FILE_MAP {
+ EFI_VARS,
+ FTW_WORK,
+ FTW_SPARE,
+};
+
+typedef enum _RPMB_FILE_MAP RPMB_FILE_MAP;
+
+struct _MAP_VAL_TO_FILE {
+ CHAR8 *Filename;
+ RPMB_FILE_MAP Map;
+};
+
+typedef struct _MAP_VAL_TO_FILE MAP_VAL_TO_FILE;
_RPMB_FILE_MAP and friends was a left over from the first version of the driver,
and somehow slipped in.
They don't affect the code at all, but we should remove them on v2.


[...]

Regards
/Ilias


Re: Overriding of linker in ed2 build system

Andrew Fish
 

Prabin,

Conf/tools_def.txt is the local untracked by git copy of the file that the build actually uses. The Conf/tools_def.txt does NOT get overwritten by the BaseTools/Conf/tools_def.template if it exists. So you can edit Conf/tools_def.txt  locally for an experiment. If you change  BaseTools/Conf/tools_def.template then people need to force the update via `. edksetup.sh —reconfig`, if they have a local copy. 

Thanks,

Andrew Fish

On Oct 21, 2020, at 7:39 AM, Prabin CA <prabin.ca@...> wrote:

Hi Andrew,

Yes, it copy from  BaseTools/Conf/tools_def.template to Conf/tools_def.txt, so if we make any changes in Conf/tools_def.txt will be over write by BaseTools/Conf/tools_def.template, then why we have to edit txt file instead template. Please confirm we have to edit template file or txt file. and we are made changes such as setting target and appending LDFLAGS on template file.


Re: Overriding of linker in ed2 build system

Prabin CA
 

Hi Andrew,

Yes, it copy from  BaseTools/Conf/tools_def.template to Conf/tools_def.txt, so if we make any changes in Conf/tools_def.txt will be over write by BaseTools/Conf/tools_def.template, then why we have to edit txt file instead template. Please confirm we have to edit template file or txt file. and we are made changes such as setting target and appending LDFLAGS on template file.


Re: Overriding of linker in ed2 build system

Andrew Fish
 



On Oct 20, 2020, at 11:44 AM, Prabin CA <prabin.ca@...> wrote:

Hi All,
I'm trying to build edk2 source code using clang, I see that linker used by edk2 build system is dependent on "-target <triplet>" defined in "BaseTools/Conf/tools_def.template". 
I wish to use llvm provided linker, I had tried appending  "-fuse-ld=lld" option to  "_CLANG38_AARCH64_DLINK_FLAGS" . But I still see the target specific linker being used by edk2 build system.
Any advice what could be the right way of overriding with llvm based ld.


Prabin,

When you run edksetup.sh that copies  BaseTools/Conf/tools_def.template to Conf/tools_def.txt. So you need to edit the Conf/tools_def.txt file. 

Thanks,

Andrew Fish

Thanks and Best Regards
Prabin CA


Re: [PATCH v2 0/2] ShellPkg/Acpiview: Add support for PCCT parser

Sami Mujawar
 

Hi Zhichao,

Can you let me know anything is needed for this patch series, please?

Regards,

Sami Mujawar

-----Original Message-----
From: Sami Mujawar <sami.mujawar@arm.com>
Sent: 24 September 2020 12:49 PM
To: devel@edk2.groups.io
Cc: Sami Mujawar <Sami.Mujawar@arm.com>; ray.ni@intel.com; zhichao.gao@intel.com; Matteo Carlini <Matteo.Carlini@arm.com>; Ben Adderson <Ben.Adderson@arm.com>; nd <nd@arm.com>
Subject: [PATCH v2 0/2] ShellPkg/Acpiview: Add support for PCCT parser

This patch series:
- Addresses the feedback for v1 patch for PCCT parser.
- Fixes an issue wherein the field validation is not
invoked when a print formatter is present.

The changes can be seen at:
https://github.com/samimujawar/edk2/tree/840_pcct_parser_v2

Marc Moisson-Franckhauser (1):
ShellPkg/AcpiView: PCCT Parser

Sami Mujawar (1):
ShellPkg/AcpiView: Fix field validator invocation

ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.c | 15 +-
ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiParser.h | 24 +-
ShellPkg/Library/UefiShellAcpiViewCommandLib/AcpiTableParser.h | 4 +-
ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Pcct/PcctParser.c | 615 ++++++++++++++++++++
ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Pcct/PcctParser.h | 33 ++
ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.c | 4 +-
ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf | 4 +-
7 files changed, 686 insertions(+), 13 deletions(-)
create mode 100644 ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Pcct/PcctParser.c
create mode 100644 ShellPkg/Library/UefiShellAcpiViewCommandLib/Parsers/Pcct/PcctParser.h

--
'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)'


Re: [PATCH v1 0/1] CryptoPkg: BaseCryptLib: Fix buffer double free in CryptPkcs7VerifyEku

Laszlo Ersek
 

On 10/21/20 04:32, Kun Qin wrote:
The issue is in VerifyEKUsInPkcs7Signature routine of
CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyEku.c:


At the "Exit" portion of this routine, this function uses X509_free to free
SignerCert instance and PKCS7_free function to free Pkcs7. But SignerCert
is part of Pkcs7 instance, thus PKCS7_free will release the memory of
SignerCert for a second time with existed routine, which will cause page
fault if use-after-free guard is enabled.


The patch fix is to free Pkcs7 instance only using PKCS7_free.

Patch v1 branch: https://github.com/kuqin12/edk2/tree/buffer_double_free_v1

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Xiaoyu Lu <xiaoyux.lu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Guomin Jiang <guomin.jiang@intel.com>

Signed-off-by: Kun Qin <kun.q@outlook.com>

Kun Qin (1):
CryptoPkg: BaseCryptLib: Fix buffer double free in CryptPkcs7VerifyEku

CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyEku.c | 4 ----
1 file changed, 4 deletions(-)
Please run "BaseTools/Scripts/SetupGit.py" in your edk2 repository, for
setting some git configuration options that you are currently missing
(such as, handling of CRLF line terminators, shallow threading, ...)

Thanks
Laszlo


Re: [PATCH v1 1/1] CryptoPkg: BaseCryptLib: Fix buffer double free in CryptPkcs7VerifyEku

Laszlo Ersek
 

On 10/21/20 04:32, Kun Qin wrote:
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2459

SignerCert is part of Pkcs7 instance when both have valid content. OpenSLL
PKCS7_free function will release the memory of SignerCert when applicable.
Is this a security issue?

Thanks
Laszlo

Freeing SignerCert with X509_free again might cause page fault if use-
after-free guard is enabled.

Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Xiaoyu Lu <xiaoyux.lu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Guomin Jiang <guomin.jiang@intel.com>

Signed-off-by: Kun Qin <kun.q@outlook.com>
---
CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyEku.c | 4 ----
1 file changed, 4 deletions(-)

diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyEku.c b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyEku.c
index c9fdb65b99d1..40cc39afe7dd 100644
--- a/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyEku.c
+++ b/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyEku.c
@@ -508,10 +508,6 @@ Exit:
free (SignedData);

}



- if (SignerCert != NULL) {

- X509_free (SignerCert);

- }

-

if (Pkcs7 != NULL) {

PKCS7_free (Pkcs7);

}


Re: [PATCH v2 1/2] MdePkg: Definitions for Extended Interrupt Flags

Sami Mujawar
 

Hi Mike,

Can you let me know if this patch is ok, please?

Ref:
https://edk2.groups.io/g/devel/message/65586
https://edk2.groups.io/g/devel/message/65697

Regards,

Sami Mujawar


Re: 回复: 回复: [PATCH v2 01/11] MdePkg, OvmfPkg: Clean up GHCB field offsets and save area

Laszlo Ersek
 

On 10/20/20 15:10, Tom Lendacky wrote:
On 10/20/20 3:31 AM, Laszlo Ersek wrote:
On 10/20/20 03:08, gaoliming wrote:
Laszlo and Tom:

-----邮件原件-----
发件人: Laszlo Ersek <lersek@redhat.com>
发送时间: 2020年10月20日 4:42
收件人: Tom Lendacky <thomas.lendacky@amd.com>; gaoliming
<gaoliming@byosoft.com.cn>; devel@edk2.groups.io
抄送: 'Brijesh Singh' <brijesh.singh@amd.com>; 'Michael D Kinney'
<michael.d.kinney@intel.com>; 'Zhiguang Liu' <zhiguang.liu@intel.com>;
'Jordan Justen' <jordan.l.justen@intel.com>; 'Ard Biesheuvel'
<ard.biesheuvel@arm.com>
主题: Re: 回复: [PATCH v2 01/11] MdePkg, OvmfPkg: Clean up GHCB field
offsets and save area

On 10/19/20 14:50, Tom Lendacky wrote:
On 10/18/20 8:41 PM, gaoliming wrote:
Please separate the patch for the change in OvmfPkg.
One commit can't cross the different packages.
I understand this is the incompatible change. But, we still need to follow
this rule.
I disagree.

We should do whatever we can for avoiding cross-package patches, but in
some cases, they are unavoidable. This is one of those cases.
I suggest to define enum GHCB_QWORD_OFFSET, then use typedef GHCB_QWORD_OFFSET GHCB_REGISTER; in Ghcb.h
The comments can be added here to describe it is for compatibility. The old one is not recommend.

Then, the change in MdePkg is compatible. Next patch is to update OvmfPkg VmgExit to consume GHCB_QWORD_OFFSET.
Ah, I totally missed that we could use typedef to bridge the gap. That
indeed allows us to do the rename in three steps (only for the type
name, the enum constant identifiers can stay the same). After the
rename, the enum constant values can be cleaned up in a separate (4th)
patch.
It seems like a lot of churn for just renaming.
Yes, it is. (I guess it helps downstreams that only want to cherry-pick
patches from specific packages.)

If there are no
objections, I'll keep the GHCB_REGISTER name. The important piece is the
change from hardcoding the offset values to using a calculated value.
If the GHCB_REGISTER type name works for you, it certainly works for me :)

Thanks
Laszlo


Re: [PATCH] MdeModulePkg/PartitionDxe: Revert the child handler blocksize change

Laszlo Ersek
 

On 10/21/20 03:33, Gao, Zhichao wrote:
Hi Laszlo,

Apologize for the patch merge thing. That is my fault. Base on your comments, I update the commit message with revert info and part of my V1 commit message. And I am thinking there is no other doubt with the reverting. Sometimes the maintainers and reviewers my give the change comment and let the submitter not to send the patch again because the change is tiny.
Indeed this is very common, but it is always agreed upon beforehand.

I treat this patch as that condition incorrectly. That's why I contact Ray to review the new commit message and help to push directly if he is OK with it. Sorry for missing you in the process.
Another problem is that the PR itself has to be created by the maintainer.

https://github.com/tianocore/tianocore.github.io/wiki/EDK-II-Development-Process#the-maintainer-process-for-the-edk-ii-project

As I understand it, the current process does not permit a contributor to
create a PR, and a maintainer to just set the "push" label on that PR.

Thanks
Laszlo



Thanks,
Zhichao

-----Original Message-----
From: Laszlo Ersek <lersek@redhat.com>
Sent: Tuesday, October 20, 2020 5:53 PM
To: devel@edk2.groups.io; Ni, Ray <ray.ni@intel.com>; Gao, Zhichao
<zhichao.gao@intel.com>; glin@suse.com
Cc: Wu, Hao A <hao.a.wu@intel.com>; Kinney, Michael D
<michael.d.kinney@intel.com>; Tom Lendacky <thomas.lendacky@amd.com>
Subject: Re: [edk2-devel] [PATCH] MdeModulePkg/PartitionDxe: Revert the child
handler blocksize change

Ray,

On 10/19/20 07:56, Ni, Ray wrote:
Zhichao,
Can you please update the commit message to address Laszlo's comments?
why did you merge <https://github.com/tianocore/edk2/pull/1033>?

PR#1033 was originally submitted as a personal build for Zhichao. When it passed
CI (and was auto-closed), Zhichao should have posted the updated patch (with
the cleaned up commit message) as v2 to the mailing list, for the next round of
review.

Instead, you reopened the (auto-closed) PR, added the push label, and the
mergify bot merged the patch. You merged a patch that was not reviewed on the
list; specifically you didn't give me any chance to re-check the commit message,
after I pointed out problems with it under the v1 thread. Of course, sometimes
we (participants in a patch review
thread) agree that the maintainer will perform some final (small) updates just
before merging the patch or series, but in this case, that has not happened -- no
specific wording was proposed or accepted in the thread, as far as I can see.

Regardin the timeline: as of this writing, Zhichao opened PR#1033 eight hours
ago, and you made the mergify bot merge the (unreviewed) patch 4 hours ago.
That is, you just wanted to get rid of it as quickly as possible, without any regard
to the community (again -- I provided
*specific* feedback under v1).

This urgency is especially appalling when contrasted with your and Eric's total
lack of feedback for Tom Lendacky's patch

[edk2-devel] [PATCH v2 1/1]
UefiCpuPkg/MpInitLib: Reduce reset vector memory pressure

https://edk2.groups.io/g/devel/message/65540

for almost a *month*. I had to merge that patch yesterday out of desperation
and embarrassment for your behaviors, with only my R-b added. You forced me
to break the development process in order not to alienate a prolific contributor.
All one of you had to do was post an Acked-by.

You can't make a contributor wait for this long, and you also can't sneak in
patches without public review (or at least public agreement about the final touch-
ups). If you can't do maintenance responsibly, for any reason, then *quit*; let
someone else become maintainer.

This behavior is a hallmark of the edk2 project not having a healthy open source
community. Sad.

Laszlo


[PATCH edk2-platforms v1 2/2] StMMRpmb: Add support for building StandaloneMm image for OP-TEE

Sughosh Ganu
 

From: Ilias Apalodimas <ilias.apalodimas@linaro.org>

With some recent changes in OP-TEE [1] and U-Boot [2] we can compile StMM
and launch it from an OP-TEE secure partition which is mimicking SPM.

There's a number of advantages in this approach. In Arm world SPM,
currently used for dispatching StMM, and SPD used for OP-TEE, are
mutually exclusive. Since there's no application in OP-TEE for managing
EFI variables, this means that one can have a secure OS or secure
variable storage.

By re-using StMM we have EDK2s approved application controlling
variable storage and the ability to run a secure world OS. This also
allows various firmware implementations to adopt EDK2 way of storing
variables (including the FTW implementation), as long as OP-TEE is
available on that given platform (or any other secure OS that can launch
StMM and has a supplicant for handling the RPMB partition).
Another advantage is that OP-TEE has the ability to access an eMMC RPMB
partition to store those variables. This requires a normal world
supplicant, which is implemented in U-Boot currently. The supplicant
picks up the encrypted buffer from OP-TEE and wires it to the eMMC
driver(s). Similar functionality can be added in EDK2 by porting the
supplicant and adapt it to using the native eMMC drivers.

There's is one drawback in using OP-TEE. The current SPM calls need to run
to completion. This contradicts the current OP-TEE RPC call requirements,
used to access the RPMB storage. Thats leads to two different SMC calls for
entering secure world to access StMM.

So let's add support for a platform that compiles StMM and an RPMB
driver that communicates with OP-TEE to read/write the variables.
For anyone interested in testing this there's repo that builds all the
sources and works on QEMU [3].

[1] https://github.com/OP-TEE/optee_os/pull/3973
[2] http://u-boot.10912.n7.nabble.com/PATCH-0-7-v4-EFI-variable-support-via-OP-TEE-td412499.html
[3] https://git.linaro.org/people/ilias.apalodimas/efi_optee_variables.git/

Signed-off-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
---
Platform/StMMRpmb/PlatformStandaloneMm.dsc | 182 ++++++++++++++++++++
Platform/StMMRpmb/PlatformStandaloneMm.fdf | 111 ++++++++++++
2 files changed, 293 insertions(+)

diff --git a/Platform/StMMRpmb/PlatformStandaloneMm.dsc b/Platform/StMMRpmb/PlatformStandaloneMm.dsc
new file mode 100644
index 0000000000..e82cd739e1
--- /dev/null
+++ b/Platform/StMMRpmb/PlatformStandaloneMm.dsc
@@ -0,0 +1,182 @@
+#
+# Copyright (c) 2018, ARM Limited. All rights reserved.
+# Copyright (c) 2020, Linaro Ltd. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+################################################################################
+#
+# Defines Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+[Defines]
+ PLATFORM_NAME = MmStandaloneRpmb
+ PLATFORM_GUID = A27A486E-D7B9-4D70-9F37-FED9ABE041A2
+ PLATFORM_VERSION = 1.0
+ DSC_SPECIFICATION = 0x00010011
+ OUTPUT_DIRECTORY = Build/$(PLATFORM_NAME)
+ SUPPORTED_ARCHITECTURES = AARCH64
+ BUILD_TARGETS = DEBUG|RELEASE|NOOPT
+ SKUID_IDENTIFIER = DEFAULT
+ FLASH_DEFINITION = Platform/StMMRpmb/PlatformStandaloneMm.fdf
+ DEFINE DEBUG_MESSAGE = TRUE
+
+ # LzmaF86
+ DEFINE COMPRESSION_TOOL_GUID = D42AE6BD-1352-4bfb-909A-CA72A6EAE889
+
+################################################################################
+#
+# Library Class section - list of all Library Classes needed by this Platform.
+#
+################################################################################
+[LibraryClasses]
+ ArmSvcLib|ArmPkg/Library/ArmSvcLib/ArmSvcLib.inf
+ ArmLib|ArmPkg/Library/ArmLib/ArmBaseLib.inf
+ BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
+ BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+ DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf
+ DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
+ ExtractGuidedSectionLib|EmbeddedPkg/Library/PrePiExtractGuidedSectionLib/PrePiExtractGuidedSectionLib.inf
+ FvLib|StandaloneMmPkg/Library/FvLib/FvLib.inf
+ HobLib|StandaloneMmPkg/Library/StandaloneMmCoreHobLib/StandaloneMmCoreHobLib.inf
+ IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
+ MemLib|StandaloneMmPkg/Library/StandaloneMmMemLib/StandaloneMmMemLib.inf
+ MemoryAllocationLib|StandaloneMmPkg/Library/StandaloneMmCoreMemoryAllocationLib/StandaloneMmCoreMemoryAllocationLib.inf
+ PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+ PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf
+ PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
+ ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf
+
+ #
+ # Entry point
+ #
+ #StandaloneMmCoreEntryPoint|StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/StandaloneMmCoreEntryPoint.inf
+ StandaloneMmCoreEntryPoint|StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/StandaloneMmCoreEntryPoint.inf
+ StandaloneMmDriverEntryPoint|MdePkg/Library/StandaloneMmDriverEntryPoint/StandaloneMmDriverEntryPoint.inf
+
+ StandaloneMmMmuLib|ArmPkg/Library/StandaloneMmMmuLib/ArmMmuStandaloneMmLib.inf
+ #CacheMaintenanceLib|ArmPkg/Library/ArmCacheMaintenanceLib/ArmCacheMaintenanceLib.inf
+ CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLibNull/BaseCacheMaintenanceLibNull.inf
+ PeCoffExtraActionLib|StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/StandaloneMmPeCoffExtraActionLib.inf
+ RngLib|MdePkg/Library/BaseRngLibNull/BaseRngLibNull.inf
+
+!if $(UART_ENABLE)
+ DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf
+ # ARM PL011 UART Driver
+ PL011UartClockLib|ArmPlatformPkg/Library/PL011UartClockLib/PL011UartClockLib.inf
+ PL011UartLib|ArmPlatformPkg/Library/PL011UartLib/PL011UartLib.inf
+ SerialPortLib|ArmPlatformPkg/Library/PL011SerialPortLib/PL011SerialPortLib.inf
+!else
+ SerialPortLib|MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf
+ DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
+!endif
+
+
+ #
+ # It is not possible to prevent the ARM compiler for generic intrinsic functions.
+ # This library provides the intrinsic functions generate by a given compiler.
+ # NULL means link this library into all ARM images.
+ #
+ NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf
+
+[LibraryClasses.common.MM_STANDALONE]
+ HobLib|StandaloneMmPkg/Library/StandaloneMmHobLib/StandaloneMmHobLib.inf
+ MmServicesTableLib|MdePkg/Library/StandaloneMmServicesTableLib/StandaloneMmServicesTableLib.inf
+ MemoryAllocationLib|StandaloneMmPkg/Library/StandaloneMmMemoryAllocationLib/StandaloneMmMemoryAllocationLib.inf
+
+ IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf
+ OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf
+ PlatformSecureLib|SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf
+ SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf
+ TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf
+################################################################################
+#
+# Pcd Section - list of all EDK II PCD Entries defined by this Platform
+#
+################################################################################
+
+[PcdsFeatureFlag.common]
+ gArmTokenSpaceGuid.PcdFfaEnable|TRUE
+
+[PcdsFixedAtBuild]
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x800000CF
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xff
+ gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask|0x0f
+
+!if $(UART_ENABLE)
+ # PL011 - Serial Terminal
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase|0x40418000
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate|115200
+ gArmPlatformTokenSpaceGuid.PL011UartClkInHz|0xA6E49C0
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultReceiveFifoDepth|0
+!endif
+
+ gEfiMdePkgTokenSpaceGuid.PcdMaximumGuidedExtractHandler|0x2
+ # Secure Storage
+ gEfiSecurityPkgTokenSpaceGuid.PcdUserPhysicalPresence|TRUE
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800
+
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize|0x00004000
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize|0x00004000
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize|0x00004000
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0x00004000
+
+[PcdsPatchableInModule]
+ # Allocated memory for EDK2 uppers layers
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase|0x0
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase|0x0
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase|0x0
+
+###################################################################################################
+#
+# Components Section - list of the modules and components that will be processed by compilation
+# tools and the EDK II tools to generate PE32/PE32+/Coff image files.
+#
+# Note: The EDK II DSC file is not used to specify how compiled binary images get placed
+# into firmware volume images. This section is just a list of modules to compile from
+# source into UEFI-compliant binaries.
+# It is the FDF file that contains information on combining binary files into firmware
+# volume images, whose concept is beyond UEFI and is described in PI specification.
+# Binary modules do not need to be listed in this section, as they should be
+# specified in the FDF file. For example: Shell binary (Shell_Full.efi), FAT binary (Fat.efi),
+# Logo (Logo.bmp), and etc.
+# There may also be modules listed in this section that are not required in the FDF file,
+# When a module listed here is excluded from FDF file, then UEFI-compliant binary will be
+# generated for it, but the binary will not be put into any firmware volume.
+#
+###################################################################################################
+[Components.common]
+ #
+ # Standalone MM components
+ #
+ Drivers/OpTeeRpmb/OpTeeRpmbFv.inf
+ StandaloneMmPkg/Core/StandaloneMmCore.inf
+ StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/StandaloneMmCpu.inf
+ MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteStandaloneMm.inf {
+ <LibraryClasses>
+ NULL|Drivers/OpTeeRpmb/FixupPcd.inf
+ }
+ MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf {
+ <LibraryClasses>
+ AuthVariableLib|SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf
+ BaseCryptLib|CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf
+ DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
+ VarCheckLib|MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf
+ NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
+ NULL|Drivers/OpTeeRpmb/FixupPcd.inf
+ }
+
+###################################################################################################
+#
+# BuildOptions Section - Define the module specific tool chain flags that should be used as
+# the default flags for a module. These flags are appended to any
+# standard flags that are defined by the build process. They can be
+# applied for any modules or only those modules with the specific
+# module style (EDK or EDKII) specified in [Components] section.
+#
+###################################################################################################
+[BuildOptions.AARCH64]
+GCC:*_*_*_DLINK_FLAGS = -z common-page-size=0x1000 -march=armv8-a+nofp
+GCC:*_*_*_CC_FLAGS = -mstrict-align
diff --git a/Platform/StMMRpmb/PlatformStandaloneMm.fdf b/Platform/StMMRpmb/PlatformStandaloneMm.fdf
new file mode 100644
index 0000000000..febc6d0d95
--- /dev/null
+++ b/Platform/StMMRpmb/PlatformStandaloneMm.fdf
@@ -0,0 +1,111 @@
+#
+# Copyright (c) 2018, ARM Limited. All rights reserved.
+# Copyright (c) 2020, Linaro Ltd. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+################################################################################
+#
+# FD Section
+# The [FD] Section is made up of the definition statements and a
+# description of what goes into the Flash Device Image. Each FD section
+# defines one flash "device" image. A flash device image may be one of
+# the following: Removable media bootable image (like a boot floppy
+# image,) an Option ROM image (that would be "flashed" into an add-in
+# card,) a System "Flash" image (that would be burned into a system's
+# flash) or an Update ("Capsule") image that will be used to update and
+# existing system flash.
+#
+################################################################################
+
+[FD.BL32_AP_MM]
+BaseAddress = 0x1000 # any address apart from 0x0
+Size = 0x00300000
+ErasePolarity = 1
+
+BlockSize = 0x00001000
+NumBlocks = 0x0300
+
+################################################################################
+#
+# Following are lists of FD Region layout which correspond to the locations of different
+# images within the flash device.
+#
+# Regions must be defined in ascending order and may not overlap.
+#
+# A Layout Region start with a eight digit hex offset (leading "0x" required) followed by
+# the pipe "|" character, followed by the size of the region, also in hex with the leading
+# "0x" characters. Like:
+# Offset|Size
+# PcdOffsetCName|PcdSizeCName
+# RegionType <FV, DATA, or FILE>
+#
+################################################################################
+
+0x00000000|0x00280000
+FV = FVMAIN_COMPACT
+
+[FV.FVMAIN_COMPACT]
+FvAlignment = 8
+ERASE_POLARITY = 1
+MEMORY_MAPPED = TRUE
+STICKY_WRITE = TRUE
+LOCK_CAP = TRUE
+LOCK_STATUS = TRUE
+WRITE_DISABLED_CAP = TRUE
+WRITE_ENABLED_CAP = TRUE
+WRITE_STATUS = TRUE
+WRITE_LOCK_CAP = TRUE
+WRITE_LOCK_STATUS = TRUE
+READ_DISABLED_CAP = TRUE
+READ_ENABLED_CAP = TRUE
+READ_STATUS = TRUE
+READ_LOCK_CAP = TRUE
+READ_LOCK_STATUS = TRUE
+
+ INF StandaloneMmPkg/Core/StandaloneMmCore.inf
+ INF Drivers/OpTeeRpmb/OpTeeRpmbFv.inf
+ INF MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteStandaloneMm.inf
+ INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
+ INF StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/StandaloneMmCpu.inf
+################################################################################
+#
+# Rules are use with the [FV] section's module INF type to define
+# how an FFS file is created for a given INF file. The following Rule are the default
+# rules for the different module type. User can add the customized rules to define the
+# content of the FFS file.
+#
+################################################################################
+
+
+############################################################################
+# Example of a DXE_DRIVER FFS file with a Checksum encapsulation section #
+############################################################################
+#
+#[Rule.Common.DXE_DRIVER]
+# FILE DRIVER = $(NAMED_GUID) {
+# DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
+# COMPRESS PI_STD {
+# GUIDED {
+# PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi
+# UI STRING="$(MODULE_NAME)" Optional
+# VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER)
+# }
+# }
+# }
+#
+############################################################################
+
+[Rule.Common.MM_CORE_STANDALONE]
+ FILE SEC = $(NAMED_GUID) FIXED {
+ PE32 PE32 Align = Auto $(INF_OUTPUT)/$(MODULE_NAME).efi
+ }
+
+[Rule.Common.MM_STANDALONE]
+ FILE MM_STANDALONE = $(NAMED_GUID) {
+ SMM_DEPEX SMM_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex
+ PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi
+ UI STRING="$(MODULE_NAME)" Optional
+ VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER)
+ }
--
2.17.1


[PATCH edk2-platforms v1 1/2] Drivers/OpTeeRpmb: Add an OP-TEE backed RPMB driver

Sughosh Ganu
 

From: Ilias Apalodimas <ilias.apalodimas@linaro.org>

A following patch is adding support for building StMM in order to run it
from OP-TEE.
OP-TEE in combination with a NS-world supplicant can use the RPMB
partition of an eMMC to store EFI variables. The supplicant
functionality is currently available in U-Boot only but can be ported
into EDK2. Assuming similar functionality is added in EDK2, this will
allow any hardware with an RPMB partition to store EFI variables
securely.

So let's add a driver that enables access of the RPMB partition through
OP-TEE. Since the upper layers expect a byte addressable interface,
the driver allocates memory and patches the PCDs, while syncing the
memory/hardware on read/write callbacks.

Signed-off-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
---
Drivers/OpTeeRpmb/FixupPcd.inf | 44 ++
Drivers/OpTeeRpmb/OpTeeRpmbFv.inf | 58 ++
Drivers/OpTeeRpmb/OpTeeRpmbFvb.h | 52 ++
Drivers/OpTeeRpmb/FixupPcd.c | 74 ++
Drivers/OpTeeRpmb/OpTeeRpmbFvb.c | 775 ++++++++++++++++++++
5 files changed, 1003 insertions(+)

diff --git a/Drivers/OpTeeRpmb/FixupPcd.inf b/Drivers/OpTeeRpmb/FixupPcd.inf
new file mode 100644
index 0000000000..f0cfdf7a4c
--- /dev/null
+++ b/Drivers/OpTeeRpmb/FixupPcd.inf
@@ -0,0 +1,44 @@
+## @file
+# Instance of Base Memory Library without assembly.
+#
+# Copyright (c) 2020, Linaro Ltd. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001A
+ BASE_NAME = FixupPcd
+ FILE_GUID = a827c337-a9c6-301b-aeb7-acbc95d8da22
+ MODULE_TYPE = BASE
+ VERSION_STRING = 0.1
+ LIBRARY_CLASS = RpmbPcdFixup|MM_STANDALONE
+ CONSTRUCTOR = FixPcdMemory
+
+[Sources]
+ FixupPcd.c
+ OpTeeRpmbFvb.h
+
+[Packages]
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ MmServicesTableLib
+ PcdLib
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
+
+
+[Protocols]
+ gEfiSmmFirmwareVolumeBlockProtocolGuid ## CONSUMES
diff --git a/Drivers/OpTeeRpmb/OpTeeRpmbFv.inf b/Drivers/OpTeeRpmb/OpTeeRpmbFv.inf
new file mode 100644
index 0000000000..b21f7397e5
--- /dev/null
+++ b/Drivers/OpTeeRpmb/OpTeeRpmbFv.inf
@@ -0,0 +1,58 @@
+## @file
+#
+# Component description file for OpTeeRpmbFv module
+#
+# Copyright (c) 2020, Linaro Ltd. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001A
+ BASE_NAME = OpTeeRpmbFv
+ FILE_GUID = 4803FC20-E583-3BCD-8C60-141E85C9A2CF
+ MODULE_TYPE = MM_STANDALONE
+ VERSION_STRING = 0.1
+ PI_SPECIFICATION_VERSION = 0x00010032
+ ENTRY_POINT = OpTeeRpmbFvbInit
+
+[Sources]
+ OpTeeRpmbFvb.c
+ OpTeeRpmbFvb.h
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ ArmPlatformPkg/ArmPlatformPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ StandaloneMmPkg/StandaloneMmPkg.dec
+
+[LibraryClasses]
+ ArmSvcLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ MmServicesTableLib
+ PcdLib
+ StandaloneMmDriverEntryPoint
+
+[Guids]
+ gEfiAuthenticatedVariableGuid
+ gEfiSystemNvDataFvGuid
+ gEfiVariableGuid
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
+
+[Protocols]
+ gEfiSmmFirmwareVolumeBlockProtocolGuid ## PRODUCES
+
+[Depex]
+ TRUE
diff --git a/Drivers/OpTeeRpmb/OpTeeRpmbFvb.h b/Drivers/OpTeeRpmb/OpTeeRpmbFvb.h
new file mode 100644
index 0000000000..f6c3fe2639
--- /dev/null
+++ b/Drivers/OpTeeRpmb/OpTeeRpmbFvb.h
@@ -0,0 +1,52 @@
+/** @file
+
+ Copyright (c) 2020, Linaro Ltd. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __OPTEE_RPMB_FV_
+#define __OPTEE_RPMB_FV_
+
+/* SVC Args */
+#define SP_SVC_RPMB_READ 0xC4000066
+#define SP_SVC_RPMB_WRITE 0xC4000067
+#define SP_SVC_GET_UART 0xC4000068
+
+#define FILENAME "EFI_VARS"
+
+#define NBLOCKS (3 * 16) // EFI Vars, FTW working, FTW spare
+#define BLOCK_SIZE SIZE_4KB
+#define FLASH_SIGNATURE SIGNATURE_32('r', 'p', 'm', 'b')
+#define INSTANCE_FROM_FVB_THIS(a) CR(a, MEM_INSTANCE, FvbProtocol, \
+ FLASH_SIGNATURE)
+enum _RPMB_FILE_MAP {
+ EFI_VARS,
+ FTW_WORK,
+ FTW_SPARE,
+};
+
+typedef enum _RPMB_FILE_MAP RPMB_FILE_MAP;
+
+struct _MAP_VAL_TO_FILE {
+ CHAR8 *Filename;
+ RPMB_FILE_MAP Map;
+};
+
+typedef struct _MAP_VAL_TO_FILE MAP_VAL_TO_FILE;
+
+typedef struct _MEM_INSTANCE MEM_INSTANCE;
+typedef EFI_STATUS (*MEM_INITIALIZE) (MEM_INSTANCE* Instance);
+struct _MEM_INSTANCE
+{
+ UINT32 Signature;
+ MEM_INITIALIZE Initialize;
+ BOOLEAN Initialized;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL FvbProtocol;
+ EFI_HANDLE Handle;
+ EFI_PHYSICAL_ADDRESS MemBaseAddress;
+ UINT16 BlockSize;
+ UINT16 NBlocks;
+};
+
+#endif
diff --git a/Drivers/OpTeeRpmb/FixupPcd.c b/Drivers/OpTeeRpmb/FixupPcd.c
new file mode 100644
index 0000000000..3cc882fa94
--- /dev/null
+++ b/Drivers/OpTeeRpmb/FixupPcd.c
@@ -0,0 +1,74 @@
+/** @file
+
+ Update the patched PCDs to their correct value
+
+ Copyright (c) 2020, Linaro Ltd. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+/**
+ * Patch the relevant PCDs of the RPMB driver with the correct address of the
+ * allocated memory
+ *
+**/
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MmServicesTableLib.h>
+#include <Library/PcdLib.h>
+
+#include <Protocol/FirmwareVolumeBlock.h>
+#include <Protocol/SmmFirmwareVolumeBlock.h>
+
+#include "OpTeeRpmbFvb.h"
+
+/**
+ Fixup the Pcd values for variable storage
+
+ Since the upper layers of EDK2 expect a memory mapped interface and we can't
+ offer that from an RPMB, the driver allocates memory on init and passes that
+ on the upper layers. Since the memory is dynamically allocated and we can't set the
+ PCD is StMM context, we need to patch it correctly on each access
+
+ @retval EFI_SUCCESS Protocol was found and PCDs patched up
+
+ **/
+EFI_STATUS
+EFIAPI
+FixPcdMemory (
+ VOID
+ )
+{
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol;
+ MEM_INSTANCE *Instance;
+ EFI_STATUS Status;
+
+ //
+ // Locate SmmFirmwareVolumeBlockProtocol
+ //
+ Status = gMmst->MmLocateProtocol (
+ &gEfiSmmFirmwareVolumeBlockProtocolGuid,
+ NULL,
+ (VOID **) &FvbProtocol
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Instance = INSTANCE_FROM_FVB_THIS(FvbProtocol);
+ // Patch PCDs with the the correct values
+ PatchPcdSet32 (PcdFlashNvStorageVariableBase, Instance->MemBaseAddress);
+ PatchPcdSet32 (PcdFlashNvStorageFtwWorkingBase, Instance->MemBaseAddress +
+ PcdGet32 (PcdFlashNvStorageVariableSize));
+ PatchPcdSet32 (PcdFlashNvStorageFtwSpareBase, Instance->MemBaseAddress +
+ PcdGet32 (PcdFlashNvStorageVariableSize) +
+ PcdGet32 (PcdFlashNvStorageFtwWorkingSize));
+
+ DEBUG ((DEBUG_INFO, "%a: Fixup PcdFlashNvStorageVariableBase: 0x%lx\n",
+ __FUNCTION__, PcdGet32 (PcdFlashNvStorageVariableBase)));
+ DEBUG ((DEBUG_INFO, "%a: Fixup PcdFlashNvStorageFtwWorkingBase: 0x%lx\n",
+ __FUNCTION__, PcdGet32 (PcdFlashNvStorageFtwWorkingBase)));
+ DEBUG ((DEBUG_INFO, "%a: Fixup PcdFlashNvStorageFtwSpareBase: 0x%lx\n",
+ __FUNCTION__, PcdGet32 (PcdFlashNvStorageFtwSpareBase)));
+
+ return Status;
+}
diff --git a/Drivers/OpTeeRpmb/OpTeeRpmbFvb.c b/Drivers/OpTeeRpmb/OpTeeRpmbFvb.c
new file mode 100644
index 0000000000..27b857da22
--- /dev/null
+++ b/Drivers/OpTeeRpmb/OpTeeRpmbFvb.c
@@ -0,0 +1,775 @@
+/** @file
+
+ FV block I/O protocol driver for RPMB eMMC accessed via OP-TEE
+
+ Copyright (c) 2020, Linaro Ltd. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/ArmSvcLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/MmServicesTableLib.h>
+#include <Library/PcdLib.h>
+
+#include <IndustryStandard/ArmFfaSvc.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+#include <Protocol/SmmFirmwareVolumeBlock.h>
+#include <Guid/VariableFormat.h>
+
+#include "OpTeeRpmbFvb.h"
+
+static const UINT16 mem_mgr_id = 3U;
+static const UINT16 storage_id = 4U;
+
+STATIC MEM_INSTANCE mInstance;
+
+/**
+ Sends an SVC call to OP-TEE for reading/writing an RPMB partition
+
+ @param SvcAct SVC ID for read/write
+ @param Addr Base address of the buffer. When reading contents will be
+ copied to that buffer after reading them from the device.
+ When writing, the buffer holds the contents we want to
+ write cwtoin the device
+ @param NumBytes Number of bytes to read/write
+ @param Offset Offset into the RPMB file
+
+ @retval OP-TEE return code
+**/
+
+STATIC
+UINTN
+ReadWriteRpmb (
+ UINTN SvcAct,
+ UINTN Addr,
+ UINTN NumBytes,
+ UINTN Offset
+ )
+{
+ ARM_SVC_ARGS SvcArgs;
+
+ ZeroMem (&SvcArgs, sizeof (SvcArgs));
+
+ SvcArgs.Arg0 = ARM_SVC_ID_FFA_MSG_SEND_DIRECT_REQ_AARCH64;
+ SvcArgs.Arg1 = storage_id;
+ SvcArgs.Arg2 = 0;
+ SvcArgs.Arg3 = SvcAct;
+ SvcArgs.Arg4 = Addr;
+ SvcArgs.Arg5 = NumBytes;
+ SvcArgs.Arg6 = Offset;
+
+ ArmCallSvc (&SvcArgs);
+ if (SvcArgs.Arg3) {
+ DEBUG ((DEBUG_ERROR, "%a: Svc Call 0x%08x Addr: 0x%08x len: 0x%x Offset: 0x%x failed with 0x%x\n",
+ __func__, SvcAct, Addr, NumBytes, Offset, SvcArgs.Arg3));
+ }
+
+ return SvcArgs.Arg3;
+}
+
+/**
+ The GetAttributes() function retrieves the attributes and
+ current settings of the block.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL instance.
+
+ @param Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the
+ attributes and current settings are
+ returned. Type EFI_FVB_ATTRIBUTES_2 is defined
+ in EFI_FIRMWARE_VOLUME_HEADER.
+
+ @retval EFI_SUCCESS The firmware volume attributes were
+ returned.
+
+**/
+STATIC
+EFI_STATUS
+OpTeeRpmbFvbGetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ )
+{
+ *Attributes = EFI_FVB2_READ_ENABLED_CAP | // Reads may be enabled
+ EFI_FVB2_READ_STATUS | // Reads are currently enabled
+ EFI_FVB2_WRITE_STATUS | // Writes are currently enabled
+ EFI_FVB2_WRITE_ENABLED_CAP | // Writes may be enabled
+ EFI_FVB2_STICKY_WRITE | // A block erase is required to flip bits into EFI_FVB2_ERASE_POLARITY
+ EFI_FVB2_MEMORY_MAPPED | // It is memory mapped
+ EFI_FVB2_ERASE_POLARITY; // After erasure all bits take this value (i.e. '1')
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The SetAttributes() function sets configurable firmware volume
+ attributes and returns the new settings of the firmware volume.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL instance.
+
+ @param Attributes On input, Attributes is a pointer to
+ EFI_FVB_ATTRIBUTES_2 that contains the
+ desired firmware volume settings. On
+ successful return, it contains the new
+ settings of the firmware volume. Type
+ EFI_FVB_ATTRIBUTES_2 is defined in
+ EFI_FIRMWARE_VOLUME_HEADER.
+
+ @retval EFI_SUCCESS The firmware volume attributes were returned.
+
+ @retval EFI_INVALID_PARAMETER The attributes requested are in
+ conflict with the capabilities
+ as declared in the firmware
+ volume header.
+
+**/
+STATIC
+EFI_STATUS
+OpTeeRpmbFvbSetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ )
+{
+ return EFI_SUCCESS; // ignore for now
+}
+
+/**
+ The GetPhysicalAddress() function retrieves the base address of
+ a memory-mapped firmware volume. This function should be called
+ only for memory-mapped firmware volumes.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL instance.
+
+ @param Address Pointer to a caller-allocated
+ EFI_PHYSICAL_ADDRESS that, on successful
+ return from GetPhysicalAddress(), contains the
+ base address of the firmware volume.
+
+ @retval EFI_SUCCESS The firmware volume base address was returned.
+
+ @retval EFI_UNSUPPORTED The firmware volume is not memory mapped.
+
+**/
+STATIC
+EFI_STATUS
+OpTeeRpmbFvbGetPhysicalAddress (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ OUT EFI_PHYSICAL_ADDRESS *Address
+ )
+{
+ MEM_INSTANCE *Instance;
+
+ Instance = INSTANCE_FROM_FVB_THIS(This);
+ *Address = Instance->MemBaseAddress;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The GetBlockSize() function retrieves the size of the requested
+ block. It also returns the number of additional blocks with
+ the identical size. The GetBlockSize() function is used to
+ retrieve the block map (see EFI_FIRMWARE_VOLUME_HEADER).
+
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL instance.
+
+ @param Lba Indicates the block for which to return the size.
+
+ @param BlockSize Pointer to a caller-allocated UINTN in which
+ the size of the block is returned.
+
+ @param NumberOfBlocks Pointer to a caller-allocated UINTN in
+ which the number of consecutive blocks,
+ starting with Lba, is returned. All
+ blocks in this range have a size of
+ BlockSize.
+
+
+ @retval EFI_SUCCESS The firmware volume base address was returned.
+
+ @retval EFI_INVALID_PARAMETER The requested LBA is out of range.
+
+**/
+STATIC
+EFI_STATUS
+OpTeeRpmbFvbGetBlockSize (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ OUT UINTN *BlockSize,
+ OUT UINTN *NumberOfBlocks
+ )
+{
+ MEM_INSTANCE *Instance;
+
+ Instance = INSTANCE_FROM_FVB_THIS(This);
+ if (Lba >= Instance->NBlocks) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *NumberOfBlocks = Instance->NBlocks - (UINTN) Lba;
+ *BlockSize = Instance->BlockSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Reads the specified number of bytes into a buffer from the specified block.
+
+ The Read() function reads the requested number of bytes from the
+ requested block and stores them in the provided buffer.
+ Implementations should be mindful that the firmware volume
+ might be in the ReadDisabled state. If it is in this state,
+ the Read() function must return the status code
+ EFI_ACCESS_DENIED without modifying the contents of the
+ buffer. The Read() function must also prevent spanning block
+ boundaries. If a read is requested that would span a block
+ boundary, the read must read up to the boundary but not
+ beyond. The output parameter NumBytes must be set to correctly
+ indicate the number of bytes actually read. The caller must be
+ aware that a read may be partially completed.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL instance.
+
+ @param Lba The starting logical block index
+ from which to read.
+
+ @param Offset Offset into the block at which to begin reading.
+
+ @param NumBytes Pointer to a UINTN. At entry, *NumBytes
+ contains the total size of the buffer. At
+ exit, *NumBytes contains the total number of
+ bytes read.
+
+ @param Buffer Pointer to a caller-allocated buffer that will
+ be used to hold the data that is read.
+
+ @retval EFI_SUCCESS The firmware volume was read successfully,
+ and contents are in Buffer.
+
+ @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA
+ boundary. On output, NumBytes
+ contains the total number of bytes
+ returned in Buffer.
+
+ @retval EFI_ACCESS_DENIED The firmware volume is in the
+ ReadDisabled state.
+
+ @retval EFI_DEVICE_ERROR The block device is not
+ functioning correctly and could
+ not be read.
+
+**/
+
+STATIC
+EFI_STATUS
+OpTeeRpmbFvbRead (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN OUT UINT8 *Buffer
+ )
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ MEM_INSTANCE *Instance;
+ VOID *Base;
+
+ Instance = INSTANCE_FROM_FVB_THIS(This);
+ if (Instance->Initialized == FALSE) {
+ Instance->Initialize (Instance);
+ }
+
+ Base = (VOID *)Instance->MemBaseAddress + Lba * Instance->BlockSize + Offset;
+ // We could read the data from the RPMB instead of memory
+ // The 2 copies should already be identical
+ // Copy from memory image
+ CopyMem (Buffer, Base, *NumBytes);
+
+ return Status;
+}
+
+/**
+ Writes the specified number of bytes from the input buffer to the block.
+
+ The Write() function writes the specified number of bytes from
+ the provided buffer to the specified block and offset. If the
+ firmware volume is sticky write, the caller must ensure that
+ all the bits of the specified range to write are in the
+ EFI_FVB_ERASE_POLARITY state before calling the Write()
+ function, or else the result will be unpredictable. This
+ unpredictability arises because, for a sticky-write firmware
+ volume, a write may negate a bit in the EFI_FVB_ERASE_POLARITY
+ state but cannot flip it back again. Before calling the
+ Write() function, it is recommended for the caller to first call
+ the EraseBlocks() function to erase the specified block to
+ write. A block erase cycle will transition bits from the
+ (NOT)EFI_FVB_ERASE_POLARITY state back to the
+ EFI_FVB_ERASE_POLARITY state. Implementations should be
+ mindful that the firmware volume might be in the WriteDisabled
+ state. If it is in this state, the Write() function must
+ return the status code EFI_ACCESS_DENIED without modifying the
+ contents of the firmware volume. The Write() function must
+ also prevent spanning block boundaries. If a write is
+ requested that spans a block boundary, the write must store up
+ to the boundary but not beyond. The output parameter NumBytes
+ must be set to correctly indicate the number of bytes actually
+ written. The caller must be aware that a write may be
+ partially completed. All writes, partial or otherwise, must be
+ fully flushed to the hardware before the Write() service
+ returns.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL instance.
+
+ @param Lba The starting logical block index to write to.
+
+ @param Offset Offset into the block at which to begin writing.
+
+ @param NumBytes The pointer to a UINTN. At entry, *NumBytes
+ contains the total size of the buffer. At
+ exit, *NumBytes contains the total number of
+ bytes actually written.
+
+ @param Buffer The pointer to a caller-allocated buffer that
+ contains the source for the write.
+
+ @retval EFI_SUCCESS The firmware volume was written successfully.
+
+ @retval EFI_BAD_BUFFER_SIZE The write was attempted across an
+ LBA boundary. On output, NumBytes
+ contains the total number of bytes
+ actually written.
+
+ @retval EFI_ACCESS_DENIED The firmware volume is in the
+ WriteDisabled state.
+
+ @retval EFI_DEVICE_ERROR The block device is malfunctioning
+ and could not be written.
+
+
+**/
+STATIC
+EFI_STATUS
+OpTeeRpmbFvbWrite (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN UINT8 *Buffer
+ )
+{
+ MEM_INSTANCE *Instance;
+ EFI_STATUS Status = EFI_SUCCESS;
+ VOID *Base;
+ UINTN Ret;
+
+ Instance = INSTANCE_FROM_FVB_THIS(This);
+ if (Instance->Initialized == FALSE) {
+ Instance->Initialize (Instance);
+ }
+ Base = (VOID *)Instance->MemBaseAddress + Lba * Instance->BlockSize + Offset;
+ // We can map OP-TEE errors to EFI exitcodes and return a more
+ // realistic error. Keep it simple for now
+ Ret = ReadWriteRpmb (SP_SVC_RPMB_WRITE, (UINTN) Buffer, *NumBytes,
+ Lba * Instance->BlockSize + Offset);
+ if (Ret) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ // Update the memory copy
+ CopyMem (Base, Buffer, *NumBytes);
+
+ return Status;
+}
+
+/**
+ Erases and initializes a firmware volume block.
+
+ The EraseBlocks() function erases one or more blocks as denoted
+ by the variable argument list. The entire parameter list of
+ blocks must be verified before erasing any blocks. If a block is
+ requested that does not exist within the associated firmware
+ volume (it has a larger index than the last block of the
+ firmware volume), the EraseBlocks() function must return the
+ status code EFI_INVALID_PARAMETER without modifying the contents
+ of the firmware volume. Implementations should be mindful that
+ the firmware volume might be in the WriteDisabled state. If it
+ is in this state, the EraseBlocks() function must return the
+ status code EFI_ACCESS_DENIED without modifying the contents of
+ the firmware volume. All calls to EraseBlocks() must be fully
+ flushed to the hardware before the EraseBlocks() service
+ returns.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
+ instance.
+
+ @param ... The variable argument list is a list of tuples.
+ Each tuple describes a range of LBAs to erase
+ and consists of the following:
+ - An EFI_LBA that indicates the starting LBA
+ - A UINTN that indicates the number of blocks to
+ erase.
+
+ The list is terminated with an
+ EFI_LBA_LIST_TERMINATOR. For example, the
+ following indicates that two ranges of blocks
+ (5-7 and 10-11) are to be erased: EraseBlocks
+ (This, 5, 3, 10, 2, EFI_LBA_LIST_TERMINATOR);
+
+ @retval EFI_SUCCESS The erase request successfully
+ completed.
+
+ @retval EFI_ACCESS_DENIED The firmware volume is in the
+ WriteDisabled state.
+ @retval EFI_DEVICE_ERROR The block device is not functioning
+ correctly and could not be written.
+ The firmware device may have been
+ partially erased.
+ @retval EFI_INVALID_PARAMETER One or more of the LBAs listed
+ in the variable argument list do
+ not exist in the firmware volume.
+
+**/
+STATIC
+EFI_STATUS
+OpTeeRpmbFvbErase (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
+ ...
+ )
+{
+ MEM_INSTANCE *Instance;
+ UINTN NumBytes;
+ UINTN NumLba;
+ EFI_LBA Start;
+ VOID *Base;
+ VOID *Buf;
+ VA_LIST Args;
+ UINTN Ret;
+
+ Instance = INSTANCE_FROM_FVB_THIS(This);
+
+ VA_START (Args, This);
+ for (Start = VA_ARG (Args, EFI_LBA);
+ Start != EFI_LBA_LIST_TERMINATOR;
+ Start = VA_ARG (Args, EFI_LBA)) {
+ NumLba = VA_ARG (Args, UINTN);
+ if (Start + NumLba >= Instance->NBlocks) {
+ return EFI_INVALID_PARAMETER;
+ }
+ NumBytes = NumLba * Instance->BlockSize;
+ Base = (VOID *)Instance->MemBaseAddress + Start * Instance->BlockSize;
+ Buf = AllocatePool(NumLba * Instance->BlockSize);
+ SetMem64 (Buf, NumLba * Instance->BlockSize, ~0UL);
+ if (!Buf) {
+ return EFI_DEVICE_ERROR;
+ }
+ // Write the device
+ Ret = ReadWriteRpmb (SP_SVC_RPMB_WRITE, (UINTN) Buf, NumBytes,
+ Start * Instance->BlockSize);
+ if (Ret) {
+ return EFI_DEVICE_ERROR;
+ }
+ // Update the in memory copy
+ SetMem64 (Base, NumLba * Instance->BlockSize, ~0UL);
+ FreePool (Buf);
+ }
+
+ VA_END (Args);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Since we use a memory backed storage we need to restore the RPMB contents
+ into memory before we register the Fvb protocol.
+
+ @param Instace Address to copy flash contents to
+
+ @retval 0 on success, OP-TEE error on failure
+**/
+STATIC
+VOID
+ReadEntireFlash (
+ MEM_INSTANCE *Instance
+ )
+{
+ UINTN ReadAddr;
+
+ UINTN StorageFtwWorkingSize = PcdGet32(PcdFlashNvStorageFtwWorkingSize);
+ UINTN StorageVariableSize = PcdGet32(PcdFlashNvStorageVariableSize);
+ UINTN StorageFtwSpareSize = PcdGet32(PcdFlashNvStorageFtwSpareSize);
+
+ ReadAddr = Instance->MemBaseAddress;
+ // There's no need to check if the read failed here. The upper EDK2 layers
+ // will initialize the flash correctly if the in-memory copy is wrong
+ ReadWriteRpmb(SP_SVC_RPMB_READ, ReadAddr, StorageVariableSize +
+ StorageFtwWorkingSize + StorageFtwSpareSize , 0);
+}
+
+
+STATIC
+EFI_STATUS
+EFIAPI
+ValidateFvHeader (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader
+ )
+{
+ UINT16 Checksum;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ UINTN VariableStoreLength;
+ UINTN FvLength;
+
+ FvLength = PcdGet32(PcdFlashNvStorageVariableSize) +
+ PcdGet32(PcdFlashNvStorageFtwWorkingSize) +
+ PcdGet32(PcdFlashNvStorageFtwSpareSize);
+
+ // Verify the header revision, header signature, length
+ // Length of FvBlock cannot be 2**64-1
+ // HeaderLength cannot be an odd number
+ //
+ if ( (FwVolHeader->Revision != EFI_FVH_REVISION)
+ || (FwVolHeader->Signature != EFI_FVH_SIGNATURE)
+ || (FwVolHeader->FvLength != FvLength)
+ )
+ {
+ DEBUG ((DEBUG_INFO, "%a: No Firmware Volume header present\n",
+ __FUNCTION__));
+ return EFI_NOT_FOUND;
+ }
+
+ // Check the Firmware Volume Guid
+ if (!CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid)) {
+ DEBUG ((DEBUG_INFO, "%a: Firmware Volume Guid non-compatible\n",
+ __FUNCTION__));
+ return EFI_NOT_FOUND;
+ }
+
+ // Verify the header checksum
+ Checksum = CalculateSum16((UINT16*)FwVolHeader, FwVolHeader->HeaderLength);
+ if (Checksum != 0) {
+ DEBUG ((DEBUG_INFO, "%a: FV checksum is invalid (Checksum:0x%X)\n",
+ __FUNCTION__, Checksum));
+ return EFI_NOT_FOUND;
+ }
+
+ VariableStoreHeader = (VOID *)((UINTN)FwVolHeader +
+ FwVolHeader->HeaderLength);
+
+ // Check the Variable Store Guid
+ if (!CompareGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid) &&
+ !CompareGuid (&VariableStoreHeader->Signature,
+ &gEfiAuthenticatedVariableGuid)) {
+ DEBUG ((DEBUG_INFO, "%a: Variable Store Guid non-compatible\n",
+ __FUNCTION__));
+ return EFI_NOT_FOUND;
+ }
+
+ VariableStoreLength = PcdGet32 (PcdFlashNvStorageVariableSize) -
+ FwVolHeader->HeaderLength;
+ if (VariableStoreHeader->Size != VariableStoreLength) {
+ DEBUG ((DEBUG_INFO, "%a: Variable Store Length does not match\n",
+ __FUNCTION__));
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+STATIC
+EFI_STATUS
+InitializeFvAndVariableStoreHeaders (
+ MEM_INSTANCE *Instance
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *FirmwareVolumeHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ EFI_STATUS Status = EFI_SUCCESS;
+ UINTN HeadersLength;
+ VOID* Headers;
+ UINTN Ret;
+
+ HeadersLength = sizeof(EFI_FIRMWARE_VOLUME_HEADER) +
+ sizeof(EFI_FV_BLOCK_MAP_ENTRY) +
+ sizeof(VARIABLE_STORE_HEADER);
+ Headers = AllocateZeroPool(HeadersLength);
+
+ //
+ // EFI_FIRMWARE_VOLUME_HEADER
+ //
+ FirmwareVolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Headers;
+ CopyGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid);
+ FirmwareVolumeHeader->FvLength =
+ PcdGet32(PcdFlashNvStorageVariableSize) +
+ PcdGet32(PcdFlashNvStorageFtwWorkingSize) +
+ PcdGet32(PcdFlashNvStorageFtwSpareSize);
+ FirmwareVolumeHeader->Signature = EFI_FVH_SIGNATURE;
+ FirmwareVolumeHeader->Attributes = EFI_FVB2_READ_ENABLED_CAP |
+ EFI_FVB2_READ_STATUS |
+ EFI_FVB2_STICKY_WRITE |
+ EFI_FVB2_MEMORY_MAPPED |
+ EFI_FVB2_ERASE_POLARITY |
+ EFI_FVB2_WRITE_STATUS |
+ EFI_FVB2_WRITE_ENABLED_CAP;
+
+ FirmwareVolumeHeader->HeaderLength = sizeof(EFI_FIRMWARE_VOLUME_HEADER) +
+ sizeof(EFI_FV_BLOCK_MAP_ENTRY);
+ FirmwareVolumeHeader->Revision = EFI_FVH_REVISION;
+ FirmwareVolumeHeader->BlockMap[0].NumBlocks = Instance->NBlocks;
+ FirmwareVolumeHeader->BlockMap[0].Length = Instance->BlockSize;
+ FirmwareVolumeHeader->BlockMap[1].NumBlocks = 0;
+ FirmwareVolumeHeader->BlockMap[1].Length = 0;
+ FirmwareVolumeHeader->Checksum = CalculateCheckSum16 (
+ (UINT16*)FirmwareVolumeHeader,
+ FirmwareVolumeHeader->HeaderLength);
+
+ //
+ // VARIABLE_STORE_HEADER
+ //
+ VariableStoreHeader = (VOID *)((UINTN)Headers +
+ FirmwareVolumeHeader->HeaderLength);
+ CopyGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid);
+ VariableStoreHeader->Size = PcdGet32(PcdFlashNvStorageVariableSize) -
+ FirmwareVolumeHeader->HeaderLength;
+ VariableStoreHeader->Format = VARIABLE_STORE_FORMATTED;
+ VariableStoreHeader->State = VARIABLE_STORE_HEALTHY;
+
+ Ret = ReadWriteRpmb(SP_SVC_RPMB_WRITE, (UINTN) Headers, HeadersLength, 0);
+ if (Ret) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ // Install the combined header in memory
+ CopyMem ((VOID*) Instance->MemBaseAddress, Headers, HeadersLength);
+
+Exit:
+ FreePool (Headers);
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+FvbInitialize (
+ MEM_INSTANCE *Instance
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ EFI_STATUS Status;
+ UINTN Ret;
+
+ if (Instance->Initialized == TRUE) {
+ return EFI_SUCCESS;
+ }
+
+ // FirmwareVolumeHeader->FvLength is declared to have the Variable area
+ // AND the FTW working area AND the FTW Spare contiguous.
+ ASSERT (PcdGet32 (PcdFlashNvStorageVariableBase) +
+ PcdGet32 (PcdFlashNvStorageVariableSize) ==
+ PcdGet32 (PcdFlashNvStorageFtwWorkingBase));
+ ASSERT (PcdGet32 (PcdFlashNvStorageFtwWorkingBase) +
+ PcdGet32 (PcdFlashNvStorageFtwWorkingSize) ==
+ PcdGet32 (PcdFlashNvStorageFtwSpareBase));
+
+ // Check if the size of the area is at least one block size
+ ASSERT ((PcdGet32 (PcdFlashNvStorageVariableSize) > 0) &&
+ (PcdGet32 (PcdFlashNvStorageVariableSize) / Instance->BlockSize > 0));
+ ASSERT ((PcdGet32 (PcdFlashNvStorageFtwWorkingSize) > 0) &&
+ (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) / Instance->BlockSize > 0));
+ ASSERT ((PcdGet32 (PcdFlashNvStorageFtwSpareSize) > 0) &&
+ (PcdGet32 (PcdFlashNvStorageFtwSpareSize) / Instance->BlockSize > 0));
+
+ // Ensure the Variable areas are aligned on block size boundaries
+ ASSERT ((PcdGet32 (PcdFlashNvStorageVariableBase) % Instance->BlockSize) == 0);
+ ASSERT ((PcdGet32 (PcdFlashNvStorageFtwWorkingBase) % Instance->BlockSize) == 0);
+ ASSERT ((PcdGet32 (PcdFlashNvStorageFtwSpareBase) % Instance->BlockSize) == 0);
+
+ // Read the file from disk and copy it to memory
+ ReadEntireFlash (Instance);
+
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) Instance->MemBaseAddress;
+ Status = ValidateFvHeader(FwVolHeader);
+ if (EFI_ERROR (Status)) {
+ // There is no valid header, so time to install one.
+ DEBUG ((DEBUG_INFO, "%a: The FVB Header is not valid.\n", __FUNCTION__));
+
+ // Reset memory
+ SetMem64 ((VOID *)Instance->MemBaseAddress, Instance->NBlocks * Instance->BlockSize, ~0UL);
+ DEBUG ((DEBUG_INFO, "%a: Erasing Flash.\n", __FUNCTION__));
+ Ret = ReadWriteRpmb(SP_SVC_RPMB_WRITE, Instance->MemBaseAddress,
+ PcdGet32(PcdFlashNvStorageVariableSize) +
+ PcdGet32(PcdFlashNvStorageFtwWorkingSize) +
+ PcdGet32(PcdFlashNvStorageFtwSpareSize), 0);
+ if (Ret) {
+ return EFI_DEVICE_ERROR;
+ }
+ // Install all appropriate headers
+ DEBUG ((DEBUG_INFO, "%a: Installing a correct one for this volume.\n",
+ __FUNCTION__));
+ Status = InitializeFvAndVariableStoreHeaders (Instance);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ DEBUG ((DEBUG_INFO, "%a: Found valid FVB Header.\n", __FUNCTION__));
+ }
+ Instance->Initialized = TRUE;
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+OpTeeRpmbFvbInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_MM_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ VOID *Addr;
+
+ Addr = AllocatePages(NBLOCKS);
+ ASSERT (Addr != NULL);
+
+ SetMem (&mInstance, sizeof (mInstance), 0);
+
+ mInstance.FvbProtocol.GetPhysicalAddress = OpTeeRpmbFvbGetPhysicalAddress;
+ mInstance.FvbProtocol.GetAttributes = OpTeeRpmbFvbGetAttributes;
+ mInstance.FvbProtocol.SetAttributes = OpTeeRpmbFvbSetAttributes;
+ mInstance.FvbProtocol.GetBlockSize = OpTeeRpmbFvbGetBlockSize;
+ mInstance.FvbProtocol.EraseBlocks = OpTeeRpmbFvbErase;
+ mInstance.FvbProtocol.Write = OpTeeRpmbFvbWrite;
+ mInstance.FvbProtocol.Read = OpTeeRpmbFvbRead;
+
+ mInstance.MemBaseAddress = (EFI_PHYSICAL_ADDRESS) Addr;
+ mInstance.Signature = FLASH_SIGNATURE;
+ mInstance.Initialize = FvbInitialize;
+ mInstance.BlockSize = BLOCK_SIZE;
+ mInstance.NBlocks = NBLOCKS;
+
+ // Update the defined PCDs related to Variable Storage
+ PatchPcdSet32 (PcdFlashNvStorageVariableBase, mInstance.MemBaseAddress);
+ PatchPcdSet32 (PcdFlashNvStorageFtwWorkingBase, mInstance.MemBaseAddress +
+ PcdGet32 (PcdFlashNvStorageVariableSize));
+ PatchPcdSet32 (PcdFlashNvStorageFtwSpareBase, mInstance.MemBaseAddress +
+ PcdGet32 (PcdFlashNvStorageVariableSize) +
+ PcdGet32 (PcdFlashNvStorageFtwWorkingSize));
+
+ Status = gMmst->MmInstallProtocolInterface (
+ &mInstance.Handle,
+ &gEfiSmmFirmwareVolumeBlockProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mInstance.FvbProtocol
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG ((DEBUG_INFO, "%a: Register OP-TEE RPMB Fvb\n", __FUNCTION__));
+ DEBUG ((DEBUG_INFO, "%a: Using NV store FV in-memory copy at 0x%lx\n",
+ __FUNCTION__, PatchPcdGet32 (PcdFlashNvStorageVariableBase)));
+
+ return Status;
+}
--
2.17.1


[PATCH edk2-platforms v1 0/2] Add support for running StandaloneMm as OP-TEE TA

Sughosh Ganu
 

SPM (responsible for dispatching StMM) and SPD (for OP-TEE) are mutually
exclusive and there's no Trusted Application in OP-TEE for managing
EFI variables (only a Microsoft one, for Authenticated variables).
This means that one can have a secure OS or secure variable storage.

With some recent changes merged in OP-TEE [1] and U-Boot [2] we can
launch StMM from an OP-TEE secure partition which is mimicking SPM.

By re-using StMM we have EDK2s approved application controlling
variable storage and the ability to run a secure world OS. This also
allows various firmware implementations to adopt EDK2 way of storing
variables (including the FTW implementation), as long as OP-TEE is
available on that given platform (or any other secure OS that can launch
StMM and has a supplicant for handling the RPMB partition).
Another advantage is that OP-TEE has the ability to access an eMMC RPMB
partition to store those variables, so any platform with OP-TEE and an
eMMC can store variables securely.
This requires a normal world supplicant, which is implemented in U-Boot
currently. Similar functionality can be added in EDK2 by porting the
supplicant and adapt it to using the native eMMC drivers.

Although this approach might seem counter-intuitive at first glance,
considering the FFA [3] in Arm architecture, using a Secure Partition that
includes everything seems like a better choice at the moment and is
preferred over a rewritten from scratch TA.

There's is one drawback in using OP-TEE. The current SPM calls need to run
to completion. This contradicts the current OP-TEE RPC call requirements,
used to access the RPMB storage. Thats leads to two different SMC calls for
entering secure world to access StMM (one for SPM and one for SPD).

Since this is quite tricky to compile and test you can use this [4].
Just clone the repo and run ./build.sh. The script will pick up edk2,
edk2-platforms, op-tee, TF-A and U-boot and compile all the necessary
binaries for QEMU. A patch (hack) has been added to U-boot to
allow RPMB emulation through it's supplicant, since QEMU RPMB emulation
is not yet available.
After compiling and launching QEMU the usual U-boot commands for EFI
variable management will store the variables on the emulated RPMB device.

[1] https://github.com/OP-TEE/optee_os/pull/3973
[2] http://u-boot.10912.n7.nabble.com/PATCH-0-7-v4-EFI-variable-support-via-OP-TEE-td412499.html
[3] https://developer.arm.com/documentation/den0077/a
[4] https://git.linaro.org/people/ilias.apalodimas/efi_optee_variables.git/

Ilias Apalodimas (2):
Drivers/OpTeeRpmb: Add an OP-TEE backed RPMB driver
StMMRpmb: Add support for building StandaloneMm image for OP-TEE

Platform/StMMRpmb/PlatformStandaloneMm.dsc | 182 +++++
Platform/StMMRpmb/PlatformStandaloneMm.fdf | 111 +++
Drivers/OpTeeRpmb/FixupPcd.inf | 44 ++
Drivers/OpTeeRpmb/OpTeeRpmbFv.inf | 58 ++
Drivers/OpTeeRpmb/OpTeeRpmbFvb.h | 52 ++
Drivers/OpTeeRpmb/FixupPcd.c | 74 ++
Drivers/OpTeeRpmb/OpTeeRpmbFvb.c | 775 ++++++++++++++++++++
7 files changed, 1296 insertions(+)
create mode 100644 Platform/StMMRpmb/PlatformStandaloneMm.dsc
create mode 100644 Platform/StMMRpmb/PlatformStandaloneMm.fdf
create mode 100644 Drivers/OpTeeRpmb/FixupPcd.inf
create mode 100644 Drivers/OpTeeRpmb/OpTeeRpmbFv.inf
create mode 100644 Drivers/OpTeeRpmb/OpTeeRpmbFvb.h
create mode 100644 Drivers/OpTeeRpmb/FixupPcd.c
create mode 100644 Drivers/OpTeeRpmb/OpTeeRpmbFvb.c

--
2.17.1


[PATCH v1 12/12] StandaloneMmPkg: Allow sending FFA Direct Request message to StandaloneMm

Sughosh Ganu
 

From: Ilias Apalodimas <ilias.apalodimas@linaro.org>

Allow passing of a request to StandaloneMm Core through the Firmware
Framework(FF-A) using FFA_MSG_SEND_DIRECT_REQ method. This method is
used as a mechanism for requesting some service from StandaloneMm.

Signed-off-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---
StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/EventHandle.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/EventHandle.c b/StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/EventHandle.c
index 6a25c4c548..199441f7d2 100644
--- a/StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/EventHandle.c
+++ b/StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/EventHandle.c
@@ -22,6 +22,7 @@
#include <Guid/ZeroGuid.h>
#include <Guid/MmramMemoryReserve.h>

+#include <IndustryStandard/ArmFfaSvc.h>
#include <IndustryStandard/ArmStdSmc.h>

#include "StandaloneMmCpu.h"
@@ -78,7 +79,8 @@ PiMmStandaloneArmTfCpuDriverEntry (
// receipt of a synchronous MM request. Use the Event ID to distinguish
// between synchronous and asynchronous events.
//
- if (ARM_SMC_ID_MM_COMMUNICATE_AARCH64 != EventId) {
+ if (ARM_SMC_ID_MM_COMMUNICATE_AARCH64 != EventId &&
+ ARM_SVC_ID_FFA_MSG_SEND_DIRECT_REQ_AARCH64 != EventId) {
DEBUG ((DEBUG_INFO, "UnRecognized Event - 0x%x\n", EventId));
return EFI_INVALID_PARAMETER;
}
--
2.17.1


[PATCH v1 11/12] MdeModulePkg/VariableStandaloneMm: Set PcdFlashNvStorageVariableBase to Pcd

Sughosh Ganu
 

From: Ilias Apalodimas <ilias.apalodimas@linaro.org>

Instead of running StMM as a SP, OP-TEE creates a new secure partition,
which emulates SPM and isolates StMM from the rest of the Trusted
Applications (TAs). We can then compile StMM as an FD image and run it
in OP-TEE. With the addition of a new RPMB driver, we can leverage OP-TEE
and store variables to an RPMB device.

Since EDK2 upper layers expect byte addressable code, for the RPMB to
work, we need to allocate memory and sync it with the hardware on
read/writes. Since DynamicPCDs are not supported in that context we
can only use PatchablePCDs. So let's switch them to Pcd instead of
FixedPcd and accomodate the new driver.

Signed-off-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
---
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
index 6e17f6cdf5..dfed7fe069 100644
--- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
+++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableStandaloneMm.inf
@@ -115,10 +115,12 @@
## SOMETIMES_PRODUCES ## Variable:L"VarErrorFlag"
gEdkiiVarErrorFlagGuid

-[FixedPcd]
- gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize ## CONSUMES
+[Pcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase ## SOMETIMES_CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize ## CONSUMES
+
+[FixedPcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize ## CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize ## CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVolatileVariableSize ## CONSUMES
--
2.17.1


[PATCH v1 10/12] ArmPkg/StandaloneMmMmuLib: Add option to use FF-A calls to set memory region's permissions

Sughosh Ganu
 

From: Achin Gupta <achin.gupta@arm.com>

Allow setting memory region's permissions using either of the Firmware
Framework(FF-A) ABI transport or through the earlier used SVC calls.

Signed-off-by: Achin Gupta <achin.gupta@arm.com>
Co-developed-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---
ArmPkg/Library/StandaloneMmMmuLib/AArch64/ArmMmuStandaloneMmLib.c | 24 ++++++++++++++++----
1 file changed, 19 insertions(+), 5 deletions(-)

diff --git a/ArmPkg/Library/StandaloneMmMmuLib/AArch64/ArmMmuStandaloneMmLib.c b/ArmPkg/Library/StandaloneMmMmuLib/AArch64/ArmMmuStandaloneMmLib.c
index ab13602556..fef5eb4d22 100644
--- a/ArmPkg/Library/StandaloneMmMmuLib/AArch64/ArmMmuStandaloneMmLib.c
+++ b/ArmPkg/Library/StandaloneMmMmuLib/AArch64/ArmMmuStandaloneMmLib.c
@@ -63,17 +63,31 @@ RequestMemoryPermissionChange (
IN UINTN Permissions
)
{
+ BOOLEAN FfaEnabled;
EFI_STATUS Status;
ARM_SVC_ARGS ChangeMemoryPermissionsSvcArgs = {0};

- ChangeMemoryPermissionsSvcArgs.Arg0 = ARM_SVC_ID_SP_SET_MEM_ATTRIBUTES_AARCH64;
- ChangeMemoryPermissionsSvcArgs.Arg1 = BaseAddress;
- ChangeMemoryPermissionsSvcArgs.Arg2 = EFI_SIZE_TO_PAGES(Length);
- ChangeMemoryPermissionsSvcArgs.Arg3 = Permissions;
+ FfaEnabled = FeaturePcdGet (PcdFfaEnable);
+
+ if (FfaEnabled) {
+ ChangeMemoryPermissionsSvcArgs.Arg0 = ARM_SVC_ID_FFA_MSG_SEND_DIRECT_REQ_AARCH64;
+ ChangeMemoryPermissionsSvcArgs.Arg1 = 0x3;
+ ChangeMemoryPermissionsSvcArgs.Arg2 = 0;
+ ChangeMemoryPermissionsSvcArgs.Arg3 = ARM_SVC_ID_SP_SET_MEM_ATTRIBUTES_AARCH64;
+ ChangeMemoryPermissionsSvcArgs.Arg4 = BaseAddress;
+ ChangeMemoryPermissionsSvcArgs.Arg5 = EFI_SIZE_TO_PAGES(Length);
+ ChangeMemoryPermissionsSvcArgs.Arg6 = Permissions;
+ } else {
+ ChangeMemoryPermissionsSvcArgs.Arg0 = ARM_SVC_ID_SP_SET_MEM_ATTRIBUTES_AARCH64;
+ ChangeMemoryPermissionsSvcArgs.Arg1 = BaseAddress;
+ ChangeMemoryPermissionsSvcArgs.Arg2 = EFI_SIZE_TO_PAGES(Length);
+ ChangeMemoryPermissionsSvcArgs.Arg3 = Permissions;
+ }

ArmCallSvc (&ChangeMemoryPermissionsSvcArgs);

- Status = ChangeMemoryPermissionsSvcArgs.Arg0;
+ Status = FfaEnabled ?
+ ChangeMemoryPermissionsSvcArgs.Arg3 : ChangeMemoryPermissionsSvcArgs.Arg0;

switch (Status) {
case ARM_SVC_SPM_RET_SUCCESS:
--
2.17.1

7781 - 7800 of 74227