blob: f28973c1a8620aa5b756e85af1b46ebfaf018839 [file] [log] [blame]
/** @file
IORT Table Generator
Copyright (c) 2017 - 2022, Arm Limited. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Reference(s):
- IO Remapping Table, Platform Design Document, Revision E.d, Feb 2022
(https://developer.arm.com/documentation/den0049/)
**/
#include <IndustryStandard/IoRemappingTable.h>
#include <Library/AcpiLib.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Protocol/AcpiTable.h>
// Module specific include files.
#include <AcpiTableGenerator.h>
#include <ConfigurationManagerObject.h>
#include <ConfigurationManagerHelper.h>
#include <Library/TableHelperLib.h>
#include <Protocol/ConfigurationManagerProtocol.h>
#include "IortGenerator.h"
/** ARM standard IORT Generator
Requirements:
The following Configuration Manager Object(s) are required by
this Generator:
- EArmObjItsGroup
- EArmObjNamedComponent
- EArmObjRootComplex
- EArmObjSmmuV1SmmuV2
- EArmObjSmmuV3
- EArmObjPmcg
- EArmObjRmr
- EArmObjGicItsIdentifierArray
- EArmObjIdMappingArray
- EArmObjSmmuInterruptArray
- EArmObjMemoryRangeDescriptor
*/
/** This macro expands to a function that retrieves the ITS
Group node information from the Configuration Manager.
*/
GET_OBJECT_LIST (
EObjNameSpaceArm,
EArmObjItsGroup,
CM_ARM_ITS_GROUP_NODE
);
/** This macro expands to a function that retrieves the
Named Component node information from the Configuration Manager.
*/
GET_OBJECT_LIST (
EObjNameSpaceArm,
EArmObjNamedComponent,
CM_ARM_NAMED_COMPONENT_NODE
);
/** This macro expands to a function that retrieves the
Root Complex node information from the Configuration Manager.
*/
GET_OBJECT_LIST (
EObjNameSpaceArm,
EArmObjRootComplex,
CM_ARM_ROOT_COMPLEX_NODE
);
/** This macro expands to a function that retrieves the
SMMU v1/v2 node information from the Configuration Manager.
*/
GET_OBJECT_LIST (
EObjNameSpaceArm,
EArmObjSmmuV1SmmuV2,
CM_ARM_SMMUV1_SMMUV2_NODE
);
/** This macro expands to a function that retrieves the
SMMU v3 node information from the Configuration Manager.
*/
GET_OBJECT_LIST (
EObjNameSpaceArm,
EArmObjSmmuV3,
CM_ARM_SMMUV3_NODE
);
/** This macro expands to a function that retrieves the
PMCG node information from the Configuration Manager.
*/
GET_OBJECT_LIST (
EObjNameSpaceArm,
EArmObjPmcg,
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.
*/
GET_OBJECT_LIST (
EObjNameSpaceArm,
EArmObjGicItsIdentifierArray,
CM_ARM_ITS_IDENTIFIER
);
/** This macro expands to a function that retrieves the
Id Mapping Array information from the Configuration Manager.
*/
GET_OBJECT_LIST (
EObjNameSpaceArm,
EArmObjIdMappingArray,
CM_ARM_ID_MAPPING
);
/** This macro expands to a function that retrieves the
SMMU Interrupt Array information from the Configuration Manager.
*/
GET_OBJECT_LIST (
EObjNameSpaceArm,
EArmObjSmmuInterruptArray,
CM_ARM_SMMU_INTERRUPT
);
/** Returns the size of the ITS Group node.
@param [in] Node Pointer to ITS Group node.
@retval Size of the ITS Group Node.
**/
STATIC
UINT32
GetItsGroupNodeSize (
IN CONST CM_ARM_ITS_GROUP_NODE *Node
)
{
ASSERT (Node != NULL);
/* Size of ITS Group Node +
Size of ITS Identifier array
*/
return (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE) +
(Node->ItsIdCount * sizeof (UINT32)));
}
/** Returns the total size required for the ITS Group 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 ITS Group node list.
@param [in] NodeCount Count of the ITS Group nodes.
@param [in, out] NodeIndexer Pointer to the next Node Indexer.
@retval Total size of the ITS Group Nodes.
**/
STATIC
UINT64
GetSizeofItsGroupNodes (
IN CONST UINT32 NodeStartOffset,
IN CONST CM_ARM_ITS_GROUP_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 += GetItsGroupNodeSize (NodeList);
(*NodeIndexer)++;
NodeList++;
}
return Size;
}
/** Returns the size of the Named Component node.
@param [in] Node Pointer to Named Component node.
@retval Size of the Named Component node.
**/
STATIC
UINT32
GetNamedComponentNodeSize (
IN CONST CM_ARM_NAMED_COMPONENT_NODE *Node
)
{
ASSERT (Node != NULL);
/* Size of Named Component node +
Size of ID mapping array +
Size of ASCII string + 'padding to 32-bit word aligned'.
*/
return (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE) +
(Node->IdMappingCount *
sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)) +
ALIGN_VALUE (AsciiStrSize (Node->ObjectName), 4));
}
/** Returns the total size required for the Named Component 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 Named Component node list.
@param [in] NodeCount Count of the Named Component nodes.
@param [in, out] NodeIndexer Pointer to the next Node Indexer.
@retval Total size of the Named Component nodes.
**/
STATIC
UINT64
GetSizeofNamedComponentNodes (
IN CONST UINT32 NodeStartOffset,
IN CONST CM_ARM_NAMED_COMPONENT_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 += GetNamedComponentNodeSize (NodeList);
(*NodeIndexer)++;
NodeList++;
}
return Size;
}
/** Returns the size of the Root Complex node.
@param [in] Node Pointer to Root Complex node.
@retval Size of the Root Complex node.
**/
STATIC
UINT32
GetRootComplexNodeSize (
IN CONST CM_ARM_ROOT_COMPLEX_NODE *Node
)
{
ASSERT (Node != NULL);
/* Size of Root Complex node +
Size of ID mapping array
*/
return (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE) +
(Node->IdMappingCount *
sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)));
}
/** Returns the total size required for the Root Complex 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 Root Complex node list.
@param [in] NodeCount Count of the Root Complex nodes.
@param [in, out] NodeIndexer Pointer to the next Node Indexer.
@retval Total size of the Root Complex nodes.
**/
STATIC
UINT64
GetSizeofRootComplexNodes (
IN CONST UINT32 NodeStartOffset,
IN CONST CM_ARM_ROOT_COMPLEX_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 += GetRootComplexNodeSize (NodeList);
(*NodeIndexer)++;
NodeList++;
}
return Size;
}
/** Returns the size of the SMMUv1/SMMUv2 node.
@param [in] Node Pointer to SMMUv1/SMMUv2 node list.
@retval Size of the SMMUv1/SMMUv2 node.
**/
STATIC
UINT32
GetSmmuV1V2NodeSize (
IN CONST CM_ARM_SMMUV1_SMMUV2_NODE *Node
)
{
ASSERT (Node != NULL);
/* Size of SMMU v1/SMMU v2 node +
Size of ID mapping array +
Size of context interrupt array +
Size of PMU interrupt array
*/
return (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE) +
(Node->IdMappingCount *
sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)) +
(Node->ContextInterruptCount *
sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT)) +
(Node->PmuInterruptCount *
sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT)));
}
/** Returns the total size required for the SMMUv1/SMMUv2 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 SMMUv1/SMMUv2 node list.
@param [in] NodeCount Count of the SMMUv1/SMMUv2 nodes.
@param [in, out] NodeIndexer Pointer to the next Node Indexer.
@retval Total size of the SMMUv1/SMMUv2 nodes.
**/
STATIC
UINT64
GetSizeofSmmuV1V2Nodes (
IN CONST UINT32 NodeStartOffset,
IN CONST CM_ARM_SMMUV1_SMMUV2_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 += GetSmmuV1V2NodeSize (NodeList);
(*NodeIndexer)++;
NodeList++;
}
return Size;
}
/** Returns the size of the SMMUv3 node.
@param [in] Node Pointer to SMMUv3 node list.
@retval Total size of the SMMUv3 nodes.
**/
STATIC
UINT32
GetSmmuV3NodeSize (
IN CONST CM_ARM_SMMUV3_NODE *Node
)
{
ASSERT (Node != NULL);
/* Size of SMMU v1/SMMU v2 node +
Size of ID mapping array
*/
return (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE) +
(Node->IdMappingCount *
sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)));
}
/** Returns the total size required for the SMMUv3 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 SMMUv3 node list.
@param [in] NodeCount Count of the SMMUv3 nodes.
@param [in, out] NodeIndexer Pointer to the next Node Indexer.
@retval Total size of the SMMUv3 nodes.
**/
STATIC
UINT64
GetSizeofSmmuV3Nodes (
IN CONST UINT32 NodeStartOffset,
IN CONST CM_ARM_SMMUV3_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 += GetSmmuV3NodeSize (NodeList);
(*NodeIndexer)++;
NodeList++;
}
return Size;
}
/** Returns the size of the PMCG node.
@param [in] Node Pointer to PMCG node.
@retval Size of the PMCG node.
**/
STATIC
UINT32
GetPmcgNodeSize (
IN CONST CM_ARM_PMCG_NODE *Node
)
{
ASSERT (Node != NULL);
/* Size of PMCG node +
Size of ID mapping array
*/
return (UINT32)(sizeof (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE) +
(Node->IdMappingCount *
sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE)));
}
/** Returns the total size required for the PMCG 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 PMCG node list.
@param [in] NodeCount Count of the PMCG nodes.
@param [in, out] NodeIndexer Pointer to the next Node Indexer.
@retval Total size of the PMCG nodes.
**/
STATIC
UINT64
GetSizeofPmcgNodes (
IN CONST UINT32 NodeStartOffset,
IN CONST CM_ARM_PMCG_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 += GetPmcgNodeSize (NodeList);
(*NodeIndexer)++;
NodeList++;
}
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.
@param [in] NodeCount Count of the nodes.
@param [in] Token Reference token for the node.
@param [out] NodeOffset Offset of the node from the
start of the IORT table.
@retval EFI_SUCCESS Success.
@retval EFI_NOT_FOUND No matching token reference
found in node indexer array.
**/
STATIC
EFI_STATUS
GetNodeOffsetReferencedByToken (
IN IORT_NODE_INDEXER *NodeIndexer,
IN UINT32 NodeCount,
IN CM_OBJECT_TOKEN Token,
OUT UINT32 *NodeOffset
)
{
DEBUG ((
DEBUG_INFO,
"IORT: Node Indexer: Search Token = %p\n",
Token
));
while (NodeCount-- != 0) {
DEBUG ((
DEBUG_INFO,
"IORT: Node Indexer: NodeIndexer->Token = %p, Offset = %d\n",
NodeIndexer->Token,
NodeIndexer->Offset
));
if (NodeIndexer->Token == Token) {
*NodeOffset = NodeIndexer->Offset;
DEBUG ((
DEBUG_INFO,
"IORT: Node Indexer: Token = %p, Found\n",
Token
));
return EFI_SUCCESS;
}
NodeIndexer++;
}
DEBUG ((
DEBUG_INFO,
"IORT: Node Indexer: Token = %p, Not Found\n",
Token
));
return EFI_NOT_FOUND;
}
/** Update the Id Mapping Array.
This function retrieves the Id Mapping Array object referenced by the
IdMappingToken and updates the IdMapArray.
@param [in] This Pointer to the table Generator.
@param [in] CfgMgrProtocol Pointer to the Configuration Manager
Protocol Interface.
@param [in] IdMapArray Pointer to an array of Id Mappings.
@param [in] IdCount Number of Id Mappings.
@param [in] IdMappingToken Reference Token for retrieving the
Id Mapping Array object.
@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
AddIdMappingArray (
IN CONST ACPI_TABLE_GENERATOR *CONST This,
IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
IN EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *IdMapArray,
IN UINT32 IdCount,
IN CONST CM_OBJECT_TOKEN IdMappingToken
)
{
EFI_STATUS Status;
CM_ARM_ID_MAPPING *IdMappings;
UINT32 IdMappingCount;
ACPI_IORT_GENERATOR *Generator;
ASSERT (IdMapArray != NULL);
Generator = (ACPI_IORT_GENERATOR *)This;
// Get the Id Mapping Array
Status = GetEArmObjIdMappingArray (
CfgMgrProtocol,
IdMappingToken,
&IdMappings,
&IdMappingCount
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to get Id Mapping array. Status = %r\n",
Status
));
return Status;
}
if (IdMappingCount < IdCount) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to get the required number of Id Mappings.\n"
));
return EFI_NOT_FOUND;
}
// Populate the Id Mapping array
while (IdCount-- != 0) {
Status = GetNodeOffsetReferencedByToken (
Generator->NodeIndexer,
Generator->IortNodeCount,
IdMappings->OutputReferenceToken,
&IdMapArray->OutputReference
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to get Output Reference for ITS Identifier array."
"Reference Token = %p"
" Status = %r\n",
IdMappings->OutputReferenceToken,
Status
));
return Status;
}
IdMapArray->InputBase = IdMappings->InputBase;
IdMapArray->NumIds = IdMappings->NumIds;
IdMapArray->OutputBase = IdMappings->OutputBase;
IdMapArray->Flags = IdMappings->Flags;
IdMapArray++;
IdMappings++;
} // Id Mapping array
return EFI_SUCCESS;
}
/** Update the ITS Group Node Information.
@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.
@param [in] NodeList Pointer to an array of ITS Group Node
Objects.
@param [in] NodeCount Number of ITS Group 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
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,
IN UINT32 NodeCount
)
{
EFI_STATUS Status;
EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE *ItsGroupNode;
UINT32 *ItsIds;
CM_ARM_ITS_IDENTIFIER *ItsIdentifier;
UINT32 ItsIdentifierCount;
UINT32 IdIndex;
UINT64 NodeLength;
ASSERT (Iort != NULL);
ItsGroupNode = (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE *)((UINT8 *)Iort +
NodesStartOffset);
while (NodeCount-- != 0) {
NodeLength = GetItsGroupNodeSize (NodeList);
if (NodeLength > MAX_UINT16) {
Status = EFI_INVALID_PARAMETER;
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: ITS Id Array Node length 0x%lx > MAX_UINT16."
" Status = %r\n",
NodeLength,
Status
));
return Status;
}
// Populate the node header
ItsGroupNode->Node.Type = EFI_ACPI_IORT_TYPE_ITS_GROUP;
ItsGroupNode->Node.Length = (UINT16)NodeLength;
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 +
sizeof (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE));
Status = GetEArmObjGicItsIdentifierArray (
CfgMgrProtocol,
NodeList->ItsIdToken,
&ItsIdentifier,
&ItsIdentifierCount
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to get ITS Identifier array. Status = %r\n",
Status
));
return Status;
}
if (ItsIdentifierCount < ItsGroupNode->NumItsIdentifiers) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to get the required number of ITS Identifiers.\n"
));
return EFI_NOT_FOUND;
}
// Populate the ITS identifier array
for (IdIndex = 0; IdIndex < ItsGroupNode->NumItsIdentifiers; IdIndex++) {
ItsIds[IdIndex] = ItsIdentifier[IdIndex].ItsId;
} // ITS identifier array
// Next IORT Group Node
ItsGroupNode = (EFI_ACPI_6_0_IO_REMAPPING_ITS_NODE *)((UINT8 *)ItsGroupNode +
ItsGroupNode->Node.Length);
NodeList++;
} // IORT Group Node
return EFI_SUCCESS;
}
/** Update the Named Component Node Information.
This function updates the Named Component 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 Named
Component Nodes.
@param [in] NodeList Pointer to an array of Named Component
Node Objects.
@param [in] NodeCount Number of Named Component 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
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,
IN UINT32 NodeCount
)
{
EFI_STATUS Status;
EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE *NcNode;
EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *IdMapArray;
CHAR8 *ObjectName;
UINTN ObjectNameLength;
UINT64 NodeLength;
ASSERT (Iort != NULL);
NcNode = (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE *)((UINT8 *)Iort +
NodesStartOffset);
while (NodeCount-- != 0) {
NodeLength = GetNamedComponentNodeSize (NodeList);
if (NodeLength > MAX_UINT16) {
Status = EFI_INVALID_PARAMETER;
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Named Component Node length 0x%lx > MAX_UINT16."
" Status = %r\n",
NodeLength,
Status
));
return Status;
}
// Populate the node header
NcNode->Node.Type = EFI_ACPI_IORT_TYPE_NAMED_COMP;
NcNode->Node.Length = (UINT16)NodeLength;
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) +
(ALIGN_VALUE (ObjectNameLength, 4))));
// Named Component specific data
NcNode->Flags = NodeList->Flags;
NcNode->CacheCoherent = NodeList->CacheCoherent;
NcNode->AllocationHints = NodeList->AllocationHints;
NcNode->Reserved = EFI_ACPI_RESERVED_WORD;
NcNode->MemoryAccessFlags = NodeList->MemoryAccessFlags;
NcNode->AddressSizeLimit = NodeList->AddressSizeLimit;
// Copy the object name
ObjectName = (CHAR8 *)((UINT8 *)NcNode +
sizeof (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE));
Status = AsciiStrCpyS (
ObjectName,
ObjectNameLength,
NodeList->ObjectName
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to copy Object Name. Status = %r\n",
Status
));
return Status;
}
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 Named Component
IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *)((UINT8 *)NcNode +
NcNode->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;
}
}
// Next Named Component Node
NcNode = (EFI_ACPI_6_0_IO_REMAPPING_NAMED_COMP_NODE *)((UINT8 *)NcNode +
NcNode->Node.Length);
NodeList++;
} // Named Component Node
return EFI_SUCCESS;
}
/** Update the Root Complex Node Information.
This function updates the Root Complex 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 Root Complex
Nodes.
@param [in] NodeList Pointer to an array of Root Complex Node
Objects.
@param [in] NodeCount Number of Root Complex 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
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,
IN UINT32 NodeCount
)
{
EFI_STATUS Status;
EFI_ACPI_6_0_IO_REMAPPING_RC_NODE *RcNode;
EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *IdMapArray;
UINT64 NodeLength;
ASSERT (Iort != NULL);
RcNode = (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE *)((UINT8 *)Iort +
NodesStartOffset);
while (NodeCount-- != 0) {
NodeLength = GetRootComplexNodeSize (NodeList);
if (NodeLength > MAX_UINT16) {
Status = EFI_INVALID_PARAMETER;
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Root Complex Node length 0x%lx > MAX_UINT16."
" Status = %r\n",
NodeLength,
Status
));
return Status;
}
// Populate the node header
RcNode->Node.Type = EFI_ACPI_IORT_TYPE_ROOT_COMPLEX;
RcNode->Node.Length = (UINT16)NodeLength;
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;
RcNode->Reserved = EFI_ACPI_RESERVED_WORD;
RcNode->MemoryAccessFlags = NodeList->MemoryAccessFlags;
RcNode->AtsAttribute = NodeList->AtsAttribute;
RcNode->PciSegmentNumber = NodeList->PciSegmentNumber;
RcNode->MemoryAddressSize = NodeList->MemoryAddressSize;
RcNode->Reserved1[0] = EFI_ACPI_RESERVED_BYTE;
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 Root Complex
IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *)((UINT8 *)RcNode +
RcNode->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;
}
}
// Next Root Complex Node
RcNode = (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE *)((UINT8 *)RcNode +
RcNode->Node.Length);
NodeList++;
} // Root Complex Node
return EFI_SUCCESS;
}
/** Update the SMMU Interrupt Array.
This function retrieves the InterruptArray object referenced by the
InterruptToken and updates the SMMU InterruptArray.
@param [in] CfgMgrProtocol Pointer to the Configuration Manager
Protocol Interface.
@param [in, out] InterruptArray Pointer to an array of Interrupts.
@param [in] InterruptCount Number of entries in the InterruptArray.
@param [in] InterruptToken Reference Token for retrieving the SMMU
InterruptArray object.
@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
AddSmmuInterruptArray (
IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
IN OUT EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT *InterruptArray,
IN UINT32 InterruptCount,
IN CONST CM_OBJECT_TOKEN InterruptToken
)
{
EFI_STATUS Status;
CM_ARM_SMMU_INTERRUPT *SmmuInterrupt;
UINT32 SmmuInterruptCount;
ASSERT (InterruptArray != NULL);
// Get the SMMU Interrupt Array
Status = GetEArmObjSmmuInterruptArray (
CfgMgrProtocol,
InterruptToken,
&SmmuInterrupt,
&SmmuInterruptCount
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to get SMMU Interrupt array. Status = %r\n",
Status
));
return Status;
}
if (SmmuInterruptCount < InterruptCount) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to get the required number of SMMU Interrupts.\n"
));
return EFI_NOT_FOUND;
}
// Populate the Id Mapping array
while (InterruptCount-- != 0) {
InterruptArray->Interrupt = SmmuInterrupt->Interrupt;
InterruptArray->InterruptFlags = SmmuInterrupt->Flags;
InterruptArray++;
SmmuInterrupt++;
} // Id Mapping array
return EFI_SUCCESS;
}
/** Update the SMMU v1/v2 Node Information.
@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.
@param [in] NodeList Pointer to an array of SMMU v1/v2 Node
Objects.
@param [in] NodeCount Number of SMMU v1/v2 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
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,
IN UINT32 NodeCount
)
{
EFI_STATUS Status;
EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE *SmmuNode;
EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *IdMapArray;
EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT *ContextInterruptArray;
EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT *PmuInterruptArray;
UINT64 NodeLength;
UINT32 Offset;
ASSERT (Iort != NULL);
SmmuNode = (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE *)((UINT8 *)Iort +
NodesStartOffset);
while (NodeCount-- != 0) {
NodeLength = GetSmmuV1V2NodeSize (NodeList);
if (NodeLength > MAX_UINT16) {
Status = EFI_INVALID_PARAMETER;
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: SMMU V1/V2 Node length 0x%lx > MAX_UINT16. Status = %r\n",
NodeLength,
Status
));
return Status;
}
// Populate the node header
SmmuNode->Node.Type = EFI_ACPI_IORT_TYPE_SMMUv1v2;
SmmuNode->Node.Length = (UINT16)NodeLength;
SmmuNode->Node.NumIdMappings = NodeList->IdMappingCount;
SmmuNode->Node.IdReference = (NodeList->IdMappingCount == 0) ?
0 : (sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE) +
(NodeList->ContextInterruptCount *
sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT)) +
(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;
SmmuNode->Model = NodeList->Model;
SmmuNode->Flags = NodeList->Flags;
// Reference to Global Interrupt Array
SmmuNode->GlobalInterruptArrayRef =
OFFSET_OF (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE, SMMU_NSgIrpt);
Offset = sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE);
// Context Interrupt
SmmuNode->NumContextInterrupts = NodeList->ContextInterruptCount;
if (NodeList->ContextInterruptCount != 0) {
SmmuNode->ContextInterruptArrayRef = Offset;
ContextInterruptArray =
(EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT *)((UINT8 *)SmmuNode + Offset);
Offset += (NodeList->ContextInterruptCount *
sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT));
}
// PMU Interrupt
SmmuNode->NumPmuInterrupts = NodeList->PmuInterruptCount;
if (NodeList->PmuInterruptCount != 0) {
SmmuNode->PmuInterruptArrayRef = Offset;
PmuInterruptArray =
(EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT *)((UINT8 *)SmmuNode + Offset);
}
SmmuNode->SMMU_NSgIrpt = NodeList->SMMU_NSgIrpt;
SmmuNode->SMMU_NSgIrptFlags = NodeList->SMMU_NSgIrptFlags;
SmmuNode->SMMU_NSgCfgIrpt = NodeList->SMMU_NSgCfgIrpt;
SmmuNode->SMMU_NSgCfgIrptFlags = NodeList->SMMU_NSgCfgIrptFlags;
if (NodeList->ContextInterruptCount != 0) {
if (NodeList->ContextInterruptToken == CM_NULL_TOKEN) {
Status = EFI_INVALID_PARAMETER;
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Invalid Context Interrupt token,"
" Token = 0x%x, Status =%r\n",
NodeList->ContextInterruptToken,
Status
));
return Status;
}
// Add Context Interrupt Array
Status = AddSmmuInterruptArray (
CfgMgrProtocol,
ContextInterruptArray,
SmmuNode->NumContextInterrupts,
NodeList->ContextInterruptToken
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to Context Interrupt Array. Status = %r\n",
Status
));
return Status;
}
}
// Add PMU Interrupt Array
if (SmmuNode->NumPmuInterrupts != 0) {
if (NodeList->PmuInterruptToken == CM_NULL_TOKEN) {
Status = EFI_INVALID_PARAMETER;
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Invalid PMU Interrupt token,"
" Token = 0x%x, Status =%r\n",
NodeList->PmuInterruptToken,
Status
));
return Status;
}
Status = AddSmmuInterruptArray (
CfgMgrProtocol,
PmuInterruptArray,
SmmuNode->NumPmuInterrupts,
NodeList->PmuInterruptToken
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to PMU Interrupt Array. Status = %r\n",
Status
));
return Status;
}
}
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 SMMU v1/v2 Node
IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *)((UINT8 *)SmmuNode +
SmmuNode->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;
}
}
// Next SMMU v1/v2 Node
SmmuNode = (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE *)((UINT8 *)SmmuNode +
SmmuNode->Node.Length);
NodeList++;
} // SMMU v1/v2 Node
return EFI_SUCCESS;
}
/** Update the SMMUv3 Node Information.
This function updates the SMMUv3 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 SMMUv3 Nodes.
@param [in] NodeList Pointer to an array of SMMUv3 Node Objects.
@param [in] NodeCount Number of SMMUv3 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
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,
IN UINT32 NodeCount
)
{
EFI_STATUS Status;
EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE *SmmuV3Node;
EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *IdMapArray;
UINT64 NodeLength;
ASSERT (Iort != NULL);
SmmuV3Node = (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE *)((UINT8 *)Iort +
NodesStartOffset);
while (NodeCount-- != 0) {
NodeLength = GetSmmuV3NodeSize (NodeList);
if (NodeLength > MAX_UINT16) {
Status = EFI_INVALID_PARAMETER;
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: SMMU V3 Node length 0x%lx > MAX_UINT16. Status = %r\n",
NodeLength,
Status
));
return Status;
}
// Populate the node header
SmmuV3Node->Node.Type = EFI_ACPI_IORT_TYPE_SMMUv3;
SmmuV3Node->Node.Length = (UINT16)NodeLength;
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;
SmmuV3Node->Reserved = EFI_ACPI_RESERVED_WORD;
SmmuV3Node->VatosAddress = NodeList->VatosAddress;
SmmuV3Node->Model = NodeList->Model;
SmmuV3Node->Event = NodeList->EventInterrupt;
SmmuV3Node->Pri = NodeList->PriInterrupt;
SmmuV3Node->Gerr = NodeList->GerrInterrupt;
SmmuV3Node->Sync = NodeList->SyncInterrupt;
if ((SmmuV3Node->Flags & EFI_ACPI_IORT_SMMUv3_FLAG_PROXIMITY_DOMAIN) != 0) {
// The Proximity Domain Valid flag is set to 1
SmmuV3Node->ProximityDomain = NodeList->ProximityDomain;
} else {
SmmuV3Node->ProximityDomain = 0;
}
if ((SmmuV3Node->Event != 0) && (SmmuV3Node->Pri != 0) &&
(SmmuV3Node->Gerr != 0) && (SmmuV3Node->Sync != 0))
{
// If all the SMMU control interrupts are GSIV based,
// the DeviceID mapping index field is ignored.
SmmuV3Node->DeviceIdMappingIndex = 0;
} else {
SmmuV3Node->DeviceIdMappingIndex = NodeList->DeviceIdMappingIndex;
}
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 SMMUv3 node
IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *)((UINT8 *)SmmuV3Node +
SmmuV3Node->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;
}
}
// Next SMMUv3 Node
SmmuV3Node = (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE *)((UINT8 *)SmmuV3Node +
SmmuV3Node->Node.Length);
NodeList++;
} // SMMUv3 Node
return EFI_SUCCESS;
}
/** Update the PMCG Node Information.
This function updates the PMCG 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
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,
IN UINT32 NodeCount
)
{
EFI_STATUS Status;
EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE *PmcgNode;
EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *IdMapArray;
ACPI_IORT_GENERATOR *Generator;
UINT64 NodeLength;
ASSERT (Iort != NULL);
Generator = (ACPI_IORT_GENERATOR *)This;
PmcgNode = (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE *)((UINT8 *)Iort +
NodesStartOffset);
while (NodeCount-- != 0) {
NodeLength = GetPmcgNodeSize (NodeList);
if (NodeLength > MAX_UINT16) {
Status = EFI_INVALID_PARAMETER;
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: PMCG Node length 0x%lx > MAX_UINT16. Status = %r\n",
NodeLength,
Status
));
return Status;
}
// Populate the node header
PmcgNode->Node.Type = EFI_ACPI_IORT_TYPE_PMCG;
PmcgNode->Node.Length = (UINT16)NodeLength;
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;
PmcgNode->Page1Base = NodeList->Page1BaseAddress;
Status = GetNodeOffsetReferencedByToken (
Generator->NodeIndexer,
Generator->IortNodeCount,
NodeList->ReferenceToken,
&PmcgNode->NodeReference
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to get Output Reference for PMCG Node."
"Reference Token = %p"
" Status = %r\n",
NodeList->ReferenceToken,
Status
));
return Status;
}
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 PMCG node
IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *)((UINT8 *)PmcgNode +
PmcgNode->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;
}
}
// Next PMCG Node
PmcgNode = (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE *)((UINT8 *)PmcgNode +
PmcgNode->Node.Length);
NodeList++;
} // PMCG Node
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
to get the required hardware information for generating the ACPI
table.
If this function allocates any resources then they must be freed
in the FreeXXXXTableResources function.
@param [in] This Pointer to the table generator.
@param [in] AcpiTableInfo Pointer to the ACPI Table Info.
@param [in] CfgMgrProtocol Pointer to the Configuration Manager
Protocol Interface.
@param [out] Table Pointer to the constructed ACPI Table.
@retval EFI_SUCCESS Table generated successfully.
@retval EFI_INVALID_PARAMETER A parameter is invalid.
@retval EFI_NOT_FOUND The required object was not found.
@retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration
Manager is less than the Object size for the
requested object.
**/
STATIC
EFI_STATUS
EFIAPI
BuildIortTable (
IN CONST ACPI_TABLE_GENERATOR *CONST This,
IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
OUT EFI_ACPI_DESCRIPTION_HEADER **CONST Table
)
{
EFI_STATUS Status;
UINT64 TableSize;
UINT64 NodeSize;
UINT32 IortNodeCount;
UINT32 ItsGroupNodeCount;
UINT32 NamedComponentNodeCount;
UINT32 RootComplexNodeCount;
UINT32 SmmuV1V2NodeCount;
UINT32 SmmuV3NodeCount;
UINT32 PmcgNodeCount;
UINT32 RmrNodeCount;
UINT32 ItsGroupOffset;
UINT32 NamedComponentOffset;
UINT32 RootComplexOffset;
UINT32 SmmuV1V2Offset;
UINT32 SmmuV3Offset;
UINT32 PmcgOffset;
UINT32 RmrOffset;
CM_ARM_ITS_GROUP_NODE *ItsGroupNodeList;
CM_ARM_NAMED_COMPONENT_NODE *NamedComponentNodeList;
CM_ARM_ROOT_COMPLEX_NODE *RootComplexNodeList;
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;
ACPI_IORT_GENERATOR *Generator;
ASSERT (This != NULL);
ASSERT (AcpiTableInfo != NULL);
ASSERT (CfgMgrProtocol != NULL);
ASSERT (Table != NULL);
ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
RmrNodeCount = 0;
if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||
(AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision))
{
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Requested table revision = %d, is not supported."
"Supported table revision: Minimum = %d, Maximum = %d\n",
AcpiTableInfo->AcpiTableRevision,
This->MinAcpiTableRevision,
This->AcpiTableRevision
));
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;
// Get the ITS group node info
Status = GetEArmObjItsGroup (
CfgMgrProtocol,
CM_NULL_TOKEN,
&ItsGroupNodeList,
&ItsGroupNodeCount
);
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to get ITS Group Node Info. Status = %r\n",
Status
));
goto error_handler;
}
// Add the ITS group node count
IortNodeCount = ItsGroupNodeCount;
// Get the Named component node info
Status = GetEArmObjNamedComponent (
CfgMgrProtocol,
CM_NULL_TOKEN,
&NamedComponentNodeList,
&NamedComponentNodeCount
);
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to get Named Component Node Info. Status = %r\n",
Status
));
goto error_handler;
}
// Add the Named Component group count
IortNodeCount += NamedComponentNodeCount;
// Get the Root complex node info
Status = GetEArmObjRootComplex (
CfgMgrProtocol,
CM_NULL_TOKEN,
&RootComplexNodeList,
&RootComplexNodeCount
);
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to get Root Complex Node Info. Status = %r\n",
Status
));
goto error_handler;
}
// Add the Root Complex node count
IortNodeCount += RootComplexNodeCount;
// Get the SMMU v1/v2 node info
Status = GetEArmObjSmmuV1SmmuV2 (
CfgMgrProtocol,
CM_NULL_TOKEN,
&SmmuV1V2NodeList,
&SmmuV1V2NodeCount
);
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to get SMMUv1/SMMUv2 Node Info. Status = %r\n",
Status
));
goto error_handler;
}
// Add the SMMU v1/v2 node count
IortNodeCount += SmmuV1V2NodeCount;
// Get the SMMUv3 node info
Status = GetEArmObjSmmuV3 (
CfgMgrProtocol,
CM_NULL_TOKEN,
&SmmuV3NodeList,
&SmmuV3NodeCount
);
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to get SMMUv3 Node Info. Status = %r\n",
Status
));
goto error_handler;
}
// Add the SMMUv3 node count
IortNodeCount += SmmuV3NodeCount;
// Get the PMCG node info
Status = GetEArmObjPmcg (
CfgMgrProtocol,
CM_NULL_TOKEN,
&PmcgNodeList,
&PmcgNodeCount
);
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to get PMCG Node Info. Status = %r\n",
Status
));
goto error_handler;
}
// 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) *
IortNodeCount)
);
if (NodeIndexer == NULL) {
Status = EFI_OUT_OF_RESOURCES;
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to allocate memory for Node Indexer" \
" Status = %r\n",
Status
));
goto error_handler;
}
DEBUG ((DEBUG_INFO, "INFO: NodeIndexer = %p\n", NodeIndexer));
Generator->IortNodeCount = IortNodeCount;
Generator->NodeIndexer = NodeIndexer;
// Calculate the size of the IORT table
TableSize = sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE);
// ITS Group Nodes
if (ItsGroupNodeCount > 0) {
ItsGroupOffset = (UINT32)TableSize;
// Size of ITS Group node list.
NodeSize = GetSizeofItsGroupNodes (
ItsGroupOffset,
ItsGroupNodeList,
ItsGroupNodeCount,
&NodeIndexer
);
if (NodeSize > MAX_UINT32) {
Status = EFI_INVALID_PARAMETER;
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Invalid Size of Group Nodes. Status = %r\n",
Status
));
goto error_handler;
}
TableSize += NodeSize;
DEBUG ((
DEBUG_INFO,
" ItsGroupNodeCount = %d\n" \
" ItsGroupOffset = %d\n",
ItsGroupNodeCount,
ItsGroupOffset
));
}
// Named Component Nodes
if (NamedComponentNodeCount > 0) {
NamedComponentOffset = (UINT32)TableSize;
// Size of Named Component node list.
NodeSize = GetSizeofNamedComponentNodes (
NamedComponentOffset,
NamedComponentNodeList,
NamedComponentNodeCount,
&NodeIndexer
);
if (NodeSize > MAX_UINT32) {
Status = EFI_INVALID_PARAMETER;
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Invalid Size of Named Component Nodes. Status = %r\n",
Status
));
goto error_handler;
}
TableSize += NodeSize;
DEBUG ((
DEBUG_INFO,
" NamedComponentNodeCount = %d\n" \
" NamedComponentOffset = %d\n",
NamedComponentNodeCount,
NamedComponentOffset
));
}
// Root Complex Nodes
if (RootComplexNodeCount > 0) {
RootComplexOffset = (UINT32)TableSize;
// Size of Root Complex node list.
NodeSize = GetSizeofRootComplexNodes (
RootComplexOffset,
RootComplexNodeList,
RootComplexNodeCount,
&NodeIndexer
);
if (NodeSize > MAX_UINT32) {
Status = EFI_INVALID_PARAMETER;
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Invalid Size of Root Complex Nodes. Status = %r\n",
Status
));
goto error_handler;
}
TableSize += NodeSize;
DEBUG ((
DEBUG_INFO,
" RootComplexNodeCount = %d\n" \
" RootComplexOffset = %d\n",
RootComplexNodeCount,
RootComplexOffset
));
}
// SMMUv1/SMMUv2 Nodes
if (SmmuV1V2NodeCount > 0) {
SmmuV1V2Offset = (UINT32)TableSize;
// Size of SMMUv1/SMMUv2 node list.
NodeSize = GetSizeofSmmuV1V2Nodes (
SmmuV1V2Offset,
SmmuV1V2NodeList,
SmmuV1V2NodeCount,
&NodeIndexer
);
if (NodeSize > MAX_UINT32) {
Status = EFI_INVALID_PARAMETER;
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Invalid Size of SMMUv1/v2 Nodes. Status = %r\n",
Status
));
goto error_handler;
}
TableSize += NodeSize;
DEBUG ((
DEBUG_INFO,
" SmmuV1V2NodeCount = %d\n" \
" SmmuV1V2Offset = %d\n",
SmmuV1V2NodeCount,
SmmuV1V2Offset
));
}
// SMMUv3 Nodes
if (SmmuV3NodeCount > 0) {
SmmuV3Offset = (UINT32)TableSize;
// Size of SMMUv3 node list.
NodeSize = GetSizeofSmmuV3Nodes (
SmmuV3Offset,
SmmuV3NodeList,
SmmuV3NodeCount,
&NodeIndexer
);
if (NodeSize > MAX_UINT32) {
Status = EFI_INVALID_PARAMETER;
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Invalid Size of SMMUv3 Nodes. Status = %r\n",
Status
));
goto error_handler;
}
TableSize += NodeSize;
DEBUG ((
DEBUG_INFO,
" SmmuV3NodeCount = %d\n" \
" SmmuV3Offset = %d\n",
SmmuV3NodeCount,
SmmuV3Offset
));
}
// PMCG Nodes
if (PmcgNodeCount > 0) {
PmcgOffset = (UINT32)TableSize;
// Size of PMCG node list.
NodeSize = GetSizeofPmcgNodes (
PmcgOffset,
PmcgNodeList,
PmcgNodeCount,
&NodeIndexer
);
if (NodeSize > MAX_UINT32) {
Status = EFI_INVALID_PARAMETER;
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Invalid Size of PMCG Nodes. Status = %r\n",
Status
));
goto error_handler;
}
TableSize += NodeSize;
DEBUG ((
DEBUG_INFO,
" PmcgNodeCount = %d\n" \
" PmcgOffset = %d\n",
PmcgNodeCount,
PmcgOffset
));
}
// 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" \
" IortNodeCount = %d\n" \
" TableSize = 0x%lx\n",
IortNodeCount,
TableSize
));
if (TableSize > MAX_UINT32) {
Status = EFI_INVALID_PARAMETER;
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: IORT Table Size 0x%lx > MAX_UINT32," \
" Status = %r\n",
TableSize,
Status
));
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) {
Status = EFI_OUT_OF_RESOURCES;
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to allocate memory for IORT Table, Size = %d," \
" Status = %r\n",
TableSize,
Status
));
goto error_handler;
}
Iort = (EFI_ACPI_6_0_IO_REMAPPING_TABLE *)*Table;
DEBUG ((
DEBUG_INFO,
"IORT: Iort = 0x%p TableSize = 0x%lx\n",
Iort,
TableSize
));
Status = AddAcpiHeader (
CfgMgrProtocol,
This,
&Iort->Header,
AcpiTableInfo,
(UINT32)TableSize
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to add ACPI header. Status = %r\n",
Status
));
goto error_handler;
}
// Update IORT table
Iort->NumNodes = IortNodeCount;
Iort->NodeOffset = sizeof (EFI_ACPI_6_0_IO_REMAPPING_TABLE);
Iort->Reserved = EFI_ACPI_RESERVED_DWORD;
if (ItsGroupNodeCount > 0) {
Status = AddItsGroupNodes (
This,
CfgMgrProtocol,
AcpiTableInfo,
Iort,
ItsGroupOffset,
ItsGroupNodeList,
ItsGroupNodeCount
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to add ITS Group Node. Status = %r\n",
Status
));
goto error_handler;
}
}
if (NamedComponentNodeCount > 0) {
Status = AddNamedComponentNodes (
This,
CfgMgrProtocol,
AcpiTableInfo,
Iort,
NamedComponentOffset,
NamedComponentNodeList,
NamedComponentNodeCount
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to add Named Component Node. Status = %r\n",
Status
));
goto error_handler;
}
}
if (RootComplexNodeCount > 0) {
Status = AddRootComplexNodes (
This,
CfgMgrProtocol,
AcpiTableInfo,
Iort,
RootComplexOffset,
RootComplexNodeList,
RootComplexNodeCount
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to add Root Complex Node. Status = %r\n",
Status
));
goto error_handler;
}
}
if (SmmuV1V2NodeCount > 0) {
Status = AddSmmuV1V2Nodes (
This,
CfgMgrProtocol,
AcpiTableInfo,
Iort,
SmmuV1V2Offset,
SmmuV1V2NodeList,
SmmuV1V2NodeCount
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to add SMMU v1/v2 Node. Status = %r\n",
Status
));
goto error_handler;
}
}
if (SmmuV3NodeCount > 0) {
Status = AddSmmuV3Nodes (
This,
CfgMgrProtocol,
AcpiTableInfo,
Iort,
SmmuV3Offset,
SmmuV3NodeList,
SmmuV3NodeCount
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to add SMMUv3 Node. Status = %r\n",
Status
));
goto error_handler;
}
}
if (PmcgNodeCount > 0) {
Status = AddPmcgNodes (
This,
CfgMgrProtocol,
AcpiTableInfo,
Iort,
PmcgOffset,
PmcgNodeList,
PmcgNodeCount
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to add PMCG Node. Status = %r\n",
Status
));
goto error_handler;
}
}
if ((AcpiTableInfo->AcpiTableRevision >=
EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05) &&
(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;
}
}
return EFI_SUCCESS;
error_handler:
if (Generator->NodeIndexer != NULL) {
FreePool (Generator->NodeIndexer);
Generator->NodeIndexer = NULL;
}
if (*Table != NULL) {
FreePool (*Table);
*Table = NULL;
}
return Status;
}
/** Free any resources allocated for constructing the IORT
@param [in] This Pointer to the table generator.
@param [in] AcpiTableInfo Pointer to the ACPI Table Info.
@param [in] CfgMgrProtocol Pointer to the Configuration Manager
Protocol Interface.
@param [in, out] Table Pointer to the ACPI Table.
@retval EFI_SUCCESS The resources were freed successfully.
@retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.
**/
STATIC
EFI_STATUS
FreeIortTableResources (
IN CONST ACPI_TABLE_GENERATOR *CONST This,
IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *CONST AcpiTableInfo,
IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
IN OUT EFI_ACPI_DESCRIPTION_HEADER **CONST Table
)
{
ACPI_IORT_GENERATOR *Generator;
ASSERT (This != NULL);
ASSERT (AcpiTableInfo != NULL);
ASSERT (CfgMgrProtocol != NULL);
ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);
ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
Generator = (ACPI_IORT_GENERATOR *)This;
// Free any memory allocated by the generator
if (Generator->NodeIndexer != NULL) {
FreePool (Generator->NodeIndexer);
Generator->NodeIndexer = NULL;
}
if ((Table == NULL) || (*Table == NULL)) {
DEBUG ((DEBUG_ERROR, "ERROR: IORT: Invalid Table Pointer\n"));
ASSERT ((Table != NULL) && (*Table != NULL));
return EFI_INVALID_PARAMETER;
}
FreePool (*Table);
*Table = NULL;
return EFI_SUCCESS;
}
/** The IORT Table Generator revision.
*/
#define IORT_GENERATOR_REVISION CREATE_REVISION (1, 0)
/** The interface for the MADT Table Generator.
*/
STATIC
ACPI_IORT_GENERATOR IortGenerator = {
// ACPI table generator header
{
// Generator ID
CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdIort),
// Generator Description
L"ACPI.STD.IORT.GENERATOR",
// ACPI Table Signature
EFI_ACPI_6_4_IO_REMAPPING_TABLE_SIGNATURE,
// ACPI Table Revision supported by this Generator
EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05,
// Minimum supported ACPI Table Revision
EFI_ACPI_IO_REMAPPING_TABLE_REVISION_00,
// Creator ID
TABLE_GENERATOR_CREATOR_ID_ARM,
// Creator Revision
IORT_GENERATOR_REVISION,
// Build Table function
BuildIortTable,
// Free Resource function
FreeIortTableResources,
// Extended build function not needed
NULL,
// Extended build function not implemented by the generator.
// Hence extended free resource function is not required.
NULL
},
// IORT Generator private data
// Iort Node count
0,
// Pointer to Iort node indexer
NULL
};
/** Register the Generator with the ACPI Table Factory.
@param [in] ImageHandle The handle to the image.
@param [in] SystemTable Pointer to the System Table.
@retval EFI_SUCCESS The Generator is registered.
@retval EFI_INVALID_PARAMETER A parameter is invalid.
@retval EFI_ALREADY_STARTED The Generator for the Table ID
is already registered.
**/
EFI_STATUS
EFIAPI
AcpiIortLibConstructor (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
Status = RegisterAcpiTableGenerator (&IortGenerator.Header);
DEBUG ((DEBUG_INFO, "IORT: Register Generator. Status = %r\n", Status));
ASSERT_EFI_ERROR (Status);
return Status;
}
/** Deregister the Generator from the ACPI Table Factory.
@param [in] ImageHandle The handle to the image.
@param [in] SystemTable Pointer to the System Table.
@retval EFI_SUCCESS The Generator is deregistered.
@retval EFI_INVALID_PARAMETER A parameter is invalid.
@retval EFI_NOT_FOUND The Generator is not registered.
**/
EFI_STATUS
EFIAPI
AcpiIortLibDestructor (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
Status = DeregisterAcpiTableGenerator (&IortGenerator.Header);
DEBUG ((DEBUG_INFO, "Iort: Deregister Generator. Status = %r\n", Status));
ASSERT_EFI_ERROR (Status);
return Status;
}