mirror of https://github.com/acidanthera/audk.git
2230 lines
69 KiB
C
2230 lines
69 KiB
C
/** @file
|
|
IORT Table Generator
|
|
|
|
Copyright (c) 2017 - 2020, ARM Limited. All rights reserved.
|
|
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
|
|
|
|
**/
|
|
|
|
#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
|
|
- EArmObjGicItsIdentifierArray
|
|
- EArmObjIdMappingArray
|
|
- EArmObjGicItsIdentifierArray
|
|
*/
|
|
|
|
/** 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
|
|
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);
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
|
|
*NodeIndexer,
|
|
(*NodeIndexer)->Token,
|
|
(*NodeIndexer)->Object,
|
|
(*NodeIndexer)->Offset
|
|
));
|
|
|
|
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);
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
|
|
*NodeIndexer,
|
|
(*NodeIndexer)->Token,
|
|
(*NodeIndexer)->Object,
|
|
(*NodeIndexer)->Offset
|
|
));
|
|
|
|
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);
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
|
|
*NodeIndexer,
|
|
(*NodeIndexer)->Token,
|
|
(*NodeIndexer)->Object,
|
|
(*NodeIndexer)->Offset
|
|
));
|
|
|
|
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);
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
|
|
*NodeIndexer,
|
|
(*NodeIndexer)->Token,
|
|
(*NodeIndexer)->Object,
|
|
(*NodeIndexer)->Offset
|
|
));
|
|
|
|
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);
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
|
|
*NodeIndexer,
|
|
(*NodeIndexer)->Token,
|
|
(*NodeIndexer)->Object,
|
|
(*NodeIndexer)->Offset
|
|
));
|
|
|
|
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);
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"IORT: Node Indexer = %p, Token = %p, Object = %p, Offset = 0x%x\n",
|
|
*NodeIndexer,
|
|
(*NodeIndexer)->Token,
|
|
(*NodeIndexer)->Object,
|
|
(*NodeIndexer)->Offset
|
|
));
|
|
|
|
Size += GetPmcgNodeSize (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] 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 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.Revision = 0;
|
|
ItsGroupNode->Node.Reserved = EFI_ACPI_RESERVED_DWORD;
|
|
ItsGroupNode->Node.NumIdMappings = 0;
|
|
ItsGroupNode->Node.IdReference = 0;
|
|
|
|
// 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] 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 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.Revision = 2;
|
|
NcNode->Node.Reserved = EFI_ACPI_RESERVED_DWORD;
|
|
NcNode->Node.NumIdMappings = NodeList->IdMappingCount;
|
|
|
|
ObjectNameLength = AsciiStrLen (NodeList->ObjectName) + 1;
|
|
NcNode->Node.IdReference =
|
|
(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) &&
|
|
(NodeList->IdMappingToken != CM_NULL_TOKEN)) {
|
|
// 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] 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 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.Revision = 1;
|
|
RcNode->Node.Reserved = EFI_ACPI_RESERVED_DWORD;
|
|
RcNode->Node.NumIdMappings = NodeList->IdMappingCount;
|
|
RcNode->Node.IdReference = sizeof (EFI_ACPI_6_0_IO_REMAPPING_RC_NODE);
|
|
|
|
// 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;
|
|
RcNode->Reserved1[1] = EFI_ACPI_RESERVED_BYTE;
|
|
RcNode->Reserved1[2] = EFI_ACPI_RESERVED_BYTE;
|
|
|
|
if ((NodeList->IdMappingCount > 0) &&
|
|
(NodeList->IdMappingToken != CM_NULL_TOKEN)) {
|
|
// 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] 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 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;
|
|
|
|
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.Revision = 0;
|
|
SmmuNode->Node.Reserved = EFI_ACPI_RESERVED_DWORD;
|
|
SmmuNode->Node.NumIdMappings = NodeList->IdMappingCount;
|
|
SmmuNode->Node.IdReference = 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));
|
|
|
|
// 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);
|
|
|
|
// Context Interrupt
|
|
SmmuNode->NumContextInterrupts = NodeList->ContextInterruptCount;
|
|
SmmuNode->ContextInterruptArrayRef =
|
|
sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE);
|
|
ContextInterruptArray =
|
|
(EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT*)((UINT8*)SmmuNode +
|
|
sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_NODE));
|
|
|
|
// PMU Interrupt
|
|
SmmuNode->NumPmuInterrupts = NodeList->PmuInterruptCount;
|
|
SmmuNode->PmuInterruptArrayRef = SmmuNode->ContextInterruptArrayRef +
|
|
(NodeList->ContextInterruptCount *
|
|
sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT));
|
|
PmuInterruptArray =
|
|
(EFI_ACPI_6_0_IO_REMAPPING_SMMU_INT*)((UINT8*)SmmuNode +
|
|
SmmuNode->PmuInterruptArrayRef);
|
|
|
|
SmmuNode->SMMU_NSgIrpt = NodeList->SMMU_NSgIrpt;
|
|
SmmuNode->SMMU_NSgIrptFlags = NodeList->SMMU_NSgIrptFlags;
|
|
SmmuNode->SMMU_NSgCfgIrpt = NodeList->SMMU_NSgCfgIrpt;
|
|
SmmuNode->SMMU_NSgCfgIrptFlags = NodeList->SMMU_NSgCfgIrptFlags;
|
|
|
|
// 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) &&
|
|
(NodeList->PmuInterruptToken != CM_NULL_TOKEN)) {
|
|
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) &&
|
|
(NodeList->IdMappingToken != CM_NULL_TOKEN)) {
|
|
// 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] 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 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.Revision = 2;
|
|
SmmuV3Node->Node.Reserved = EFI_ACPI_RESERVED_DWORD;
|
|
SmmuV3Node->Node.NumIdMappings = NodeList->IdMappingCount;
|
|
SmmuV3Node->Node.IdReference =
|
|
sizeof (EFI_ACPI_6_0_IO_REMAPPING_SMMU3_NODE);
|
|
|
|
// 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) &&
|
|
(NodeList->IdMappingToken != CM_NULL_TOKEN)) {
|
|
// 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] 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 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.Revision = 1;
|
|
PmcgNode->Node.Reserved = EFI_ACPI_RESERVED_DWORD;
|
|
PmcgNode->Node.NumIdMappings = NodeList->IdMappingCount;
|
|
PmcgNode->Node.IdReference = sizeof (EFI_ACPI_6_0_IO_REMAPPING_PMCG_NODE);
|
|
|
|
// 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) &&
|
|
(NodeList->IdMappingToken != CM_NULL_TOKEN)) {
|
|
// 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;
|
|
}
|
|
|
|
/** 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 ItsGroupOffset;
|
|
UINT32 NamedComponentOffset;
|
|
UINT32 RootComplexOffset;
|
|
UINT32 SmmuV1V2Offset;
|
|
UINT32 SmmuV3Offset;
|
|
UINT32 PmcgOffset;
|
|
|
|
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;
|
|
|
|
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);
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
|
|
// 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
|
|
));
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
// 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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
Iort,
|
|
PmcgOffset,
|
|
PmcgNodeList,
|
|
PmcgNodeCount
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"ERROR: IORT: Failed to add SMMUv3 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_2_IO_REMAPPING_TABLE_SIGNATURE,
|
|
// ACPI Table Revision supported by this Generator
|
|
EFI_ACPI_IO_REMAPPING_TABLE_REVISION,
|
|
// Minimum supported ACPI Table Revision
|
|
EFI_ACPI_IO_REMAPPING_TABLE_REVISION,
|
|
// 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;
|
|
}
|