DynamicTablesPkg: IORT generator updates for Rev E.d spec

Bugzilla: 3458 - Add support IORT Rev E.d specification updates
          (https://bugzilla.tianocore.org/show_bug.cgi?id=3458)

The IO Remapping Table, Platform Design Document, Revision E.d,
Feb 2022 (https://developer.arm.com/documentation/den0049/)
introduces the following updates, collectively including the
updates and errata fixes to Rev E, Rev E.a, Rev E.b, Rev E.c:
 - increments the IORT table revision to 5.
 - updates the node definition to add an 'Identifier' field.
 - adds definition of node type 6 - Reserved Memory Range node.
 - adds definition for Memory Range Descriptors.
 - adds flag to indicate PRI support for root complexes.
 - adds flag to indicate if the root complex supports forwarding
   of PASID information on translated transactions to the SMMU.
 - adds flag to indicate if the root complex supports PASID.
 - adds flags to define access privilege and attributes for the
   memory ranges.

Therefore, update the IORT generator to:
  - increment IORT table revision count to 5.
  - populate Identifier filed if revision is greater than 4.
  - add support to populate Reserved Memory Range nodes and
    the Memory range descriptors.
  - add validation to check that the Identifier field is
    unique.
  - Populate the PASID capabilities and Flags field of the
    Root complex node.
 - Added checks to not generate IORT Rev E, Rev E.<a,b,c>.

Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
Reviewed-by: Pierre Gondois <pierre.gondois@arm.com>
This commit is contained in:
Sami Mujawar 2022-07-14 17:50:31 +01:00 committed by mergify[bot]
parent de200b7e2c
commit e9150618ec
2 changed files with 610 additions and 50 deletions

View File

@ -5,8 +5,8 @@
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Reference(s):
- IO Remapping Table, Platform Design Document,
Document number: ARM DEN 0049D, Issue D, March 2018
- IO Remapping Table, Platform Design Document, Revision E.d, Feb 2022
(https://developer.arm.com/documentation/den0049/)
**/
@ -37,9 +37,11 @@ Requirements:
- EArmObjSmmuV1SmmuV2
- EArmObjSmmuV3
- EArmObjPmcg
- EArmObjRmr
- EArmObjGicItsIdentifierArray
- EArmObjIdMappingArray
- EArmObjGicItsIdentifierArray
- EArmObjSmmuInterruptArray
- EArmObjMemoryRangeDescriptor
*/
/** This macro expands to a function that retrieves the ITS
@ -96,6 +98,24 @@ GET_OBJECT_LIST (
CM_ARM_PMCG_NODE
);
/** This macro expands to a function that retrieves the
RMR node information from the Configuration Manager.
*/
GET_OBJECT_LIST (
EObjNameSpaceArm,
EArmObjRmr,
CM_ARM_RMR_NODE
);
/** This macro expands to a function that retrieves the
Memory Range Descriptor Array information from the Configuration Manager.
*/
GET_OBJECT_LIST (
EObjNameSpaceArm,
EArmObjMemoryRangeDescriptor,
CM_ARM_MEMORY_RANGE_DESCRIPTOR
);
/** This macro expands to a function that retrieves the
ITS Identifier Array information from the Configuration Manager.
*/
@ -174,16 +194,19 @@ GetSizeofItsGroupNodes (
Size = 0;
while (NodeCount-- != 0) {
(*NodeIndexer)->Token = NodeList->Token;
(*NodeIndexer)->Object = (VOID *)NodeList;
(*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);
(*NodeIndexer)->Token = NodeList->Token;
(*NodeIndexer)->Object = (VOID *)NodeList;
(*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);
(*NodeIndexer)->Identifier = NodeList->Identifier;
DEBUG ((
DEBUG_INFO,
"IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
"IORT: Node Indexer = %p, Token = %p, Object = %p,"
" Offset = 0x%x, Identifier = 0x%x\n",
*NodeIndexer,
(*NodeIndexer)->Token,
(*NodeIndexer)->Object,
(*NodeIndexer)->Offset
(*NodeIndexer)->Offset,
(*NodeIndexer)->Identifier
));
Size += GetItsGroupNodeSize (NodeList);
@ -248,16 +271,19 @@ GetSizeofNamedComponentNodes (
Size = 0;
while (NodeCount-- != 0) {
(*NodeIndexer)->Token = NodeList->Token;
(*NodeIndexer)->Object = (VOID *)NodeList;
(*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);
(*NodeIndexer)->Token = NodeList->Token;
(*NodeIndexer)->Object = (VOID *)NodeList;
(*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);
(*NodeIndexer)->Identifier = NodeList->Identifier;
DEBUG ((
DEBUG_INFO,
"IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
"IORT: Node Indexer = %p, Token = %p, Object = %p,"
" Offset = 0x%x, Identifier = 0x%x\n",
*NodeIndexer,
(*NodeIndexer)->Token,
(*NodeIndexer)->Object,
(*NodeIndexer)->Offset
(*NodeIndexer)->Offset,
(*NodeIndexer)->Identifier
));
Size += GetNamedComponentNodeSize (NodeList);
@ -320,16 +346,19 @@ GetSizeofRootComplexNodes (
Size = 0;
while (NodeCount-- != 0) {
(*NodeIndexer)->Token = NodeList->Token;
(*NodeIndexer)->Object = (VOID *)NodeList;
(*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);
(*NodeIndexer)->Token = NodeList->Token;
(*NodeIndexer)->Object = (VOID *)NodeList;
(*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);
(*NodeIndexer)->Identifier = NodeList->Identifier;
DEBUG ((
DEBUG_INFO,
"IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
"IORT: Node Indexer = %p, Token = %p, Object = %p,"
" Offset = 0x%x, Identifier = 0x%x\n",
*NodeIndexer,
(*NodeIndexer)->Token,
(*NodeIndexer)->Object,
(*NodeIndexer)->Offset
(*NodeIndexer)->Offset,
(*NodeIndexer)->Identifier
));
Size += GetRootComplexNodeSize (NodeList);
@ -398,16 +427,19 @@ GetSizeofSmmuV1V2Nodes (
Size = 0;
while (NodeCount-- != 0) {
(*NodeIndexer)->Token = NodeList->Token;
(*NodeIndexer)->Object = (VOID *)NodeList;
(*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);
(*NodeIndexer)->Token = NodeList->Token;
(*NodeIndexer)->Object = (VOID *)NodeList;
(*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);
(*NodeIndexer)->Identifier = NodeList->Identifier;
DEBUG ((
DEBUG_INFO,
"IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
"IORT: Node Indexer = %p, Token = %p, Object = %p,"
" Offset = 0x%x, Identifier = 0x%x\n",
*NodeIndexer,
(*NodeIndexer)->Token,
(*NodeIndexer)->Object,
(*NodeIndexer)->Offset
(*NodeIndexer)->Offset,
(*NodeIndexer)->Identifier
));
Size += GetSmmuV1V2NodeSize (NodeList);
@ -470,16 +502,19 @@ GetSizeofSmmuV3Nodes (
Size = 0;
while (NodeCount-- != 0) {
(*NodeIndexer)->Token = NodeList->Token;
(*NodeIndexer)->Object = (VOID *)NodeList;
(*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);
(*NodeIndexer)->Token = NodeList->Token;
(*NodeIndexer)->Object = (VOID *)NodeList;
(*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);
(*NodeIndexer)->Identifier = NodeList->Identifier;
DEBUG ((
DEBUG_INFO,
"IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
"IORT: Node Indexer = %p, Token = %p, Object = %p,"
" Offset = 0x%x, Identifier = 0x%x\n",
*NodeIndexer,
(*NodeIndexer)->Token,
(*NodeIndexer)->Object,
(*NodeIndexer)->Offset
(*NodeIndexer)->Offset,
(*NodeIndexer)->Identifier
));
Size += GetSmmuV3NodeSize (NodeList);
@ -542,16 +577,19 @@ GetSizeofPmcgNodes (
Size = 0;
while (NodeCount-- != 0) {
(*NodeIndexer)->Token = NodeList->Token;
(*NodeIndexer)->Object = (VOID *)NodeList;
(*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);
(*NodeIndexer)->Token = NodeList->Token;
(*NodeIndexer)->Object = (VOID *)NodeList;
(*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);
(*NodeIndexer)->Identifier = NodeList->Identifier;
DEBUG ((
DEBUG_INFO,
"IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
"IORT: Node Indexer = %p, Token = %p, Object = %p,"
" Offset = 0x%x, Identifier = 0x%x\n",
*NodeIndexer,
(*NodeIndexer)->Token,
(*NodeIndexer)->Object,
(*NodeIndexer)->Offset
(*NodeIndexer)->Offset,
(*NodeIndexer)->Identifier
));
Size += GetPmcgNodeSize (NodeList);
@ -562,6 +600,84 @@ GetSizeofPmcgNodes (
return Size;
}
/** Returns the size of the RMR node.
@param [in] Node Pointer to RMR node.
@retval Size of the RMR node.
**/
STATIC
UINT32
GetRmrNodeSize (
IN CONST CM_ARM_RMR_NODE *Node
)
{
ASSERT (Node != NULL);
/* Size of RMR node +
Size of ID mapping array +
Size of Memory Range Descriptor array
*/
return (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_RMR_NODE) +
(Node->IdMappingCount *
sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)) +
(Node->MemRangeDescCount *
sizeof (EFI_ACPI_6_0_IO_REMAPPING_MEM_RANGE_DESC)));
}
/** Returns the total size required for the RMR nodes and
updates the Node Indexer.
This function calculates the size required for the node group
and also populates the Node Indexer array with offsets for the
individual nodes.
@param [in] NodeStartOffset Offset from the start of the
IORT where this node group starts.
@param [in] NodeList Pointer to RMR node list.
@param [in] NodeCount Count of the RMR nodes.
@param [in, out] NodeIndexer Pointer to the next Node Indexer.
@retval Total size of the RMR nodes.
**/
STATIC
UINT64
GetSizeofRmrNodes (
IN CONST UINT32 NodeStartOffset,
IN CONST CM_ARM_RMR_NODE *NodeList,
IN UINT32 NodeCount,
IN OUT IORT_NODE_INDEXER **CONST NodeIndexer
)
{
UINT64 Size;
ASSERT (NodeList != NULL);
Size = 0;
while (NodeCount-- != 0) {
(*NodeIndexer)->Token = NodeList->Token;
(*NodeIndexer)->Object = (VOID *)NodeList;
(*NodeIndexer)->Offset = (UINT32)(Size + NodeStartOffset);
(*NodeIndexer)->Identifier = NodeList->Identifier;
DEBUG ((
DEBUG_INFO,
"IORT: Node Indexer = %p, Token = %p, Object = %p,"
" Offset = 0x%x, Identifier = 0x%x\n",
*NodeIndexer,
(*NodeIndexer)->Token,
(*NodeIndexer)->Object,
(*NodeIndexer)->Offset,
(*NodeIndexer)->Identifier
));
Size += GetRmrNodeSize (NodeList);
(*NodeIndexer)++;
NodeList++;
}
return Size;
}
/** Returns the offset of the Node referenced by the Token.
@param [in] NodeIndexer Pointer to node indexer array.
@ -713,6 +829,7 @@ AddIdMappingArray (
@param [in] This Pointer to the table Generator.
@param [in] CfgMgrProtocol Pointer to the Configuration Manager
Protocol Interface.
@param [in] AcpiTableInfo Pointer to the ACPI table info structure.
@param [in] Iort Pointer to IORT table structure.
@param [in] NodesStartOffset Offset for the start of the ITS Group
Nodes.
@ -729,6 +846,7 @@ EFI_STATUS
AddItsGroupNodes (
IN CONST ACPI_TABLE_GENERATOR *CONST This,
IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort,
IN CONST UINT32 NodesStartOffset,
IN CONST CM_ARM_ITS_GROUP_NODE *NodeList,
@ -765,11 +883,19 @@ AddItsGroupNodes (
// Populate the node header
ItsGroupNode->Node.Type = EFI_ACPI_IORT_TYPE_ITS_GROUP;
ItsGroupNode->Node.Length = (UINT16)NodeLength;
ItsGroupNode->Node.Revision = 0;
ItsGroupNode->Node.Identifier = EFI_ACPI_RESERVED_DWORD;
ItsGroupNode->Node.NumIdMappings = 0;
ItsGroupNode->Node.IdReference = 0;
if (AcpiTableInfo->AcpiTableRevision <
EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05)
{
ItsGroupNode->Node.Revision = 0;
ItsGroupNode->Node.Identifier = EFI_ACPI_RESERVED_DWORD;
} else {
ItsGroupNode->Node.Revision = 1;
ItsGroupNode->Node.Identifier = NodeList->Identifier;
}
// IORT specific data
ItsGroupNode->NumItsIdentifiers = NodeList->ItsIdCount;
ItsIds = (UINT32 *)((UINT8 *)ItsGroupNode +
@ -820,6 +946,7 @@ AddItsGroupNodes (
@param [in] This Pointer to the table Generator.
@param [in] CfgMgrProtocol Pointer to the Configuration Manager
Protocol Interface.
@param [in] AcpiTableInfo Pointer to the ACPI table info structure.
@param [in] Iort Pointer to IORT table structure.
@param [in] NodesStartOffset Offset for the start of the Named
Component Nodes.
@ -836,6 +963,7 @@ EFI_STATUS
AddNamedComponentNodes (
IN CONST ACPI_TABLE_GENERATOR *CONST This,
IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort,
IN CONST UINT32 NodesStartOffset,
IN CONST CM_ARM_NAMED_COMPONENT_NODE *NodeList,
@ -871,10 +999,18 @@ AddNamedComponentNodes (
// Populate the node header
NcNode->Node.Type = EFI_ACPI_IORT_TYPE_NAMED_COMP;
NcNode->Node.Length = (UINT16)NodeLength;
NcNode->Node.Revision = 2;
NcNode->Node.Identifier = EFI_ACPI_RESERVED_DWORD;
NcNode->Node.NumIdMappings = NodeList->IdMappingCount;
if (AcpiTableInfo->AcpiTableRevision <
EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05)
{
NcNode->Node.Revision = 2;
NcNode->Node.Identifier = EFI_ACPI_RESERVED_DWORD;
} else {
NcNode->Node.Revision = 4;
NcNode->Node.Identifier = NodeList->Identifier;
}
ObjectNameLength = AsciiStrLen (NodeList->ObjectName) + 1;
NcNode->Node.IdReference = (NodeList->IdMappingCount == 0) ?
0 : ((UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE) +
@ -955,6 +1091,7 @@ AddNamedComponentNodes (
@param [in] This Pointer to the table Generator.
@param [in] CfgMgrProtocol Pointer to the Configuration Manager
Protocol Interface.
@param [in] AcpiTableInfo Pointer to the ACPI table info structure.
@param [in] Iort Pointer to IORT table structure.
@param [in] NodesStartOffset Offset for the start of the Root Complex
Nodes.
@ -971,6 +1108,7 @@ EFI_STATUS
AddRootComplexNodes (
IN CONST ACPI_TABLE_GENERATOR *CONST This,
IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort,
IN CONST UINT32 NodesStartOffset,
IN CONST CM_ARM_ROOT_COMPLEX_NODE *NodeList,
@ -1004,12 +1142,23 @@ AddRootComplexNodes (
// Populate the node header
RcNode->Node.Type = EFI_ACPI_IORT_TYPE_ROOT_COMPLEX;
RcNode->Node.Length = (UINT16)NodeLength;
RcNode->Node.Revision = 1;
RcNode->Node.Identifier = EFI_ACPI_RESERVED_DWORD;
RcNode->Node.NumIdMappings = NodeList->IdMappingCount;
RcNode->Node.IdReference = (NodeList->IdMappingCount == 0) ?
0 : sizeof (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE);
if (AcpiTableInfo->AcpiTableRevision <
EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05)
{
RcNode->Node.Revision = 1;
RcNode->Node.Identifier = EFI_ACPI_RESERVED_DWORD;
RcNode->PasidCapabilities = EFI_ACPI_RESERVED_WORD;
} else {
RcNode->Node.Revision = 4;
RcNode->Node.Identifier = NodeList->Identifier;
RcNode->PasidCapabilities = NodeList->PasidCapabilities;
RcNode->Flags = NodeList->Flags;
}
// Root Complex specific data
RcNode->CacheCoherent = NodeList->CacheCoherent;
RcNode->AllocationHints = NodeList->AllocationHints;
@ -1018,7 +1167,6 @@ AddRootComplexNodes (
RcNode->AtsAttribute = NodeList->AtsAttribute;
RcNode->PciSegmentNumber = NodeList->PciSegmentNumber;
RcNode->MemoryAddressSize = NodeList->MemoryAddressSize;
RcNode->PasidCapabilities = EFI_ACPI_RESERVED_WORD;
RcNode->Reserved1[0] = EFI_ACPI_RESERVED_BYTE;
if (NodeList->IdMappingCount > 0) {
@ -1134,6 +1282,7 @@ AddSmmuInterruptArray (
@param [in] This Pointer to the table Generator.
@param [in] CfgMgrProtocol Pointer to the Configuration Manager
Protocol Interface.
@param [in] AcpiTableInfo Pointer to the ACPI table info structure.
@param [in] Iort Pointer to IORT table structure.
@param [in] NodesStartOffset Offset for the start of the SMMU v1/v2
Nodes.
@ -1150,6 +1299,7 @@ EFI_STATUS
AddSmmuV1V2Nodes (
IN CONST ACPI_TABLE_GENERATOR *CONST This,
IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort,
IN CONST UINT32 NodesStartOffset,
IN CONST CM_ARM_SMMUV1_SMMUV2_NODE *NodeList,
@ -1186,8 +1336,6 @@ AddSmmuV1V2Nodes (
// Populate the node header
SmmuNode->Node.Type = EFI_ACPI_IORT_TYPE_SMMUv1v2;
SmmuNode->Node.Length = (UINT16)NodeLength;
SmmuNode->Node.Revision = 0;
SmmuNode->Node.Identifier = EFI_ACPI_RESERVED_DWORD;
SmmuNode->Node.NumIdMappings = NodeList->IdMappingCount;
SmmuNode->Node.IdReference = (NodeList->IdMappingCount == 0) ?
0 : (sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE) +
@ -1196,6 +1344,16 @@ AddSmmuV1V2Nodes (
(NodeList->PmuInterruptCount *
sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT)));
if (AcpiTableInfo->AcpiTableRevision <
EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05)
{
SmmuNode->Node.Revision = 1;
SmmuNode->Node.Identifier = EFI_ACPI_RESERVED_DWORD;
} else {
SmmuNode->Node.Revision = 3;
SmmuNode->Node.Identifier = NodeList->Identifier;
}
// SMMU v1/v2 specific data
SmmuNode->Base = NodeList->BaseAddress;
SmmuNode->Span = NodeList->Span;
@ -1339,6 +1497,7 @@ AddSmmuV1V2Nodes (
@param [in] This Pointer to the table Generator.
@param [in] CfgMgrProtocol Pointer to the Configuration Manager
Protocol Interface.
@param [in] AcpiTableInfo Pointer to the ACPI table info structure.
@param [in] Iort Pointer to IORT table structure.
@param [in] NodesStartOffset Offset for the start of the SMMUv3 Nodes.
@param [in] NodeList Pointer to an array of SMMUv3 Node Objects.
@ -1353,6 +1512,7 @@ EFI_STATUS
AddSmmuV3Nodes (
IN CONST ACPI_TABLE_GENERATOR *CONST This,
IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort,
IN CONST UINT32 NodesStartOffset,
IN CONST CM_ARM_SMMUV3_NODE *NodeList,
@ -1385,12 +1545,20 @@ AddSmmuV3Nodes (
// Populate the node header
SmmuV3Node->Node.Type = EFI_ACPI_IORT_TYPE_SMMUv3;
SmmuV3Node->Node.Length = (UINT16)NodeLength;
SmmuV3Node->Node.Revision = 2;
SmmuV3Node->Node.Identifier = EFI_ACPI_RESERVED_DWORD;
SmmuV3Node->Node.NumIdMappings = NodeList->IdMappingCount;
SmmuV3Node->Node.IdReference = (NodeList->IdMappingCount == 0) ?
0 : sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE);
if (AcpiTableInfo->AcpiTableRevision <
EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05)
{
SmmuV3Node->Node.Revision = 2;
SmmuV3Node->Node.Identifier = EFI_ACPI_RESERVED_DWORD;
} else {
SmmuV3Node->Node.Revision = 4;
SmmuV3Node->Node.Identifier = NodeList->Identifier;
}
// SMMUv3 specific data
SmmuV3Node->Base = NodeList->BaseAddress;
SmmuV3Node->Flags = NodeList->Flags;
@ -1468,6 +1636,7 @@ AddSmmuV3Nodes (
@param [in] This Pointer to the table Generator.
@param [in] CfgMgrProtocol Pointer to the Configuration Manager
Protocol Interface.
@param [in] AcpiTableInfo Pointer to the ACPI table info structure.
@param [in] Iort Pointer to IORT table structure.
@param [in] NodesStartOffset Offset for the start of the PMCG Nodes.
@param [in] NodeList Pointer to an array of PMCG Node Objects.
@ -1482,6 +1651,7 @@ EFI_STATUS
AddPmcgNodes (
IN CONST ACPI_TABLE_GENERATOR *CONST This,
IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort,
IN CONST UINT32 NodesStartOffset,
IN CONST CM_ARM_PMCG_NODE *NodeList,
@ -1516,12 +1686,20 @@ AddPmcgNodes (
// Populate the node header
PmcgNode->Node.Type = EFI_ACPI_IORT_TYPE_PMCG;
PmcgNode->Node.Length = (UINT16)NodeLength;
PmcgNode->Node.Revision = 1;
PmcgNode->Node.Identifier = EFI_ACPI_RESERVED_DWORD;
PmcgNode->Node.NumIdMappings = NodeList->IdMappingCount;
PmcgNode->Node.IdReference = (NodeList->IdMappingCount == 0) ?
0 : sizeof (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE);
if (AcpiTableInfo->AcpiTableRevision <
EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05)
{
PmcgNode->Node.Revision = 1;
PmcgNode->Node.Identifier = EFI_ACPI_RESERVED_DWORD;
} else {
PmcgNode->Node.Revision = 2;
PmcgNode->Node.Identifier = NodeList->Identifier;
}
// PMCG specific data
PmcgNode->Base = NodeList->BaseAddress;
PmcgNode->OverflowInterruptGsiv = NodeList->OverflowInterrupt;
@ -1588,6 +1766,274 @@ AddPmcgNodes (
return EFI_SUCCESS;
}
/** Update the Memory Range Descriptor Array.
This function retrieves the Memory Range Descriptor objects referenced by
MemRangeDescToken and updates the Memory Range Descriptor array.
@param [in] This Pointer to the table Generator.
@param [in] CfgMgrProtocol Pointer to the Configuration Manager
Protocol Interface.
@param [in] DescArray Pointer to an array of Memory Range
Descriptors.
@param [in] DescCount Number of Id Descriptors.
@param [in] DescToken Reference Token for retrieving the
Memory Range Descriptor Array.
@retval EFI_SUCCESS Table generated successfully.
@retval EFI_INVALID_PARAMETER A parameter is invalid.
@retval EFI_NOT_FOUND The required object was not found.
**/
STATIC
EFI_STATUS
AddMemRangeDescArray (
IN CONST ACPI_TABLE_GENERATOR *CONST This,
IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
IN EFI_ACPI_6_0_IO_REMAPPING_MEM_RANGE_DESC *DescArray,
IN UINT32 DescCount,
IN CONST CM_OBJECT_TOKEN DescToken
)
{
EFI_STATUS Status;
CM_ARM_MEMORY_RANGE_DESCRIPTOR *MemRangeDesc;
UINT32 MemRangeDescCount;
ASSERT (DescArray != NULL);
// Get the Id Mapping Array
Status = GetEArmObjMemoryRangeDescriptor (
CfgMgrProtocol,
DescToken,
&MemRangeDesc,
&MemRangeDescCount
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to get Memory Range Descriptor array. Status = %r\n",
Status
));
return Status;
}
if (MemRangeDescCount < DescCount) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to get the required number of Memory"
" Range Descriptors.\n"
));
return EFI_NOT_FOUND;
}
// Populate the Memory Range Descriptor array
while (DescCount-- != 0) {
DescArray->Base = MemRangeDesc->BaseAddress;
DescArray->Length = MemRangeDesc->Length;
DescArray->Reserved = EFI_ACPI_RESERVED_DWORD;
DescArray++;
MemRangeDesc++;
}
return EFI_SUCCESS;
}
/** Update the RMR Node Information.
This function updates the RMR node information in the IORT table.
@param [in] This Pointer to the table Generator.
@param [in] CfgMgrProtocol Pointer to the Configuration Manager
Protocol Interface.
@param [in] AcpiTableInfo Pointer to the ACPI table info structure.
@param [in] Iort Pointer to IORT table structure.
@param [in] NodesStartOffset Offset for the start of the PMCG Nodes.
@param [in] NodeList Pointer to an array of PMCG Node Objects.
@param [in] NodeCount Number of PMCG Node Objects.
@retval EFI_SUCCESS Table generated successfully.
@retval EFI_INVALID_PARAMETER A parameter is invalid.
@retval EFI_NOT_FOUND The required object was not found.
**/
STATIC
EFI_STATUS
AddRmrNodes (
IN CONST ACPI_TABLE_GENERATOR *CONST This,
IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
IN CONST EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort,
IN CONST UINT32 NodesStartOffset,
IN CONST CM_ARM_RMR_NODE *NodeList,
IN UINT32 NodeCount
)
{
EFI_STATUS Status;
EFI_ACPI_6_0_IO_REMAPPING_RMR_NODE *RmrNode;
EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *IdMapArray;
EFI_ACPI_6_0_IO_REMAPPING_MEM_RANGE_DESC *MemRangeDescArray;
UINT64 NodeLength;
ASSERT (Iort != NULL);
RmrNode = (EFI_ACPI_6_0_IO_REMAPPING_RMR_NODE *)((UINT8 *)Iort +
NodesStartOffset);
while (NodeCount-- != 0) {
NodeLength = GetRmrNodeSize (NodeList);
if (NodeLength > MAX_UINT16) {
Status = EFI_INVALID_PARAMETER;
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: RMR Node length 0x%lx > MAX_UINT16. Status = %r\n",
NodeLength,
Status
));
return Status;
}
if (NodeList->MemRangeDescCount == 0) {
Status = EFI_INVALID_PARAMETER;
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Memory Range Desc count = %d. Status = %r\n",
NodeList->MemRangeDescCount,
Status
));
return Status;
}
if (NodeList->MemRangeDescToken == CM_NULL_TOKEN) {
Status = EFI_INVALID_PARAMETER;
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Invalid Memory Range Descriptor token,"
" Token = 0x%x. Status = %r\n",
NodeList->MemRangeDescToken,
Status
));
return Status;
}
// Populate the node header
RmrNode->Node.Type = EFI_ACPI_IORT_TYPE_RMR;
RmrNode->Node.Length = (UINT16)NodeLength;
RmrNode->Node.Revision = 3;
RmrNode->Node.Identifier = NodeList->Identifier;
RmrNode->Node.NumIdMappings = NodeList->IdMappingCount;
RmrNode->Node.IdReference = (NodeList->IdMappingCount == 0) ?
0 : sizeof (EFI_ACPI_6_0_IO_REMAPPING_RMR_NODE);
// RMR specific data
RmrNode->Flags = NodeList->Flags;
RmrNode->NumMemRangeDesc = NodeList->MemRangeDescCount;
RmrNode->MemRangeDescRef = (NodeList->MemRangeDescCount == 0) ?
0 : (sizeof (EFI_ACPI_6_0_IO_REMAPPING_RMR_NODE) +
(NodeList->IdMappingCount *
sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)));
if (NodeList->IdMappingCount > 0) {
if (NodeList->IdMappingToken == CM_NULL_TOKEN) {
Status = EFI_INVALID_PARAMETER;
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Invalid Id Mapping token,"
" Token = 0x%x, Status =%r\n",
NodeList->IdMappingToken,
Status
));
return Status;
}
// Ids for RMR node
IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *)((UINT8 *)RmrNode +
RmrNode->Node.IdReference);
Status = AddIdMappingArray (
This,
CfgMgrProtocol,
IdMapArray,
NodeList->IdMappingCount,
NodeList->IdMappingToken
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
Status
));
return Status;
}
}
// Memory Range Descriptors for RMR node
MemRangeDescArray = (EFI_ACPI_6_0_IO_REMAPPING_MEM_RANGE_DESC *)(
(UINT8 *)RmrNode +
RmrNode->MemRangeDescRef
);
Status = AddMemRangeDescArray (
This,
CfgMgrProtocol,
MemRangeDescArray,
NodeList->MemRangeDescCount,
NodeList->MemRangeDescToken
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to Memory Range Descriptor Array. Status = %r\n",
Status
));
return Status;
}
// Next RMR Node
RmrNode = (EFI_ACPI_6_0_IO_REMAPPING_RMR_NODE *)((UINT8 *)RmrNode +
RmrNode->Node.Length);
NodeList++;
} // RMR Node
return EFI_SUCCESS;
}
/** Validates that the IORT nodes Identifier are unique.
@param [in] NodeIndexer Pointer to the Node Indexer.
@param [in] NodeCount Number of IORT Nodes.
@retval EFI_SUCCESS Success.
@retval EFI_INVALID_PARAMETER Identifier field not unique.
**/
STATIC
EFI_STATUS
ValidateNodeIdentifiers (
IN CONST IORT_NODE_INDEXER *CONST NodeIndexer,
IN UINT32 NodeCount
)
{
UINT32 IndexI;
UINT32 IndexJ;
for (IndexI = 0; IndexI < NodeCount; IndexI++) {
for (IndexJ = 0; IndexJ < NodeCount; IndexJ++) {
if ((IndexI != IndexJ) &&
(NodeIndexer[IndexI].Identifier == NodeIndexer[IndexJ].Identifier))
{
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: UID %d of Token %p matches with that of Token %p.\n",
NodeIndexer[IndexI].Identifier,
NodeIndexer[IndexI].Token,
NodeIndexer[IndexJ].Token
));
return EFI_INVALID_PARAMETER;
}
}// IndexJ
} // IndexI
return EFI_SUCCESS;
}
/** Construct the IORT ACPI table.
This function invokes the Configuration Manager protocol interface
@ -1632,6 +2078,7 @@ BuildIortTable (
UINT32 SmmuV1V2NodeCount;
UINT32 SmmuV3NodeCount;
UINT32 PmcgNodeCount;
UINT32 RmrNodeCount;
UINT32 ItsGroupOffset;
UINT32 NamedComponentOffset;
@ -1639,6 +2086,7 @@ BuildIortTable (
UINT32 SmmuV1V2Offset;
UINT32 SmmuV3Offset;
UINT32 PmcgOffset;
UINT32 RmrOffset;
CM_ARM_ITS_GROUP_NODE *ItsGroupNodeList;
CM_ARM_NAMED_COMPONENT_NODE *NamedComponentNodeList;
@ -1646,6 +2094,7 @@ BuildIortTable (
CM_ARM_SMMUV1_SMMUV2_NODE *SmmuV1V2NodeList;
CM_ARM_SMMUV3_NODE *SmmuV3NodeList;
CM_ARM_PMCG_NODE *PmcgNodeList;
CM_ARM_RMR_NODE *RmrNodeList;
EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort;
IORT_NODE_INDEXER *NodeIndexer;
@ -1672,6 +2121,16 @@ BuildIortTable (
return EFI_INVALID_PARAMETER;
}
if ((AcpiTableInfo->AcpiTableRevision > EFI_ACPI_IO_REMAPPING_TABLE_REVISION_00) &&
(AcpiTableInfo->AcpiTableRevision < EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05))
{
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Revisions E (1), E.a(2),b(3),c(4) are not supported.\n"
));
return EFI_INVALID_PARAMETER;
}
Generator = (ACPI_IORT_GENERATOR *)This;
*Table = NULL;
@ -1789,6 +2248,29 @@ BuildIortTable (
// Add the PMCG node count
IortNodeCount += PmcgNodeCount;
if (AcpiTableInfo->AcpiTableRevision >=
EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05)
{
// Get the RMR node info
Status = GetEArmObjRmr (
CfgMgrProtocol,
CM_NULL_TOKEN,
&RmrNodeList,
&RmrNodeCount
);
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to get RMR Node Info. Status = %r\n",
Status
));
goto error_handler;
}
// Add the RMR node count
IortNodeCount += RmrNodeCount;
}
// Allocate Node Indexer array
NodeIndexer = (IORT_NODE_INDEXER *)AllocateZeroPool (
(sizeof (IORT_NODE_INDEXER) *
@ -1998,6 +2480,40 @@ BuildIortTable (
));
}
// RMR Nodes
if ((AcpiTableInfo->AcpiTableRevision >=
EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05) &&
(RmrNodeCount > 0))
{
RmrOffset = (UINT32)TableSize;
// Size of RMR node list.
NodeSize = GetSizeofRmrNodes (
RmrOffset,
RmrNodeList,
RmrNodeCount,
&NodeIndexer
);
if (NodeSize > MAX_UINT32) {
Status = EFI_INVALID_PARAMETER;
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Invalid Size of RMR Nodes. Status = %r\n",
Status
));
goto error_handler;
}
TableSize += NodeSize;
DEBUG ((
DEBUG_INFO,
" RmrNodeCount = %d\n" \
" RmrOffset = %d\n",
RmrNodeCount,
RmrOffset
));
}
DEBUG ((
DEBUG_INFO,
"INFO: IORT:\n" \
@ -2019,6 +2535,21 @@ BuildIortTable (
goto error_handler;
}
// Validate that the identifiers for the nodes are unique
if (AcpiTableInfo->AcpiTableRevision >=
EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05)
{
Status = ValidateNodeIdentifiers (Generator->NodeIndexer, IortNodeCount);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Node Identifier not unique. Status = %r\n",
Status
));
goto error_handler;
}
}
// Allocate the Buffer for IORT table
*Table = (EFI_ACPI_DESCRIPTION_HEADER *)AllocateZeroPool (TableSize);
if (*Table == NULL) {
@ -2067,6 +2598,7 @@ BuildIortTable (
Status = AddItsGroupNodes (
This,
CfgMgrProtocol,
AcpiTableInfo,
Iort,
ItsGroupOffset,
ItsGroupNodeList,
@ -2086,6 +2618,7 @@ BuildIortTable (
Status = AddNamedComponentNodes (
This,
CfgMgrProtocol,
AcpiTableInfo,
Iort,
NamedComponentOffset,
NamedComponentNodeList,
@ -2105,6 +2638,7 @@ BuildIortTable (
Status = AddRootComplexNodes (
This,
CfgMgrProtocol,
AcpiTableInfo,
Iort,
RootComplexOffset,
RootComplexNodeList,
@ -2124,6 +2658,7 @@ BuildIortTable (
Status = AddSmmuV1V2Nodes (
This,
CfgMgrProtocol,
AcpiTableInfo,
Iort,
SmmuV1V2Offset,
SmmuV1V2NodeList,
@ -2143,6 +2678,7 @@ BuildIortTable (
Status = AddSmmuV3Nodes (
This,
CfgMgrProtocol,
AcpiTableInfo,
Iort,
SmmuV3Offset,
SmmuV3NodeList,
@ -2162,6 +2698,7 @@ BuildIortTable (
Status = AddPmcgNodes (
This,
CfgMgrProtocol,
AcpiTableInfo,
Iort,
PmcgOffset,
PmcgNodeList,
@ -2170,7 +2707,27 @@ BuildIortTable (
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to add SMMUv3 Node. Status = %r\n",
"ERROR: IORT: Failed to add PMCG Node. Status = %r\n",
Status
));
goto error_handler;
}
}
if (RmrNodeCount > 0) {
Status = AddRmrNodes (
This,
CfgMgrProtocol,
AcpiTableInfo,
Iort,
RmrOffset,
RmrNodeList,
RmrNodeCount
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to add RMR Node. Status = %r\n",
Status
));
goto error_handler;
@ -2255,9 +2812,9 @@ ACPI_IORT_GENERATOR IortGenerator = {
// Generator Description
L"ACPI.STD.IORT.GENERATOR",
// ACPI Table Signature
EFI_ACPI_6_2_IO_REMAPPING_TABLE_SIGNATURE,
EFI_ACPI_6_4_IO_REMAPPING_TABLE_SIGNATURE,
// ACPI Table Revision supported by this Generator
EFI_ACPI_IO_REMAPPING_TABLE_REVISION_00,
EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05,
// Minimum supported ACPI Table Revision
EFI_ACPI_IO_REMAPPING_TABLE_REVISION_00,
// Creator ID

View File

@ -1,6 +1,6 @@
/** @file
Copyright (c) 2018, ARM Limited. All rights reserved.
Copyright (c) 2018 - 2022, Arm Limited. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
@ -25,6 +25,9 @@ typedef struct IortNodeIndexer {
VOID *Object;
/// Node offset from the start of the IORT table
UINT32 Offset;
/// Unique identifier for the Node
UINT32 Identifier;
} IORT_NODE_INDEXER;
typedef struct AcpiIortGenerator {