This commit is contained in:
LeviYeoReum 2026-08-27 07:46:50 +09:00 committed by GitHub
commit 8808fdae75
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 5719 additions and 132 deletions

View file

@ -117,6 +117,7 @@
"gerror",
"invoc",
"ITARGETSR",
"iwbdevicetabletemplate",
"GTBLOCK",
"lgreater",
"lless",

View file

@ -38,6 +38,7 @@
UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
[LibraryClasses.AARCH64]
ArmLib|MdePkg/Library/ArmLib/ArmBaseLib.inf
PL011UartLib|ArmPlatformPkg/Library/PL011UartLib/PL011UartLib.inf
[Components.common]

View file

@ -1,6 +1,6 @@
/** @file
Copyright (c) 2017 - 2024, Arm Limited. All rights reserved.<BR>
Copyright (c) 2017 - 2026, Arm Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
@ -55,6 +55,10 @@ typedef enum ArmObjectID {
EArmObjDmc620PmuRegInfo, ///< 25 - DMC620 PMU Reg Info
EArmObjProcessorSpecificBlockInfo, ///< 26 - Processor Specific Block.
EArmObjProcessorSpecificSubDataArchInfo, ///< 27 - Processor Specific Sub Data (ArchData)
EArmObjGicIrsInfo, ///< 28 - GIC IRS Info
EArmObjGicItsV5Info, ///< 29 - GIC ITS v5 Info
EArmObjGicItsV5TranslateFrameInfo, ///< 30 - GIC ITS v5 Translate Frame Info
EArmObjGicIwbInfo, ///< 34 - GIC IWB Info
EArmObjMax
} EARM_OBJECT_ID;
@ -205,6 +209,16 @@ typedef struct CmArmGicCInfo {
CM_ARM_GICC_INFO.ClockDomain
*/
CM_OBJECT_TOKEN ClockDomainToken;
/** GICv5 Interrupt Controller processor affinity ID.
This must be 0 for pre-v5 GIC.
*/
UINT16 IAffId;
/** The ID of the IRS that this processor is connected to.
This must be CM_NULL_TOKEN for pre-v5 GIC.
*/
CM_OBJECT_TOKEN IrsToken;
} CM_ARM_GICC_INFO;
/** A structure that describes the
@ -621,7 +635,7 @@ typedef struct CmArmPmcgNode {
ID: EArmObjGicItsIdentifierArray
*/
typedef struct CmArmGicItsIdentifier {
/// The ITS Identifier
/// The ITS Identifier or ITS Translate Id (GicV5)
UINT32 ItsId;
} CM_ARM_ITS_IDENTIFIER;
@ -873,4 +887,99 @@ typedef struct CmArmProcessorSpecificSubDataArchInfo {
UINT64 IdAA64Zfr0;
} CM_ARM_PROCESSOR_SPECIFIC_SUB_DATA_ARCH_INFO;
/** A structure that describes GIC interrupt Routing Service (IRS).
ID: EArmObjGicIrsInfo
*/
typedef struct CmArmGicIrsInfo {
/// An unique token used to identify this object
CM_OBJECT_TOKEN Token;
/// GIC version.
UINT32 GicVersion;
/// The GIC IRS ID
UINT32 GicIrsId;
/// Flags
UINT32 Flags;
/// Base address of the IRS config frame
UINT64 ConfigFrameBase;
/// Base address of the IRS SET_LPI frame
UINT64 SetLpiFrameBase;
/// Proximity domain that this IRS belongs to
UINT32 ProximityDomain;
/** Optional field: Reference Token to the ProximityDomain this object
belongs to. If this field is used, the following field is ignored:
CM_ARM_GIC_IRS_INFO.ProximityDomain
*/
CM_OBJECT_TOKEN ProximityDomainToken;
} CM_ARM_GIC_IRS_INFO;
/** A structure that describes the
GICv5 Interrupt Translation Service information for the Platform.
ID: EArmObjGicItsV5Info
*/
typedef struct CmArmGicItsV5Info {
/// An unique token used to identify this object
CM_OBJECT_TOKEN Token;
/// The GIC ITSv5 ID
UINT32 GicItsId;
/// Flags
UINT32 Flags;
/// Base address of the ITS config frame
UINT64 PhysicalBaseAddress;
/** The proximity domain to which the logical processor belongs.
This field is used to populate the GIC ITS affinity structure
in the SRAT table.
*/
UINT32 ProximityDomain;
/** Optional field: Reference Token to the ProximityDomain this object
belongs to. If this field is used, the following field is ignored:
CM_ARM_GIC_ITSV5_INFO.ProximityDomain
*/
CM_OBJECT_TOKEN ProximityDomainToken;
} CM_ARM_GIC_ITSV5_INFO;
/** A structure that describes the
frame information for GICv5 Interrupt Translation Service.
ID: EArmObjGicItsV5Info
*/
typedef struct CmArmGicItsV5TranslateFrameInfo {
/// Relevant ITSv5 Token
CM_OBJECT_TOKEN ItsV5Token;
/// The GIC ITSv5 translate frame ID
UINT32 ItsTranslateId;
/// Base address of the ITS translate frame
UINT64 ItsTranslateFrameBase;
} CM_ARM_GIC_ITSV5_TRANSLATE_FRAME_INFO;
/** A structure that describes the
Interrupt Wire Bridge (IWB) information.
ID: EArmObjGicIwbInfo
*/
typedef struct CmArmGicIwbInfo {
/// An unique token used to identify this object
CM_OBJECT_TOKEN Token;
/// The GIC IWB ID
UINT32 GicIwbId;
/// Linked ITSv5 ID Token
CM_OBJECT_TOKEN ItsV5Token;
/// Base address of the IWB config frame
UINT64 ConfigFrameBase;
/// Device ID used to signal any interrupt to the connected ITS
UINT32 DeviceId;
/// Base GSIV for this IWB
UINT32 BaseGsiv;
/// Number of wires handled by this IWB
UINT32 NumWires;
/// Reference token for the ID mapping array
CM_OBJECT_TOKEN IdMappingToken;
/// Unique identifier for this node.
UINT32 Identifier;
} CM_ARM_GIC_IWB_INFO;
#pragma pack()

View file

@ -63,3 +63,16 @@ ValidateSerialPortInfo (
IN CONST CM_ARCH_COMMON_SERIAL_PORT_INFO *SerialPortInfoTable,
IN UINT32 SerialPortCount
);
/** Validate the Serial Port Architecture Information.
@param [in] SerialPortInfoTable Table of CM_ARCH_COMMON_SERIAL_PORT_INFO.
@retval EFI_SUCCESS Success.
@retval EFI_INVALID_PARAMETER Invalid parameter.
**/
EFI_STATUS
EFIAPI
ArchValidateSerialPortInfo (
IN CONST CM_ARCH_COMMON_SERIAL_PORT_INFO *SerialPortInfo
);

View file

@ -19,6 +19,8 @@
[Sources]
IortGenerator.c
IortGenerator.h
IwbDeviceTable.c
IwbDeviceTableTemplate.asl
[Packages]
MdePkg/MdePkg.dec

View file

@ -1,11 +1,11 @@
/** @file
IORT Table Generator
Copyright (c) 2017 - 2022, Arm Limited. All rights reserved.
Copyright (c) 2017 - 2026, 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
- IO Remapping Table, Platform Design Document, Revision E.g, Mar 2026
(https://developer.arm.com/documentation/den0049/)
**/
@ -15,17 +15,25 @@
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/PrintLib.h>
#include <Protocol/AcpiTable.h>
// Module specific include files.
#include <AcpiTableGenerator.h>
#include <ConfigurationManagerObject.h>
#include <ConfigurationManagerHelper.h>
#include <Library/AcpiHelperLib.h>
#include <Library/TableHelperLib.h>
#include <Protocol/ConfigurationManagerProtocol.h>
#include "IortGenerator.h"
/** According to GICv5 spec, maximum wires per IWB instance is 65,336.
Therefore, it's reasonable to set the maximum number of IWB instance
as 16.
*/
#define MAX_IWB_COUNT (16)
/** ARM standard IORT Generator
Requirements:
@ -42,6 +50,7 @@ Requirements:
- EArmObjIdMappingArray
- EArmObjSmmuInterruptArray
- EArmObjMemoryRangeDescriptor
- EArmObjGicIwbInfo
*/
/** This macro expands to a function that retrieves the ITS
@ -143,6 +152,15 @@ GET_OBJECT_LIST (
CM_ARM_SMMU_INTERRUPT
);
/** This macro expands to a function that retrieves the
GIC IWB information from the Configuration Manager.
*/
GET_OBJECT_LIST (
EObjNameSpaceArm,
EArmObjGicIwbInfo,
CM_ARM_GIC_IWB_INFO
);
/** Returns the size of the ITS Group node.
@param [in] Node Pointer to ITS Group node.
@ -2164,6 +2182,225 @@ AddRmrNodes (
return EFI_SUCCESS;
}
/** Returns the size of the IWB node.
@param [in] Node Pointer to IWB node.
@retval Size of the IWB node.
**/
STATIC
UINT32
GetIwbNodeSize (
IN CONST CM_ARM_GIC_IWB_INFO *Node
)
{
ASSERT (Node != NULL);
/* Size of IWB 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_IWB_NODE) +
sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE) +
ALIGN_VALUE (IWB_DEV_PATH_SIZE, 4));
}
/** Returns the total size required for the Iwb 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 IWB node list.
@param [in] NodeCount Count of the IWB nodes.
@param [in, out] NodeIndexer Pointer to the next Node Indexer.
@retval Total size of the IWB nodes.
**/
STATIC
UINT64
GetSizeofIwbNodes (
IN CONST UINT32 NodeStartOffset,
IN CONST CM_ARM_GIC_IWB_INFO *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 += GetIwbNodeSize (NodeList);
(*NodeIndexer)++;
NodeList++;
}
return Size;
}
/** Update the IWB 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 IWB Group
Nodes.
@param [in] NodeList Pointer to an array of IWB Group Node
Objects.
@param [in] NodeCount Number of IWB 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
AddIwbNodes (
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_GIC_IWB_INFO *NodeList,
IN UINT32 NodeCount
)
{
EFI_STATUS Status;
EFI_ACPI_6_0_IO_REMAPPING_IWB_NODE *IwbNode;
EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *IdMapArray;
UINT64 NodeLength;
CHAR8 *ObjectName;
CHAR8 IwbDevPath[IWB_DEV_PATH_SIZE];
UINT32 Idx;
ASSERT (Iort != NULL);
IwbNode = (EFI_ACPI_6_0_IO_REMAPPING_IWB_NODE *)((UINT8 *)Iort +
NodesStartOffset);
/*
* Auto generated object name could be IWB0 to IWBF for
* the limit of AML_NAME_SEG_SIZE (4 chars).
*/
if (NodeCount > MAX_IWB_COUNT) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Too many number of IWB. Couldn't generate object name. Count: %d\n",
NodeCount
));
return EFI_INVALID_PARAMETER;
}
for (Idx = 0; Idx < NodeCount; Idx++) {
NodeLength = GetIwbNodeSize (NodeList);
if (NodeLength > MAX_UINT16) {
Status = EFI_INVALID_PARAMETER;
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: IWB Id Array Node length 0x%lx > MAX_UINT16."
" Status = %r\n",
NodeLength,
Status
));
return Status;
}
// Populate the node header
IwbNode->Node.Type = EFI_ACPI_IORT_TYPE_IWB;
IwbNode->Node.Length = (UINT16)NodeLength;
IwbNode->Node.Revision = 1;
IwbNode->Node.Identifier = NodeList->Identifier;
IwbNode->Node.NumIdMappings = 1;
IwbNode->Node.IdReference = NodeLength - sizeof (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE);
// IORT specific data
IwbNode->ConfigFrameBase = NodeList->ConfigFrameBase;
IwbNode->IwbIndex = NodeList->GicIwbId;
// Generate object name
AsciiSPrint (IwbDevPath, IWB_DEV_PATH_SIZE, "\\_SB_.IWB%x", IwbNode->IwbIndex);
// Copy the object name
ObjectName = (CHAR8 *)((UINT8 *)IwbNode +
sizeof (EFI_ACPI_6_0_IO_REMAPPING_IWB_NODE));
Status = AsciiStrCpyS (
ObjectName,
IWB_DEV_PATH_SIZE,
IwbDevPath
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to copy Object Name. Status = %r\n",
Status
));
return Status;
}
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 IWB node
IdMapArray = (EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE *)((UINT8 *)IwbNode +
IwbNode->Node.IdReference);
Status = AddIdMappingArray (
This,
CfgMgrProtocol,
IdMapArray,
1,
NodeList->IdMappingToken
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to add Id Mapping Array. Status = %r\n",
Status
));
return Status;
}
// Next IORT Group Node
IwbNode = (EFI_ACPI_6_0_IO_REMAPPING_IWB_NODE *)((UINT8 *)IwbNode +
IwbNode->Node.Length);
NodeList++;
} // IORT Group Node
return EFI_SUCCESS;
}
/** Validates that the IORT nodes Identifier are unique.
@param [in] NodeIndexer Pointer to the Node Indexer.
@ -2189,10 +2426,12 @@ ValidateNodeIdentifiers (
{
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: UID %d of Token %p matches with that of Token %p.\n",
"ERROR: IORT: UID %d of Token %p matches with that of Token %p. (%u/%u)\n",
NodeIndexer[IndexI].Identifier,
NodeIndexer[IndexI].Token,
NodeIndexer[IndexJ].Token
NodeIndexer[IndexJ].Token,
IndexI,
IndexJ
));
return EFI_INVALID_PARAMETER;
}
@ -2215,7 +2454,8 @@ ValidateNodeIdentifiers (
@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.
@param [out] Table Pointer to a list of generated ACPI table(s).
@param [out] TableCount Number of generated ACPI table(s).
@retval EFI_SUCCESS Table generated successfully.
@retval EFI_INVALID_PARAMETER A parameter is invalid.
@ -2227,11 +2467,12 @@ ValidateNodeIdentifiers (
STATIC
EFI_STATUS
EFIAPI
BuildIortTable (
BuildIortTableEx (
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
OUT EFI_ACPI_DESCRIPTION_HEADER ***Table,
OUT UINTN *CONST TableCount
)
{
EFI_STATUS Status;
@ -2247,6 +2488,7 @@ BuildIortTable (
UINT32 SmmuV3NodeCount;
UINT32 PmcgNodeCount;
UINT32 RmrNodeCount;
UINT32 IwbNodeCount;
UINT32 ItsGroupOffset;
UINT32 NamedComponentOffset;
@ -2255,6 +2497,7 @@ BuildIortTable (
UINT32 SmmuV3Offset;
UINT32 PmcgOffset;
UINT32 RmrOffset;
UINT32 IwbOffset;
CM_ARM_ITS_GROUP_NODE *ItsGroupNodeList;
CM_ARM_NAMED_COMPONENT_NODE *NamedComponentNodeList;
@ -2263,11 +2506,16 @@ BuildIortTable (
CM_ARM_SMMUV3_NODE *SmmuV3NodeList;
CM_ARM_PMCG_NODE *PmcgNodeList;
CM_ARM_RMR_NODE *RmrNodeList;
CM_ARM_GIC_IWB_INFO *IwbNodeList;
EFI_ACPI_6_0_IO_REMAPPING_TABLE *Iort;
IORT_NODE_INDEXER *NodeIndexer;
ACPI_IORT_GENERATOR *Generator;
EFI_ACPI_DESCRIPTION_HEADER **TableList;
UINT32 TableIdx;
UINT32 IwbIdx;
ASSERT (This != NULL);
ASSERT (AcpiTableInfo != NULL);
ASSERT (CfgMgrProtocol != NULL);
@ -2301,8 +2549,13 @@ BuildIortTable (
return EFI_INVALID_PARAMETER;
}
Generator = (ACPI_IORT_GENERATOR *)This;
*Table = NULL;
Generator = (ACPI_IORT_GENERATOR *)This;
*Table = NULL;
*TableCount = 0;
TableList = NULL;
Iort = NULL;
IwbNodeCount = 0;
// Get the ITS group node info
Status = GetEArmObjItsGroup (
@ -2320,6 +2573,18 @@ BuildIortTable (
goto error_handler;
}
if ((AcpiTableInfo->AcpiTableRevision >= EFI_ACPI_IO_REMAPPING_TABLE_REVISION_07) &&
(ItsGroupNodeCount > 1))
{
Status = EFI_INVALID_PARAMETER;
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Number of ITS Group Node Info must be 1. ItsGroupCount: %d\n",
ItsGroupNodeCount
));
goto error_handler;
}
// Add the ITS group node count
IortNodeCount = ItsGroupNodeCount;
@ -2441,6 +2706,29 @@ BuildIortTable (
IortNodeCount += RmrNodeCount;
}
if (AcpiTableInfo->AcpiTableRevision >=
EFI_ACPI_IO_REMAPPING_TABLE_REVISION_07)
{
// Get the IWB node info
Status = GetEArmObjGicIwbInfo (
CfgMgrProtocol,
CM_NULL_TOKEN,
&IwbNodeList,
&IwbNodeCount
);
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to get IWB Node Info. Status = %r\n",
Status
));
goto error_handler;
}
// Add the IWB node count
IortNodeCount += IwbNodeCount;
}
// Allocate Node Indexer array
NodeIndexer = (IORT_NODE_INDEXER *)AllocateZeroPool (
(sizeof (IORT_NODE_INDEXER) *
@ -2684,6 +2972,40 @@ BuildIortTable (
));
}
// IWB Nodes
if ((AcpiTableInfo->AcpiTableRevision >=
EFI_ACPI_IO_REMAPPING_TABLE_REVISION_07) &&
(IwbNodeCount > 0))
{
IwbOffset = (UINT32)TableSize;
// Size of IWB node list.
NodeSize = GetSizeofIwbNodes (
IwbOffset,
IwbNodeList,
IwbNodeCount,
&NodeIndexer
);
if (NodeSize > MAX_UINT32) {
Status = EFI_INVALID_PARAMETER;
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Invalid Size of IWB Nodes. Status = %r\n",
Status
));
goto error_handler;
}
TableSize += NodeSize;
DEBUG ((
DEBUG_INFO,
" IwbNodeCount = %d\n" \
" IwbOffset = %d\n",
IwbNodeCount,
IwbOffset
));
}
DEBUG ((
DEBUG_INFO,
"INFO: IORT:\n" \
@ -2720,9 +3042,24 @@ BuildIortTable (
}
}
// Allocate the Buffer for IORT table
*Table = (EFI_ACPI_DESCRIPTION_HEADER *)AllocateZeroPool (TableSize);
if (*Table == NULL) {
// Allocate the Buffer for IORT and IWB SSDT tables.
TableList = (EFI_ACPI_DESCRIPTION_HEADER **)
AllocateZeroPool (
(sizeof (EFI_ACPI_DESCRIPTION_HEADER *) * (1 + IwbNodeCount))
);
if (TableList == NULL) {
Status = EFI_OUT_OF_RESOURCES;
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to allocate memory for TableList.\n"
));
goto error_handler;
}
// The IORT ACPI table is at index 0 in the TableList[]
TableIdx = 0;
TableList[TableIdx] = (EFI_ACPI_DESCRIPTION_HEADER *)AllocateZeroPool (TableSize);
if (TableList[TableIdx] == NULL) {
Status = EFI_OUT_OF_RESOURCES;
DEBUG ((
DEBUG_ERROR,
@ -2734,7 +3071,7 @@ BuildIortTable (
goto error_handler;
}
Iort = (EFI_ACPI_6_0_IO_REMAPPING_TABLE *)*Table;
Iort = (EFI_ACPI_6_0_IO_REMAPPING_TABLE *)TableList[TableIdx];
DEBUG ((
DEBUG_INFO,
@ -2907,6 +3244,49 @@ BuildIortTable (
}
}
if ((AcpiTableInfo->AcpiTableRevision >=
EFI_ACPI_IO_REMAPPING_TABLE_REVISION_07) &&
(IwbNodeCount > 0))
{
Status = AddIwbNodes (
This,
CfgMgrProtocol,
AcpiTableInfo,
Iort,
IwbOffset,
IwbNodeList,
IwbNodeCount
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to add IWB Node. Status = %r\n",
Status
));
goto error_handler;
}
for (IwbIdx = 0; IwbIdx < IwbNodeCount; IwbIdx++) {
// The Iwb AML table list starts at index 1.
TableIdx++;
Status = BuildIwbDeviceTable (
&IwbNodeList[IwbIdx],
&TableList[TableIdx]
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IORT: Failed to add IWB SSDT table. Status = %r\n",
Status
));
goto error_handler;
}
} // for
}
*Table = TableList;
*TableCount = 1 + IwbNodeCount;
return EFI_SUCCESS;
error_handler:
@ -2915,9 +3295,17 @@ error_handler:
Generator->NodeIndexer = NULL;
}
if (*Table != NULL) {
FreePool (*Table);
*Table = NULL;
if (TableList != NULL) {
while (TableIdx > 1) {
TableIdx--;
FreeIwbDeviceTable (TableList[TableIdx]);
}
if (Iort != NULL) {
FreePool (TableList[0]);
}
FreePool (TableList);
}
return Status;
@ -2929,21 +3317,26 @@ error_handler:
@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.
@param [in, out] Table Pointer to an array of pointers
to ACPI Table(s).
@param [in] TableCount Number of ACPI table(s).
@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
FreeIortTableResourcesEx (
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,
IN CONST UINTN TableCount
)
{
ACPI_IORT_GENERATOR *Generator;
ACPI_IORT_GENERATOR *Generator;
EFI_ACPI_DESCRIPTION_HEADER **TableList;
UINTN Idx;
ASSERT (This != NULL);
ASSERT (AcpiTableInfo != NULL);
@ -2965,6 +3358,16 @@ FreeIortTableResources (
return EFI_INVALID_PARAMETER;
}
TableList = *Table;
for (Idx = 1; Idx < TableCount; Idx++) {
FreeIwbDeviceTable (TableList[Idx]);
}
if (TableList[0] != NULL) {
FreePool (TableList[0]);
}
FreePool (*Table);
*Table = NULL;
return EFI_SUCCESS;
@ -2985,9 +3388,9 @@ ACPI_IORT_GENERATOR IortGenerator = {
// Generator Description
L"ACPI.STD.IORT.GENERATOR",
// ACPI Table Signature
EFI_ACPI_6_4_IO_REMAPPING_TABLE_SIGNATURE,
EFI_ACPI_6_7_IO_REMAPPING_TABLE_SIGNATURE,
// ACPI Table Revision supported by this Generator
EFI_ACPI_IO_REMAPPING_TABLE_REVISION_06,
EFI_ACPI_IO_REMAPPING_TABLE_REVISION_07,
// Minimum supported ACPI Table Revision
EFI_ACPI_IO_REMAPPING_TABLE_REVISION_00,
// Creator ID
@ -2995,14 +3398,13 @@ ACPI_IORT_GENERATOR IortGenerator = {
// 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
// Free Resource function
NULL,
// Extended build function not needed
BuildIortTableEx,
// Extended Free Resource function
FreeIortTableResourcesEx,
},
// IORT Generator private data

View file

@ -12,6 +12,9 @@
#pragma once
#define IWB_DEV_NAME_SIZE (AML_NAME_SEG_SIZE + 1)
#define IWB_DEV_PATH_SIZE (IWB_DEV_NAME_SIZE + 6) /* "\\_SB_." */
#pragma pack(1)
/** A structure that describes the Node indexer
@ -41,4 +44,36 @@ typedef struct AcpiIortGenerator {
IORT_NODE_INDEXER *NodeIndexer;
} ACPI_IORT_GENERATOR;
/** Build a SSDT table describing the IWB device.
The table created by this function must be freed by FreeSimpleIwbDeviceTable.
@param [in] IwbInfo IWB device info to describe in the SSDT table.
@param [out] Table If success, pointer to the created SSDT table.
@retval EFI_SUCCESS Table generated successfully.
@retval EFI_INVALID_PARAMETER A parameter is invalid.
@retval EFI_NOT_FOUND Could not find information.
@retval EFI_OUT_OF_RESOURCES Could not allocate memory.
**/
EFI_STATUS
EFIAPI
BuildIwbDeviceTable (
IN CONST CM_ARM_GIC_IWB_INFO *IwbInfo,
OUT EFI_ACPI_DESCRIPTION_HEADER **Table
);
/** Free an Iwb device table previously created by
the BuildIwbDeviceTable function.
@param [in] Table Pointer to a Iwb Device table allocated by
the BuildIwbDeviceTable function.
**/
VOID
EFIAPI
FreeIwbDeviceTable (
IN EFI_ACPI_DESCRIPTION_HEADER *Table
);
#pragma pack()

View file

@ -0,0 +1,333 @@
/** @file
Generate IWB SSDT table.
Copyright (c) 2026, Arm Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Reference(s):
- IO Remapping Table, Platform Design Document, Revision E.g, Mar 2026
(https://developer.arm.com/documentation/den0049/)
**/
#include <Library/AcpiLib.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/PcdLib.h>
#include <Protocol/AcpiTable.h>
// Module specific include files.
#include <ConfigurationManagerObject.h>
#include <Library/AcpiHelperLib.h>
#include <Library/AmlLib/AmlLib.h>
#include "IortGenerator.h"
/** According to GICv5 specification chapther 10.4.1 IWB_CONFIG_FRAME,
IWB_CONFIG_FRAME's block size is 0x10000 bytes.
*/
#define IWB_FRAME_BLOCK_SIZE 0x10000
/** C array containing the compiled AML template.
This symbol is defined in the auto generated C file
containing the AML bytecode array.
*/
extern CHAR8 iwbdevicetabletemplate_aml_code[];
/** Fixup the IWB device UID (_UID).
@param [in] RootNodeHandle Pointer to the root of an AML tree.
@param [in] Uid UID for the IWB device.
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_INVALID_PARAMETER Invalid parameter.
@retval EFI_NOT_FOUND Could not find information.
@retval EFI_OUT_OF_RESOURCES Out of resources.
**/
STATIC
EFI_STATUS
EFIAPI
FixupIwbDeviceUid (
IN AML_ROOT_NODE_HANDLE RootNodeHandle,
IN CONST UINT64 Uid
)
{
EFI_STATUS Status;
AML_OBJECT_NODE_HANDLE NameOpIdNode;
// Get the _UID NameOp object defined by the "Name ()" statement,
// and update its value.
Status = AmlFindNode (
RootNodeHandle,
"\\_SB_.IWB0._UID",
&NameOpIdNode
);
if (EFI_ERROR (Status)) {
return Status;
}
return AmlNameOpUpdateInteger (NameOpIdNode, (UINT64)Uid);
}
/** Fixup the Iwb device name.
@param [in] RootNodeHandle Pointer to the root of an AML tree.
@param [in] Name The Name to give to the Device.
Must be a NULL-terminated ASL NameString
e.g.: "DEV0", "DV15.DEV0", etc.
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_INVALID_PARAMETER Invalid parameter.
@retval EFI_NOT_FOUND Could not find information.
@retval EFI_OUT_OF_RESOURCES Out of resources.
**/
STATIC
EFI_STATUS
EFIAPI
FixupIwbDeviceName (
IN AML_ROOT_NODE_HANDLE RootNodeHandle,
IN CONST CHAR8 *Name
)
{
EFI_STATUS Status;
AML_OBJECT_NODE_HANDLE DeviceNode;
// Get the COM0 variable defined by the "Device ()" statement.
Status = AmlFindNode (RootNodeHandle, "\\_SB_.IWB0", &DeviceNode);
if (EFI_ERROR (Status)) {
return Status;
}
// Update the Device's name.
return AmlDeviceOpUpdateName (DeviceNode, Name);
}
/** Fixup the Iwb device _CRS values (BaseAddress, ...).
@param [in] RootNodeHandle Pointer to the root of an AML tree.
@param [in] IwbInfo Pointer to a IWB device Information
structure.
Get the device size Information from there.
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_INVALID_PARAMETER Invalid parameter.
@retval EFI_NOT_FOUND Could not find information.
@retval EFI_OUT_OF_RESOURCES Out of resources.
**/
STATIC
EFI_STATUS
EFIAPI
FixupIwbDeviceCrs (
IN AML_ROOT_NODE_HANDLE RootNodeHandle,
IN CONST CM_ARM_GIC_IWB_INFO *IwbInfo
)
{
EFI_STATUS Status;
AML_OBJECT_NODE_HANDLE NameOpCrsNode;
AML_DATA_NODE_HANDLE QWordRdNode;
// Get the "_CRS" object defined by the "Name ()" statement.
Status = AmlFindNode (
RootNodeHandle,
"\\_SB_.IWB0._CRS",
&NameOpCrsNode
);
if (EFI_ERROR (Status)) {
return Status;
}
// Get the first Rd node in the "_CRS" object.
Status = AmlNameOpGetFirstRdNode (NameOpCrsNode, &QWordRdNode);
if (EFI_ERROR (Status)) {
return Status;
}
if (QWordRdNode == NULL) {
return EFI_INVALID_PARAMETER;
}
// Update the IWB device's base address and length.
Status = AmlUpdateRdQWord (
QWordRdNode,
IwbInfo->ConfigFrameBase,
IWB_FRAME_BLOCK_SIZE
);
if (EFI_ERROR (Status)) {
return Status;
}
return Status;
}
/** Fixup the IWB Device in the AML tree.
For each template value:
- find the node to update;
- update the value.
@param [in] RootNodeHandle Pointer to the root of the AML tree.
@param [in] IwbInfo Pointer to a IWB device Information
structure.
@param [in] Name The Name to give to the Device.
Must be a NULL-terminated ASL NameString
e.g.: "DEV0", "DV15.DEV0", etc.
@param [in] Uid UID for the IWB device.
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_INVALID_PARAMETER Invalid parameter.
@retval EFI_NOT_FOUND Could not find information.
@retval EFI_OUT_OF_RESOURCES Out of resources.
**/
STATIC
EFI_STATUS
EFIAPI
FixupIwbDeviceInfo (
IN AML_ROOT_NODE_HANDLE RootNodeHandle,
IN CONST CM_ARM_GIC_IWB_INFO *IwbInfo,
IN CONST CHAR8 *Name,
IN CONST UINT64 Uid
)
{
EFI_STATUS Status;
ASSERT (RootNodeHandle != NULL);
ASSERT (IwbInfo != NULL);
ASSERT (Name != NULL);
// Fixup the _UID value.
Status = FixupIwbDeviceUid (RootNodeHandle, Uid);
if (EFI_ERROR (Status)) {
return Status;
}
// Fixup the _CRS values.
Status = FixupIwbDeviceCrs (RootNodeHandle, IwbInfo);
if (EFI_ERROR (Status)) {
return Status;
}
// Fixup the Iwb device name.
// This MUST be done at the end, otherwise AML paths won't be valid anymore.
return FixupIwbDeviceName (RootNodeHandle, Name);
}
/** Build a SSDT table describing the IWB device.
The table created by this function must be freed by FreeSimpleIwbDeviceTable.
@param [in] IwbInfo IWB device info to describe in the SSDT table.
@param [out] Table If success, pointer to the created SSDT table.
@retval EFI_SUCCESS Table generated successfully.
@retval EFI_INVALID_PARAMETER A parameter is invalid.
@retval EFI_NOT_FOUND Could not find information.
@retval EFI_OUT_OF_RESOURCES Could not allocate memory.
**/
EFI_STATUS
EFIAPI
BuildIwbDeviceTable (
IN CONST CM_ARM_GIC_IWB_INFO *IwbInfo,
OUT EFI_ACPI_DESCRIPTION_HEADER **Table
)
{
EFI_STATUS Status;
EFI_STATUS Status1;
AML_ROOT_NODE_HANDLE RootNodeHandle;
CHAR8 IwbDevName[IWB_DEV_NAME_SIZE];
ASSERT (IwbInfo != NULL);
ASSERT (Table != NULL);
IwbDevName[0] = 'I';
IwbDevName[1] = 'W';
IwbDevName[2] = 'B';
IwbDevName[3] = AsciiFromHex (IwbInfo->GicIwbId);
IwbDevName[4] = '\0';
// Parse the IWB Device Table Template.
Status = AmlParseDefinitionBlock (
(EFI_ACPI_DESCRIPTION_HEADER *)iwbdevicetabletemplate_aml_code,
&RootNodeHandle
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IWB-DEVICE-FIXUP:"
" Failed to parse SSDT IWB device Template. Status = %r\n",
Status
));
return Status;
}
// Fixup the template values.
Status = FixupIwbDeviceInfo (
RootNodeHandle,
IwbInfo,
IwbDevName,
IwbInfo->GicIwbId
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IWB-DEVICE-FIXUP: Failed to fixup SSDT IWB Device Table."
" Status = %r\n",
Status
));
goto ExitHandler;
}
// Serialize the tree.
Status = AmlSerializeDefinitionBlock (
RootNodeHandle,
Table
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IWB-DEVICE-FIXUP: Failed to Serialize SSDT Table Data."
" Status = %r\n",
Status
));
}
ExitHandler:
// Cleanup
if (RootNodeHandle != NULL) {
Status1 = AmlDeleteTree (RootNodeHandle);
if (EFI_ERROR (Status1)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: IWB-DEVICE-FIXUP: Failed to cleanup AML tree."
" Status = %r\n",
Status1
));
// If Status was success but we failed to delete the AML Tree
// return Status1 else return the original error code, i.e. Status.
if (!EFI_ERROR (Status)) {
return Status1;
}
}
}
return Status;
}
/** Free an Iwb device table previously created by
the BuildIwbDeviceTable function.
@param [in] Table Pointer to a Iwb Device table allocated by
the BuildIwbDeviceTable function.
**/
VOID
EFIAPI
FreeIwbDeviceTable (
IN EFI_ACPI_DESCRIPTION_HEADER *Table
)
{
ASSERT (Table != NULL);
FreePool (Table);
}

View file

@ -0,0 +1,38 @@
/** @file
IWB Device Table Template
Copyright (c) 2026, Arm Ltd. All rights reserved.<BR>
All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Reference(s)
- IO Remapping Table, Platform Design Document, Revision E.g Mar 2026
@par Glossary:
- {template} - Data fixed up using AML Fixup APIs.
**/
DefinitionBlock("IwbDeviceTableTemplate.aml", "SSDT", 2, "ARMLTD", "IWB", 1) {
Scope(_SB) {
Device (IWB0) { // {template}
Name (_HID, "ARMH0003")
Name (_UID, 0) // {template}
Name (_CRS, ResourceTemplate () {
QWordMemory (
,
,
MinFixed,
MaxFixed,
NonCacheable,
ReadWrite,
0x0,
0x000000002F000000, // IWB config frame base // {template}
0x000000002F00FFFF, // IWB config frame last byte // {template}
0, // Translation Offset
0x0000000000010000, // IWB config frame length
) // QWordMemory
}) // Name
} // Device
} // Scope(_SB)
}

View file

@ -1,11 +1,11 @@
/** @file
MADT Table Generator
Copyright (c) 2017 - 2023, Arm Limited. All rights reserved.
Copyright (c) 2017 - 2026, Arm Limited. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Reference(s):
- ACPI 6.5 Specification - Aug 29, 2022
- ACPI 6.7 Specification.
**/
@ -81,19 +81,157 @@ GET_OBJECT_LIST (
CM_ARM_GIC_ITS_INFO
);
/** This macro expands to a function that retrieves the GIC
IRS Information from the Configuration Manager.
*/
GET_OBJECT_LIST (
EObjNameSpaceArm,
EArmObjGicIrsInfo,
CM_ARM_GIC_IRS_INFO
);
/** This macro expands to a function that retrieves the GIC
Interrupt Translation Service v5 Information from the
Configuration Manager.
*/
GET_OBJECT_LIST (
EObjNameSpaceArm,
EArmObjGicItsV5Info,
CM_ARM_GIC_ITSV5_INFO
);
/** This macro expands to a function that retrieves the GIC
ITS v5 Translate Frame Information from the
Configuration Manager.
*/
GET_OBJECT_LIST (
EObjNameSpaceArm,
EArmObjGicItsV5TranslateFrameInfo,
CM_ARM_GIC_ITSV5_TRANSLATE_FRAME_INFO
);
/** Add the GIC Interrupt Routing Service Information
to the MADT Table.
@param [in] GicIrs GIC IRS structure.
@param [in] GicIrsInfo GIC IRS Info.
**/
STATIC
VOID
AddGICInterruptRoutingService (
IN EFI_ACPI_6_7_GIC_IRS_STRUCTURE *CONST GicIrs,
IN CONST CM_ARM_GIC_IRS_INFO *CONST GicIrsInfo
)
{
ASSERT (GicIrs != NULL);
ASSERT (GicIrsInfo != NULL);
// UINT8 Type
GicIrs->Type = EFI_ACPI_6_7_GIC_IRS;
// UINT8 Length
GicIrs->Length = sizeof (EFI_ACPI_6_7_GIC_IRS_STRUCTURE);
// UINT8 GicVersion
GicIrs->GicVersion = EFI_ACPI_6_7_GIC_V5;
// UINT8 Reserved
GicIrs->Reserved = EFI_ACPI_RESERVED_BYTE;
// UINT32 IrsId
GicIrs->IrsId = GicIrsInfo->GicIrsId;
// UINT32 Flags
GicIrs->Flags = GicIrsInfo->Flags;
// UINT32 Reserved2
GicIrs->Reserved2 = EFI_ACPI_RESERVED_DWORD;
// UINT32 IrsConfigFrameBase
GicIrs->IrsConfigFrameBase = GicIrsInfo->ConfigFrameBase;
// UINT32 IrsSetLpiFrameBase
GicIrs->IrsSetLpiFrameBase = GicIrsInfo->SetLpiFrameBase;
}
/** Add the GICv5 Interrupt Translation Service Information
to the MADT Table.
@param [in] GicItsV5 GIC ITSv5 structure list.
@param [in] GicItsV5Info GIC ITSv5 Info.
**/
STATIC
VOID
AddGICInterruptTranslationServiceV5 (
IN EFI_ACPI_6_7_GIC_ITSV5_STRUCTURE *CONST GicItsV5,
IN CONST CM_ARM_GIC_ITSV5_INFO *CONST GicItsV5Info
)
{
ASSERT (GicItsV5 != NULL);
ASSERT (GicItsV5Info != NULL);
// UINT8 Type
GicItsV5->Type = EFI_ACPI_6_7_GIC_ITSV5;
// UINT8 Length
GicItsV5->Length = sizeof (EFI_ACPI_6_7_GIC_ITSV5_STRUCTURE);
// UINT8 Flags
GicItsV5->Flags = GicItsV5Info->Flags;
// UINT8 Reserved
GicItsV5->Reserved = EFI_ACPI_RESERVED_BYTE;
// UINT32 GicItsId
GicItsV5->GicItsId = GicItsV5Info->GicItsId;
// UINT64 PhysicalBaseAddress
GicItsV5->PhysicalBaseAddress = GicItsV5Info->PhysicalBaseAddress;
}
/** Add the GICv5 Interrupt Translation Service Translate Frame Information
to the MADT Table.
@param [in] GicItsV5TranslateFrame GIC ITSv5 Translate frame
structure.
@param [in] GicItsV5TransFrameInfo GIC ITSv5 Translate frame Info.
@param [in] GicItsV5Info GIC ITSv5 Info.
**/
STATIC
VOID
AddGICInterruptTranslationServiceV5TranslateFrame (
IN EFI_ACPI_6_7_GIC_ITSV5_TRANSLATE_FRAME_STRUCTURE *CONST GicItsV5TranslateFrame,
IN CONST CM_ARM_GIC_ITSV5_TRANSLATE_FRAME_INFO *CONST GicItsV5TransFrameInfo,
IN CONST CM_ARM_GIC_ITSV5_INFO *CONST GicItsV5Info
)
{
ASSERT (GicItsV5TranslateFrame != NULL);
ASSERT (GicItsV5TransFrameInfo != NULL);
// UINT8 Type
GicItsV5TranslateFrame->Type = EFI_ACPI_6_7_GIC_ITSV5_TRANSLATE_FRAME;
// UINT8 Length
GicItsV5TranslateFrame->Length = sizeof (EFI_ACPI_6_7_GIC_ITSV5_TRANSLATE_FRAME_STRUCTURE);
// UINT16 Reserved
GicItsV5TranslateFrame->Reserved = EFI_ACPI_RESERVED_WORD;
// UINT32 LinkedGicItsId
GicItsV5TranslateFrame->LinkedGicItsId = GicItsV5Info->GicItsId;
// UINT32 ItsTranslateId
GicItsV5TranslateFrame->ItsTranslateId = GicItsV5TransFrameInfo->ItsTranslateId;
// UINT32 Reserved2
GicItsV5TranslateFrame->Reserved2 = EFI_ACPI_RESERVED_DWORD;
// UINT32 ItsTranslateFrameBase
GicItsV5TranslateFrame->ItsTranslateFrameBase = GicItsV5TransFrameInfo->ItsTranslateFrameBase;
}
/** This function updates the GIC CPU Interface Information in the
EFI_ACPI_6_5_GIC_STRUCTURE structure.
EFI_ACPI_6_7_GIC_STRUCTURE structure.
@param [in] Gicc Pointer to GIC CPU Interface structure.
@param [in] GicCInfo Pointer to the GIC CPU Interface Information.
@param [in] GicIrsInfo Pointer to the GIC IRS structure.
@param [in] MadtRev MADT table revision.
@param [in] GicRPresent TRUE if MADT also contains any GICR structures.
**/
STATIC
VOID
AddGICC (
IN EFI_ACPI_6_5_GIC_STRUCTURE *CONST Gicc,
IN EFI_ACPI_6_7_GIC_STRUCTURE *CONST Gicc,
IN CONST CM_ARM_GICC_INFO *CONST GicCInfo,
IN CONST CM_ARM_GIC_IRS_INFO *CONST GicIrsInfo,
IN CONST UINT8 MadtRev,
IN CONST BOOLEAN GicRPresent
)
@ -102,9 +240,9 @@ AddGICC (
ASSERT (GicCInfo != NULL);
// UINT8 Type
Gicc->Type = EFI_ACPI_6_5_GIC;
Gicc->Type = EFI_ACPI_6_7_GIC;
// UINT8 Length
Gicc->Length = sizeof (EFI_ACPI_6_5_GIC_STRUCTURE);
Gicc->Length = sizeof (EFI_ACPI_6_7_GIC_STRUCTURE);
// UINT16 Reserved
Gicc->Reserved = EFI_ACPI_RESERVED_WORD;
@ -159,6 +297,13 @@ AddGICC (
if (MadtRev > EFI_ACPI_6_4_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION) {
Gicc->TrbeInterrupt = GicCInfo->TrbeInterrupt;
}
if (MadtRev >= EFI_ACPI_6_6_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION) {
if (GicIrsInfo != NULL) {
Gicc->IrsId = GicIrsInfo->GicIrsId;
Gicc->IAffId = GicCInfo->IAffId;
}
}
}
/**
@ -214,6 +359,8 @@ IsAcpiUidEqual (
@param [in] Gicc Pointer to GIC CPU Interface structure list.
@param [in] GicCInfo Pointer to the GIC CPU Information list.
@param [in] GicCCount Count of GIC CPU Interfaces.
@param [in] GicIrsInfo Pointer to the GIC IRS list.
@param [in] GicIrsCount Count of GIC IRS.
@param [in] MadtRev MADT table revision.
@param [in] GicRPresent TRUE if MADT also contains any GICR
structures.
@ -227,14 +374,18 @@ IsAcpiUidEqual (
STATIC
EFI_STATUS
AddGICCList (
IN EFI_ACPI_6_5_GIC_STRUCTURE *Gicc,
IN EFI_ACPI_6_7_GIC_STRUCTURE *Gicc,
IN CONST CM_ARM_GICC_INFO *GicCInfo,
IN UINT32 GicCCount,
IN CONST CM_ARM_GIC_IRS_INFO *GicIrsInfo,
IN UINT32 GicIrsCount,
IN CONST UINT8 MadtRev,
IN CONST BOOLEAN GicRPresent
)
{
BOOLEAN IsAcpiProcUidDuplicated;
BOOLEAN IsAcpiProcUidDuplicated;
CONST CM_ARM_GIC_IRS_INFO *IrsInfo;
UINTN Idx;
ASSERT (Gicc != NULL);
ASSERT (GicCInfo != NULL);
@ -252,7 +403,22 @@ AddGICCList (
}
while (GicCCount-- != 0) {
AddGICC (Gicc++, GicCInfo++, MadtRev, GicRPresent);
IrsInfo = NULL;
if ((GicIrsInfo != NULL) && (GicCInfo->IrsToken != CM_NULL_TOKEN)) {
for (Idx = 0; Idx < GicIrsCount; Idx++) {
if (GicCInfo->IrsToken == GicIrsInfo[Idx].Token) {
IrsInfo = &GicIrsInfo[Idx];
break;
}
}
if (IrsInfo == NULL) {
return EFI_INVALID_PARAMETER;
}
}
AddGICC (Gicc++, GicCInfo++, IrsInfo, MadtRev, GicRPresent);
}
return EFI_SUCCESS;
@ -434,6 +600,106 @@ AddGICItsList (
}
}
/** Add the GIC Interrupt Routing Service Information
to the MADT Table.
@param [in] GicIrs Pointer to GIC IRS structure list.
@param [in] GicIrsInfo Pointer to the GIC IRS list.
@param [in] GicIrsCount Count of GIC IRS.
**/
STATIC
VOID
AddGICIrsList (
IN EFI_ACPI_6_7_GIC_IRS_STRUCTURE *GicIrs,
IN CONST CM_ARM_GIC_IRS_INFO *GicIrsInfo,
IN UINT32 GicIrsCount
)
{
ASSERT (GicIrs != NULL);
ASSERT (GicIrsInfo != NULL);
while (GicIrsCount-- != 0) {
AddGICInterruptRoutingService (GicIrs++, GicIrsInfo++);
}
}
/** Add the GICv5 Interrupt Translation Service Information
to the MADT Table.
@param [in] GicItsV5 Pointer to GIC ITSv5 structure list.
@param [in] GicItsV5Info Pointer to the GIC ITSv5 list.
@param [in] GicItsV5Count Count of GIC ITSv5.
**/
STATIC
VOID
AddGICItsV5List (
IN EFI_ACPI_6_7_GIC_ITSV5_STRUCTURE *GicItsV5,
IN CONST CM_ARM_GIC_ITSV5_INFO *GicItsV5Info,
IN UINT32 GicItsV5Count
)
{
ASSERT (GicItsV5 != NULL);
ASSERT (GicItsV5Info != NULL);
while (GicItsV5Count-- != 0) {
AddGICInterruptTranslationServiceV5 (GicItsV5++, GicItsV5Info++);
}
}
/** Add the GICv5 Interrupt Translation Service Translate Frame Information
to the MADT Table.
@param [in] GicItsV5TranslateFrame Pointer to GIC ITSv5 Translate frame
structure list.
@param [in] GicItsV5TransFrameInfo Pointer to the GIC ITSv5
Translate frame list.
@param [in] GicItsV5TransFrameCount Count of GIC ITSv5.Translate frame.
@param [in] GicItsV5Info Pointer to the GIC ITSv5 list.
@param [in] GicItsV5Count Count of GIC ITSv5.
**/
STATIC
EFI_STATUS
AddGICItsV5TranslateFrameList (
IN EFI_ACPI_6_7_GIC_ITSV5_TRANSLATE_FRAME_STRUCTURE *GicItsV5TranslateFrame,
IN CONST CM_ARM_GIC_ITSV5_TRANSLATE_FRAME_INFO *GicItsV5TransFrameInfo,
IN UINT32 GicItsV5TransFrameCount,
IN CONST CM_ARM_GIC_ITSV5_INFO *GicItsV5Info,
IN UINT32 GicItsV5Count
)
{
CONST CM_ARM_GIC_ITSV5_INFO *ItsInfo;
UINTN Idx;
ASSERT (GicItsV5TranslateFrame != NULL);
ASSERT (GicItsV5TransFrameInfo != NULL);
ASSERT (GicItsV5Info != NULL);
while (GicItsV5TransFrameCount-- != 0) {
ItsInfo = NULL;
for (Idx = 0; Idx < GicItsV5Count; Idx++) {
if (GicItsV5TransFrameInfo->ItsV5Token == GicItsV5Info[Idx].Token) {
ItsInfo = &GicItsV5Info[Idx];
break;
}
}
if (ItsInfo == NULL) {
return EFI_INVALID_PARAMETER;
}
AddGICInterruptTranslationServiceV5TranslateFrame (
GicItsV5TranslateFrame++,
GicItsV5TransFrameInfo++,
ItsInfo
);
}
return EFI_SUCCESS;
}
/** Construct the MADT ACPI table.
This function invokes the Configuration Manager protocol interface
@ -466,25 +732,34 @@ BuildMadtTable (
OUT EFI_ACPI_DESCRIPTION_HEADER **CONST Table
)
{
EFI_STATUS Status;
UINT32 TableSize;
UINT32 GicCCount;
UINT32 GicDCount;
UINT32 GicMSICount;
UINT32 GicRedistCount;
UINT32 GicItsCount;
CM_ARM_GICC_INFO *GicCInfo;
CM_ARM_GICD_INFO *GicDInfo;
CM_ARM_GIC_MSI_FRAME_INFO *GicMSIInfo;
CM_ARM_GIC_REDIST_INFO *GicRedistInfo;
CM_ARM_GIC_ITS_INFO *GicItsInfo;
UINT32 GicCOffset;
UINT32 GicDOffset;
UINT32 GicMSIOffset;
UINT32 GicRedistOffset;
UINT32 GicItsOffset;
EFI_STATUS Status;
UINT32 TableSize;
UINT32 GicCCount;
UINT32 GicDCount;
UINT32 GicMSICount;
UINT32 GicRedistCount;
UINT32 GicItsCount;
UINT32 GicIrsCount;
UINT32 GicItsV5Count;
UINT32 GicItsV5TransFrameCount;
CM_ARM_GICC_INFO *GicCInfo;
CM_ARM_GICD_INFO *GicDInfo;
CM_ARM_GIC_MSI_FRAME_INFO *GicMSIInfo;
CM_ARM_GIC_REDIST_INFO *GicRedistInfo;
CM_ARM_GIC_ITS_INFO *GicItsInfo;
CM_ARM_GIC_IRS_INFO *GicIrsInfo;
CM_ARM_GIC_ITSV5_INFO *GicItsV5Info;
CM_ARM_GIC_ITSV5_TRANSLATE_FRAME_INFO *GicItsV5TransFrameInfo;
UINT32 GicCOffset;
UINT32 GicDOffset;
UINT32 GicMSIOffset;
UINT32 GicRedistOffset;
UINT32 GicItsOffset;
UINT32 GicIrsOffset;
UINT32 GicItsV5Offset;
UINT32 GicItsV5TranslateFrameOffset;
EFI_ACPI_6_5_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *Madt;
EFI_ACPI_6_7_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *Madt;
ASSERT (This != NULL);
ASSERT (AcpiTableInfo != NULL);
@ -540,7 +815,10 @@ BuildMadtTable (
&GicDInfo,
&GicDCount
);
if (EFI_ERROR (Status)) {
if (EFI_ERROR (Status) &&
((AcpiTableInfo->AcpiTableRevision < EFI_ACPI_6_7_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION) ||
(Status != EFI_NOT_FOUND)))
{
DEBUG ((
DEBUG_ERROR,
"ERROR: MADT: Failed to get GICD Info. Status = %r\n",
@ -549,16 +827,6 @@ BuildMadtTable (
goto error_handler;
}
if (GicDCount == 0) {
DEBUG ((
DEBUG_ERROR,
"ERROR: MADT: GIC Distributor information not provided.\n"
));
ASSERT (GicDCount != 0);
Status = EFI_INVALID_PARAMETER;
goto error_handler;
}
if (GicDCount > 1) {
DEBUG ((
DEBUG_ERROR,
@ -616,10 +884,77 @@ BuildMadtTable (
goto error_handler;
}
TableSize = sizeof (EFI_ACPI_6_5_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER);
Status = GetEArmObjGicIrsInfo (
CfgMgrProtocol,
CM_NULL_TOKEN,
&GicIrsInfo,
&GicIrsCount
);
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: MADT: Failed to get GIC IRS Info. Status = %r\n",
Status
));
goto error_handler;
}
Status = GetEArmObjGicItsV5Info (
CfgMgrProtocol,
CM_NULL_TOKEN,
&GicItsV5Info,
&GicItsV5Count
);
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: MADT: Failed to get GIC ITSv5 Info. Status = %r\n",
Status
));
goto error_handler;
}
Status = GetEArmObjGicItsV5TranslateFrameInfo (
CfgMgrProtocol,
CM_NULL_TOKEN,
&GicItsV5TransFrameInfo,
&GicItsV5TransFrameCount
);
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: MADT: Failed to get GIC ITSv5 Info. Status = %r\n",
Status
));
goto error_handler;
}
if (((GicIrsCount == 0) && (GicDCount == 0)) ||
((GicIrsCount > 0) && (GicDCount > 0)))
{
Status = EFI_INVALID_PARAMETER;
DEBUG ((
DEBUG_ERROR,
"ERROR: MADT: No GicIrs and GicD Info or have both. Status = %r\n",
Status
));
goto error_handler;
}
if ((GicItsV5Count != 0) && (GicItsV5Count > GicItsV5TransFrameCount)) {
Status = EFI_INVALID_PARAMETER;
DEBUG ((
DEBUG_ERROR,
"ERROR: MADT: Each GicItsV5 should have at least 1 Translate Frame. Status = %r\n",
Status
));
goto error_handler;
}
TableSize = sizeof (EFI_ACPI_6_7_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER);
GicCOffset = TableSize;
TableSize += (sizeof (EFI_ACPI_6_5_GIC_STRUCTURE) * GicCCount);
TableSize += (sizeof (EFI_ACPI_6_7_GIC_STRUCTURE) * GicCCount);
GicDOffset = TableSize;
TableSize += (sizeof (EFI_ACPI_6_5_GIC_DISTRIBUTOR_STRUCTURE) * GicDCount);
@ -633,6 +968,15 @@ BuildMadtTable (
GicItsOffset = TableSize;
TableSize += (sizeof (EFI_ACPI_6_5_GIC_ITS_STRUCTURE) * GicItsCount);
GicIrsOffset = TableSize;
TableSize += (sizeof (EFI_ACPI_6_7_GIC_IRS_STRUCTURE) * GicIrsCount);
GicItsV5Offset = TableSize;
TableSize += (sizeof (EFI_ACPI_6_7_GIC_ITSV5_STRUCTURE) * GicItsV5Count);
GicItsV5TranslateFrameOffset = TableSize;
TableSize += (sizeof (EFI_ACPI_6_7_GIC_ITSV5_TRANSLATE_FRAME_STRUCTURE) * GicItsV5TransFrameCount);
// Allocate the Buffer for MADT table
*Table = (EFI_ACPI_DESCRIPTION_HEADER *)AllocateZeroPool (TableSize);
if (*Table == NULL) {
@ -647,7 +991,7 @@ BuildMadtTable (
goto error_handler;
}
Madt = (EFI_ACPI_6_5_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *)*Table;
Madt = (EFI_ACPI_6_7_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *)*Table;
DEBUG ((
DEBUG_INFO,
@ -673,9 +1017,11 @@ BuildMadtTable (
}
Status = AddGICCList (
(EFI_ACPI_6_5_GIC_STRUCTURE *)((UINT8 *)Madt + GicCOffset),
(EFI_ACPI_6_7_GIC_STRUCTURE *)((UINT8 *)Madt + GicCOffset),
GicCInfo,
GicCCount,
GicIrsInfo,
GicIrsCount,
Madt->Header.Revision,
GicRedistCount != 0
);
@ -688,10 +1034,12 @@ BuildMadtTable (
goto error_handler;
}
AddGICD (
(EFI_ACPI_6_5_GIC_DISTRIBUTOR_STRUCTURE *)((UINT8 *)Madt + GicDOffset),
GicDInfo
);
if (GicDCount != 0) {
AddGICD (
(EFI_ACPI_6_5_GIC_DISTRIBUTOR_STRUCTURE *)((UINT8 *)Madt + GicDOffset),
GicDInfo
);
}
if (GicMSICount != 0) {
AddGICMsiFrameInfoList (
@ -717,6 +1065,40 @@ BuildMadtTable (
);
}
if (GicIrsCount != 0) {
AddGICIrsList (
(EFI_ACPI_6_7_GIC_IRS_STRUCTURE *)((UINT8 *)Madt + GicIrsOffset),
GicIrsInfo,
GicIrsCount
);
}
if (GicItsV5Count != 0) {
AddGICItsV5List (
(EFI_ACPI_6_7_GIC_ITSV5_STRUCTURE *)((UINT8 *)Madt + GicItsV5Offset),
GicItsV5Info,
GicItsV5Count
);
}
if (GicItsV5TransFrameCount != 0) {
Status = AddGICItsV5TranslateFrameList (
(EFI_ACPI_6_7_GIC_ITSV5_TRANSLATE_FRAME_STRUCTURE *)((UINT8 *)Madt + GicItsV5TranslateFrameOffset),
GicItsV5TransFrameInfo,
GicItsV5TransFrameCount,
GicItsV5Info,
GicItsV5Count
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: MADT: Failed to add GIC ITSv5 translate frame structures. Status = %r\n",
Status
));
goto error_handler;
}
}
return EFI_SUCCESS;
error_handler:
@ -779,9 +1161,9 @@ ACPI_TABLE_GENERATOR MadtGenerator = {
// Generator Description
L"ACPI.STD.MADT.GENERATOR",
// ACPI Table Signature
EFI_ACPI_6_5_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE,
EFI_ACPI_6_7_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE,
// ACPI Table Revision supported by this Generator
EFI_ACPI_6_5_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION,
EFI_ACPI_6_7_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION,
// Minimum supported ACPI Table Revision
EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION,
// Creator ID

View file

@ -1,11 +1,11 @@
/** @file
Arm SRAT Table Generator
Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.
Copyright (c) 2019 - 2026, Arm Limited. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Reference(s):
- ACPI 6.3 Specification, January 2019
- ACPI 6.7 Specification.
@par Glossary:
- Cm or CM - Configuration Manager
@ -56,12 +56,34 @@ GET_OBJECT_LIST (
CM_ARM_GIC_ITS_INFO
);
/** This macro expands to a function that retrieves the GIC
Interrupt Translation Service v5 Information from the
Configuration Manager.
*/
GET_OBJECT_LIST (
EObjNameSpaceArm,
EArmObjGicItsV5Info,
CM_ARM_GIC_ITSV5_INFO
);
/** This macro expands to a function that retrieves the GIC
Interrupt Routing Service Information from the
Configuration Manager.
*/
GET_OBJECT_LIST (
EObjNameSpaceArm,
EArmObjGicIrsInfo,
CM_ARM_GIC_IRS_INFO
);
/** Enum of the Arm specific CM objects required to
build the arch specific information of the SRAT table.
*/
typedef enum ArmSratSubTableType {
EArmGicCSubTableType,
EArmGicItsSubTableType,
EArmGicItsV5SubTableType,
EArmGicIrsSubTableType,
EArmSubTableTypeMax,
} EARM_SRAT_SUB_TABLE_TYPE;
@ -146,16 +168,58 @@ ArchReserveOffsets (
return Status;
}
Status = GetEArmObjGicItsV5Info (
CfgMgrProtocol,
CM_NULL_TOKEN,
(CM_ARM_GIC_ITSV5_INFO **)&mSratSubTable[EArmGicItsV5SubTableType].CmInfo,
&mSratSubTable[EArmGicItsV5SubTableType].Count
);
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: SRAT: Failed to get GIC ITSv5 Info. Status = %r\n",
Status
));
return Status;
}
Status = GetEArmObjGicIrsInfo (
CfgMgrProtocol,
CM_NULL_TOKEN,
(CM_ARM_GIC_IRS_INFO **)&mSratSubTable[EArmGicIrsSubTableType].CmInfo,
&mSratSubTable[EArmGicIrsSubTableType].Count
);
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
DEBUG ((
DEBUG_ERROR,
"ERROR: SRAT: Failed to get GIC IRS Info. Status = %r\n",
Status
));
return Status;
}
mSratSubTable[EArmGicCSubTableType].Offset = *ArchOffset;
*ArchOffset += (sizeof (EFI_ACPI_6_3_GICC_AFFINITY_STRUCTURE) *
mSratSubTable[EArmGicCSubTableType].Count);
if (mSratSubTable[EArmGicItsSubTableType].Count != 0) {
mSratSubTable[EArmGicItsSubTableType].Offset = *ArchOffset;
*ArchOffset += (sizeof (EFI_ACPI_6_3_GIC_ITS_AFFINITY_STRUCTURE) *
*ArchOffset += (sizeof (EFI_ACPI_6_7_GIC_ITS_AFFINITY_STRUCTURE) *
mSratSubTable[EArmGicItsSubTableType].Count);
}
if (mSratSubTable[EArmGicItsV5SubTableType].Count != 0) {
mSratSubTable[EArmGicItsV5SubTableType].Offset = *ArchOffset;
*ArchOffset += (sizeof (EFI_ACPI_6_7_GIC_ITS_AFFINITY_STRUCTURE) *
mSratSubTable[EArmGicItsV5SubTableType].Count);
}
if (mSratSubTable[EArmGicIrsSubTableType].Count != 0) {
mSratSubTable[EArmGicIrsSubTableType].Offset = *ArchOffset;
*ArchOffset += (sizeof (EFI_ACPI_6_7_GIC_IRS_AFFINITY_STRUCTURE) *
mSratSubTable[EArmGicIrsSubTableType].Count);
}
return EFI_SUCCESS;
}
@ -222,36 +286,55 @@ AddGICCAffinity (
@param [in] CfgMgrProtocol Pointer to the Configuration Manager
Protocol Interface.
@param [in] Srat Pointer to the SRAT Table.
@param [in] ItsType EArmGicItsSubTableType or EArmGicItsV5SubTableType.
**/
STATIC
VOID
EFIAPI
AddGICItsAffinity (
IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
IN EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER *CONST Srat
IN EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER *CONST Srat,
IN EARM_SRAT_SUB_TABLE_TYPE CONST ItsType
)
{
EFI_STATUS Status;
EFI_ACPI_6_3_GIC_ITS_AFFINITY_STRUCTURE *GicItsAff;
EFI_ACPI_6_7_GIC_ITS_AFFINITY_STRUCTURE *GicItsAff;
CM_ARM_GIC_ITS_INFO *GicItsInfo;
CM_ARM_GIC_ITSV5_INFO *GicItsV5Info;
UINT32 ProximityDomain;
CM_OBJECT_TOKEN ProximityDomainToken;
GicItsInfo = mSratSubTable[EArmGicItsSubTableType].CmInfo;
GicItsAff = (EFI_ACPI_6_3_GIC_ITS_AFFINITY_STRUCTURE *)((UINT8 *)Srat +
mSratSubTable[EArmGicItsSubTableType].Offset);
if (ItsType == EArmGicItsSubTableType) {
GicItsInfo = mSratSubTable[ItsType].CmInfo;
} else {
GicItsV5Info = mSratSubTable[ItsType].CmInfo;
}
while (mSratSubTable[EArmGicItsSubTableType].Count-- != 0) {
GicItsAff = (EFI_ACPI_6_7_GIC_ITS_AFFINITY_STRUCTURE *)((UINT8 *)Srat +
mSratSubTable[ItsType].Offset);
while (mSratSubTable[ItsType].Count-- != 0) {
DEBUG ((DEBUG_INFO, "SRAT: GicItsAff = 0x%p\n", GicItsAff));
GicItsAff->Type = EFI_ACPI_6_3_GIC_ITS_AFFINITY;
GicItsAff->Length = sizeof (EFI_ACPI_6_3_GIC_ITS_AFFINITY_STRUCTURE);
GicItsAff->Type = EFI_ACPI_6_7_GIC_ITS_AFFINITY;
GicItsAff->Length = sizeof (EFI_ACPI_6_7_GIC_ITS_AFFINITY_STRUCTURE);
GicItsAff->Reserved[0] = EFI_ACPI_RESERVED_BYTE;
GicItsAff->Reserved[1] = EFI_ACPI_RESERVED_BYTE;
GicItsAff->ItsId = GicItsInfo->GicItsId;
if (ItsType == EArmGicItsSubTableType) {
ProximityDomain = GicItsInfo->ProximityDomain;
ProximityDomainToken = GicItsInfo->ProximityDomainToken;
GicItsAff->ItsId = GicItsInfo->GicItsId;
} else {
ProximityDomain = GicItsV5Info->ProximityDomain;
ProximityDomainToken = GicItsV5Info->ProximityDomainToken;
GicItsAff->ItsId = GicItsV5Info->GicItsId;
}
Status = GetProximityDomainId (
CfgMgrProtocol,
GicItsInfo->ProximityDomain,
GicItsInfo->ProximityDomainToken,
ProximityDomain,
ProximityDomainToken,
&GicItsAff->ProximityDomain
);
if (EFI_ERROR (Status)) {
@ -265,6 +348,54 @@ AddGICItsAffinity (
}// while
}
/** Add the GIC IRS Affinity Structures in the SRAT Table.
@param [in] CfgMgrProtocol Pointer to the Configuration Manager
Protocol Interface.
@param [in] Srat Pointer to the SRAT Table.
**/
STATIC
VOID
EFIAPI
AddGICIrsAffinity (
IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol,
IN EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER *CONST Srat
)
{
EFI_STATUS Status;
EFI_ACPI_6_7_GIC_IRS_AFFINITY_STRUCTURE *GicIrsAff;
CM_ARM_GIC_IRS_INFO *GicIrsInfo;
GicIrsInfo = mSratSubTable[EArmGicIrsSubTableType].CmInfo;
GicIrsAff = (EFI_ACPI_6_7_GIC_IRS_AFFINITY_STRUCTURE *)((UINT8 *)Srat +
mSratSubTable[EArmGicIrsSubTableType].Offset);
while (mSratSubTable[EArmGicIrsSubTableType].Count-- != 0) {
DEBUG ((DEBUG_INFO, "SRAT: GicIrsAff = 0x%p\n", GicIrsAff));
GicIrsAff->Type = EFI_ACPI_6_7_GIC_IRS_AFFINITY;
GicIrsAff->Length = sizeof (EFI_ACPI_6_7_GIC_IRS_AFFINITY_STRUCTURE);
GicIrsAff->Reserved = EFI_ACPI_RESERVED_WORD;
GicIrsAff->IrsId = GicIrsInfo->GicIrsId;
GicIrsAff->Reserved2 = EFI_ACPI_RESERVED_DWORD;
Status = GetProximityDomainId (
CfgMgrProtocol,
GicIrsInfo->ProximityDomain,
GicIrsInfo->ProximityDomainToken,
&GicIrsAff->ProximityDomain
);
if (EFI_ERROR (Status)) {
ASSERT_EFI_ERROR (Status);
return;
}
// Next
GicIrsAff++;
GicIrsInfo++;
}// while
}
/** Add the arch specific sub-tables to the SRAT table.
These sub-tables are written in the space reserved beforehand.
@ -287,8 +418,16 @@ AddArchObjects (
AddGICCAffinity (CfgMgrProtocol, Srat);
if (mSratSubTable[EArmGicCSubTableType].Count != 0) {
AddGICItsAffinity (CfgMgrProtocol, Srat);
if (mSratSubTable[EArmGicItsSubTableType].Count != 0) {
AddGICItsAffinity (CfgMgrProtocol, Srat, EArmGicItsSubTableType);
}
if (mSratSubTable[EArmGicItsV5SubTableType].Count != 0) {
AddGICItsAffinity (CfgMgrProtocol, Srat, EArmGicItsV5SubTableType);
}
if (mSratSubTable[EArmGicIrsSubTableType].Count != 0) {
AddGICIrsAffinity (CfgMgrProtocol, Srat);
}
return EFI_SUCCESS;

View file

@ -1,13 +1,13 @@
/** @file
SRAT Table Generator
Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.
Copyright (c) 2019 - 2026, Arm Limited. All rights reserved.
Copyright (C) 2025 Advanced Micro Devices, Inc. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Reference(s):
- ACPI 6.3 Specification, January 2019
- ACPI 6.7 Specification.
@par Glossary:
- Cm or CM - Configuration Manager
@ -623,9 +623,9 @@ ACPI_TABLE_GENERATOR SratGenerator = {
// Generator Description
L"ACPI.STD.SRAT.GENERATOR",
// ACPI Table Signature
EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_SIGNATURE,
EFI_ACPI_6_7_SYSTEM_RESOURCE_AFFINITY_TABLE_SIGNATURE,
// ACPI Table Revision supported by this Generator
EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_REVISION,
EFI_ACPI_6_7_SYSTEM_RESOURCE_AFFINITY_TABLE_REVISION,
// Minimum supported ACPI Table Revision
EFI_ACPI_6_3_SYSTEM_RESOURCE_AFFINITY_TABLE_REVISION,
// Creator ID

View file

@ -0,0 +1,75 @@
/** @file
SSDT Serial Port Fixup Library.
Copyright (c) 2026, Arm Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Reference(s):
- Arm Server Base Boot Requirements (SBBR), s4.2.1.8 "SPCR".
- Microsoft Debug Port Table 2 (DBG2) Specification - December 10, 2015.
- ACPI for Arm Components 1.0 - 2020
- Arm Generic Interrupt Controller Architecture Specification,
Issue H, January 2022.
(https://developer.arm.com/documentation/ihi0069/)
**/
#include <Library/ArmLib.h>
#include <Library/ArmGicLib.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <ArchCommonNameSpaceObjects.h>
/** Validate the Serial Port Architecture Information.
@param [in] SerialPortInfoTable Table of CM_ARCH_COMMON_SERIAL_PORT_INFO.
@retval EFI_SUCCESS Success.
@retval EFI_INVALID_PARAMETER Invalid parameter.
**/
EFI_STATUS
EFIAPI
ArchValidateSerialPortInfo (
IN CONST CM_ARCH_COMMON_SERIAL_PORT_INFO *SerialPortInfo
)
{
BOOLEAN ValidInterrupt;
if (SerialPortInfo == NULL) {
return EFI_INVALID_PARAMETER;
}
// If an interrupt is not wired to the serial port, the Configuration
// Manager specifies the interrupt as 0.
// Any other value must be within the SPI or extended SPI range.
if ((SerialPortInfo->Interrupt != 0)) {
ValidInterrupt = FALSE;
if (ArmHasGicV5SystemRegisters ()) {
if ((SerialPortInfo->Interrupt >= ARM_GICV5_ARCH_SPI_MIN) &&
(SerialPortInfo->Interrupt <= ARM_GICV5_ARCH_SPI_MAX))
{
ValidInterrupt = TRUE;
}
} else {
if (((SerialPortInfo->Interrupt >= ARM_GIC_ARCH_SPI_MIN) &&
(SerialPortInfo->Interrupt <= ARM_GIC_ARCH_SPI_MAX)) ||
((SerialPortInfo->Interrupt >= ARM_GIC_ARCH_EXT_SPI_MIN) &&
(SerialPortInfo->Interrupt <= ARM_GIC_ARCH_EXT_SPI_MAX)))
{
ValidInterrupt = TRUE;
}
}
if (!ValidInterrupt) {
DEBUG ((
DEBUG_ERROR,
"ERROR: Invalid UART port interrupt ID. Interrupt = %lu\n",
SerialPortInfo->Interrupt
));
return EFI_INVALID_PARAMETER;
}
}
return EFI_SUCCESS;
}

View file

@ -0,0 +1,36 @@
/** @file
SSDT Serial Port Fixup Library.
Copyright (c) 2026, Arm Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Reference(s):
- Arm Server Base Boot Requirements (SBBR), s4.2.1.8 "SPCR".
- Microsoft Debug Port Table 2 (DBG2) Specification - December 10, 2015.
- ACPI for Arm Components 1.0 - 2020
- Arm Generic Interrupt Controller Architecture Specification,
Issue H, January 2022.
(https://developer.arm.com/documentation/ihi0069/)
**/
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <ArchCommonNameSpaceObjects.h>
/** Validate the Serial Port Architecture Information.
@param [in] SerialPortInfoTable Table of CM_ARCH_COMMON_SERIAL_PORT_INFO.
@retval EFI_SUCCESS Success.
@retval EFI_INVALID_PARAMETER Invalid parameter.
**/
EFI_STATUS
EFIAPI
ArchValidateSerialPortInfo (
IN CONST CM_ARCH_COMMON_SERIAL_PORT_INFO *SerialPortInfo
)
{
/// Nothing to do.
return EFI_SUCCESS;
}

View file

@ -28,12 +28,9 @@
#include <ConfigurationManagerHelper.h>
#include <Library/AcpiHelperLib.h>
#include <Library/AmlLib/AmlLib.h>
#include <Library/SsdtSerialPortFixupLib.h>
#include <Protocol/ConfigurationManagerProtocol.h>
#if defined (MDE_CPU_AARCH64)
#include <Library/ArmGicLib.h>
#endif
/** C array containing the compiled AML template.
This symbol is defined in the auto generated C file
containing the AML bytecode array.
@ -61,6 +58,7 @@ ValidateSerialPortInfo (
{
UINT32 Index;
CONST CM_ARCH_COMMON_SERIAL_PORT_INFO *SerialPortInfo;
EFI_STATUS Status;
if ((SerialPortInfoTable == NULL) ||
(SerialPortCount == 0))
@ -107,26 +105,11 @@ ValidateSerialPortInfo (
return EFI_INVALID_PARAMETER;
}
#if defined (MDE_CPU_AARCH64)
// If an interrupt is not wired to the serial port, the Configuration
// Manager specifies the interrupt as 0.
// Any other value must be within the SPI or extended SPI range.
if ((SerialPortInfo->Interrupt != 0) &&
!(((SerialPortInfo->Interrupt >= ARM_GIC_ARCH_SPI_MIN) &&
(SerialPortInfo->Interrupt <= ARM_GIC_ARCH_SPI_MAX)) ||
((SerialPortInfo->Interrupt >= ARM_GIC_ARCH_EXT_SPI_MIN) &&
(SerialPortInfo->Interrupt <= ARM_GIC_ARCH_EXT_SPI_MAX))))
{
DEBUG ((
DEBUG_ERROR,
"ERROR: Invalid UART port interrupt ID. Interrupt = %lu\n",
SerialPortInfo->Interrupt
));
return EFI_INVALID_PARAMETER;
Status = ArchValidateSerialPortInfo (SerialPortInfo);
if (EFI_ERROR (Status)) {
return Status;
}
#endif
DEBUG ((DEBUG_INFO, "UART Configuration:\n"));
DEBUG ((
DEBUG_INFO,

View file

@ -18,6 +18,15 @@
SsdtSerialPortFixupLib.c
SsdtSerialPortTemplate.asl
[Sources.AARCH64]
Arm/ArmSsdtSerialPortFixupLib.c
[Sources.IA32, Sources.X64]
X64/X64SsdtSerialPortFixupLib.c
[Sources.RISCV64]
RiscV/RiscVSsdtSerialPortFixupLib.c
[Packages.common]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
@ -32,5 +41,8 @@
AmlLib
BaseLib
[LibraryClasses.AARCH64]
ArmLib
[Pcd]
gEdkiiDynamicTablesPkgTokenSpaceGuid.PcdNonBsaCompliant16550SerialHid

View file

@ -0,0 +1,36 @@
/** @file
SSDT Serial Port Fixup Library.
Copyright (c) 2026, Arm Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Reference(s):
- Arm Server Base Boot Requirements (SBBR), s4.2.1.8 "SPCR".
- Microsoft Debug Port Table 2 (DBG2) Specification - December 10, 2015.
- ACPI for Arm Components 1.0 - 2020
- Arm Generic Interrupt Controller Architecture Specification,
Issue H, January 2022.
(https://developer.arm.com/documentation/ihi0069/)
**/
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <ArchCommonNameSpaceObjects.h>
/** Validate the Serial Port Architecture Information.
@param [in] SerialPortInfoTable Table of CM_ARCH_COMMON_SERIAL_PORT_INFO.
@retval EFI_SUCCESS Success.
@retval EFI_INVALID_PARAMETER Invalid parameter.
**/
EFI_STATUS
EFIAPI
ArchValidateSerialPortInfo (
IN CONST CM_ARCH_COMMON_SERIAL_PORT_INFO *SerialPortInfo
)
{
/// Nothing to do.
return EFI_SUCCESS;
}

View file

@ -11,4 +11,4 @@
#pragma once
#include <IndustryStandard/Acpi66.h>
#include <IndustryStandard/Acpi67.h>

File diff suppressed because it is too large Load diff

View file

@ -29,6 +29,7 @@
#define EFI_ACPI_IO_REMAPPING_TABLE_REVISION_04 0x4 // Deprecated
#define EFI_ACPI_IO_REMAPPING_TABLE_REVISION_05 0x5
#define EFI_ACPI_IO_REMAPPING_TABLE_REVISION_06 0x6
#define EFI_ACPI_IO_REMAPPING_TABLE_REVISION_07 0x7
#define EFI_ACPI_IORT_TYPE_ITS_GROUP 0x0
#define EFI_ACPI_IORT_TYPE_NAMED_COMP 0x1
@ -37,6 +38,7 @@
#define EFI_ACPI_IORT_TYPE_SMMUv3 0x4
#define EFI_ACPI_IORT_TYPE_PMCG 0x5
#define EFI_ACPI_IORT_TYPE_RMR 0x6
#define EFI_ACPI_IORT_TYPE_IWB 0x7
#define EFI_ACPI_IORT_MEM_ACCESS_PROP_CCA BIT0
@ -279,4 +281,16 @@ typedef struct {
// EFI_ACPI_6_0_IO_REMAPPING_MEM_RANGE_DESC MemRangeDesc[1];
} EFI_ACPI_6_0_IO_REMAPPING_RMR_NODE;
///
/// Node type 7: IWB node
///
typedef struct {
EFI_ACPI_6_0_IO_REMAPPING_NODE Node;
UINT64 ConfigFrameBase;
UINT16 IwbIndex;
// UINT8 ObjectName[];
// EFI_ACPI_6_0_IO_REMAPPING_ID_TABLE IdMapping[1];
} EFI_ACPI_6_0_IO_REMAPPING_IWB_NODE;
#pragma pack()

View file

@ -70,6 +70,7 @@
"Include/Guid/Cper.h",
"Include/IndustryStandard/Acpi64.h",
"Include/IndustryStandard/Acpi65.h",
"Include/IndustryStandard/Acpi67.h",
"Include/IndustryStandard/Tpm12.h",
"Include/IndustryStandard/Tpm20.h",
"Include/IndustryStandard/IoRemappingTable.h",

View file

@ -5,7 +5,7 @@
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Reference(s):
- IO Remapping Table, Platform Design Document, Revision E.d, Feb 2022
- IO Remapping Table, Platform Design Document, Revision E.f, Apr 2024
(https://developer.arm.com/documentation/den0049/)
@par Glossary:
@ -162,6 +162,52 @@ ValidateRmrMemDescCount (
}
}
/**
This function validates the ID Mapping array count for the IWB node.
@param [in] Ptr Pointer to the start of the field data.
@param [in] Length Length of the field.
@param [in] Context Pointer to context specific information e.g. this
could be a pointer to the ACPI table header.
**/
STATIC
VOID
EFIAPI
ValidateIwbIdMappingCount (
IN UINT8 *Ptr,
IN UINT32 Length,
IN VOID *Context
)
{
if (*(UINT32 *)Ptr != 1) {
IncrementErrorCount ();
Print (L"\nERROR: IORT ID Mapping count must be equal to 1.");
}
}
/**
This function validates the ID Mapping array offset for the IWB node.
@param [in] Ptr Pointer to the start of the field data.
@param [in] Length Length of the field.
@param [in] Context Pointer to context specific information e.g. this
could be a pointer to the ACPI table header.
**/
STATIC
VOID
EFIAPI
ValidateIwbIdArrayReference (
IN UINT8 *Ptr,
IN UINT32 Length,
IN VOID *Context
)
{
if (*(UINT32 *)Ptr == 0) {
IncrementErrorCount ();
Print (L"\nERROR: IORT ID Mapping offset must non-zero.");
}
}
/**
Helper Macro for populating the IORT Node header in the ACPI_PARSER array.
@ -340,6 +386,18 @@ STATIC CONST ACPI_PARSER IortNodeRmrMemRangeDescParser[] = {
{ L"Reserved", 4, 16, L"0x%x", NULL, NULL, NULL, NULL}
};
/**
An ACPI_PARSER array describing the IORT IWB node.
**/
STATIC CONST ACPI_PARSER IortNodeIwbParser[] = {
PARSE_IORT_NODE_HEADER (
ValidateIwbIdMappingCount,
ValidateIwbIdArrayReference
),
{ L"Config frame base", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL },
{ L"IWB_index", 2, 24, L"%d", NULL, NULL, NULL, NULL },
};
/**
This function parses the IORT Node Id Mapping array.
@ -786,6 +844,54 @@ DumpIortNodeRmr (
);
}
/**
This function parses the IORT IWB node.
@param [in] Ptr Pointer to the start of the buffer.
@param [in] Length Length of the buffer.
@param [in] MappingCount The ID Mapping count.
@param [in] MappingOffset The offset of the ID Mapping array
from the start of the IORT table.
**/
STATIC
VOID
DumpIortNodeIwb (
IN UINT8 *Ptr,
IN UINT16 Length,
IN UINT32 MappingCount,
IN UINT32 MappingOffset
)
{
UINT32 Offset;
Offset = ParseAcpi (
TRUE,
2,
"IWB Node",
Ptr,
Length,
PARSER_PARAMS (IortNodeIwbParser)
);
// Estimate the Device Name length
PrintFieldName (2, L"Device Object Name");
while ((*(Ptr + Offset) != 0) &&
(Offset < Length))
{
Print (L"%c", *(Ptr + Offset));
Offset++;
}
Print (L"\n");
DumpIortNodeIdMappings (
Ptr + MappingOffset,
Length - MappingOffset,
MappingCount
);
}
/**
This function parses the ACPI IORT table.
When trace is enabled this function parses the IORT table and traces the ACPI
@ -799,6 +905,7 @@ DumpIortNodeRmr (
- SMMUv3
- PMCG
- RMR
- IWB
This function also performs validation of the ACPI table fields.
@ -970,6 +1077,14 @@ ParseAcpiIort (
*IortIdMappingOffset
);
break;
case EFI_ACPI_IORT_TYPE_IWB:
DumpIortNodeIwb (
NodePtr,
*IortNodeLength,
*IortIdMappingCount,
*IortIdMappingOffset
);
break;
default:
IncrementErrorCount ();
Print (L"ERROR: Unsupported IORT Node type = %d\n", *IortNodeType);

View file

@ -1,7 +1,7 @@
/** @file
MADT table parser
Copyright (c) 2016 - 2024, Arm Limited. All rights reserved.
Copyright (c) 2016 - 2026, Arm Limited. All rights reserved.
Copyright (c) 2022, AMD Incorporated. All rights reserved.
Copyright (c) 2024, Loongson Technology Corporation Limited. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
@ -84,7 +84,7 @@ ValidateSpeOverflowInterrupt (
IncrementErrorCount ();
Print (
L"\nERROR: SPE Overflow Interrupt ID of %d is not in the allowed PPI ID "
L"ranges of %d-%d or %d-%d (for GICv3.1 or later).",
L"ranges of %d-%d or %d-%d (for GICv3.1 - 4).",
SpeOverflowInterrupt,
ARM_PPI_ID_MIN,
ARM_PPI_ID_MAX,
@ -136,7 +136,7 @@ ValidateTrbeInterrupt (
IncrementErrorCount ();
Print (
L"\nERROR: TRBE Interrupt ID of %d is not in the allowed PPI ID "
L"ranges of %d-%d or %d-%d (for GICv3.1 or later).",
L"ranges of %d-%d or %d-%d (for GICv3.1 - 4).",
TrbeInterrupt,
ARM_PPI_ID_MIN,
ARM_PPI_ID_MAX,
@ -238,7 +238,9 @@ STATIC CONST ACPI_PARSER GicCParser[] = {
{ L"SPE overflow Interrupt", 2, 78, L"0x%x", NULL, NULL,
ValidateSpeOverflowInterrupt, NULL },
{ L"TRBE Interrupt", 2, 80, L"0x%x", NULL, NULL,
ValidateTrbeInterrupt, NULL }
ValidateTrbeInterrupt, NULL },
{ L"IAFFID", 2, 82, L"0x%x", NULL, NULL, NULL, NULL },
{ L"IrsID", 4, 84, L"0x%x", NULL, NULL, NULL, NULL },
};
/**
@ -485,6 +487,49 @@ STATIC CONST ACPI_PARSER LpcPic[] = {
{ L"Cascade vector", 2, 13, L"0x%x", NULL, NULL, NULL, NULL }
};
/**
An ACPI_PARSER array describing the GIC IRS Interrupt Controller Structure.
**/
STATIC CONST ACPI_PARSER GicIrsParser[] = {
{ L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL },
{ L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL },
{ L"GIC Version", 1, 2, L"%d", NULL, NULL, NULL, NULL },
{ L"Reserved", 1, 3, L"0x%x", NULL, NULL, NULL, NULL },
{ L"GIC IRS ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL },
{ L"Flags", 4, 8, L"0x%x", NULL, NULL, NULL, NULL },
{ L"Reserved", 4, 12, L"0x%x", NULL, NULL, NULL, NULL },
{ L"IRS Config Frame Base", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL },
{ L"IRS Set LPI Frame Base", 8, 24, L"0x%lx", NULL, NULL, NULL, NULL }
};
/**
An ACPI_PARSER array describing the GIC ITSv5 Interrupt Controller Structure.
**/
STATIC CONST ACPI_PARSER GicItsV5Parser[] = {
{ L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL },
{ L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL },
{ L"Flags", 1, 2, L"0x%x", NULL, NULL, NULL, NULL },
{ L"Reserved", 1, 3, L"0x%x", NULL, NULL, NULL, NULL },
{ L"GIC ITS ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL },
{ L"Physical Base Address", 8, 8, L"0x%lx", NULL, NULL, NULL, NULL },
};
/**
An ACPI_PARSER array describing the GIC ITSv5 Translate Frame Structure.
**/
STATIC CONST ACPI_PARSER GicItsV5TranslateFrameParser[] = {
{ L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL },
{ L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL },
{ L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL },
{ L"Linked GIC ITS ID", 4, 4, L"0x%x", NULL, NULL, NULL, NULL },
{ L"ITS Translate Frame ID", 4, 8, L"0x%x", NULL, NULL, NULL, NULL },
{ L"Reserved", 4, 12, L"0x%x", NULL, NULL, NULL, NULL },
{ L"ITS Translate Frame Base Address", 8, 16, L"0x%lx", NULL, NULL, NULL, NULL }
};
/**
An ACPI_PARSER array describing the ACPI MADT Table.
**/
@ -517,6 +562,9 @@ STATIC CONST ACPI_PARSER MadtInterruptControllerHeaderParser[] = {
- GIC MSI Frame
- GICR
- GIC ITS
- GIC IRS
- GIC ITSv5
- GIC ITSv5 translate frame
This function also performs validation of the ACPI table fields.
@ -823,6 +871,45 @@ ParseAcpiMadt (
break;
}
case EFI_ACPI_6_7_GIC_IRS:
{
ParseAcpi (
TRUE,
2,
"GIC IRS",
InterruptContollerPtr,
*MadtInterruptControllerLength,
PARSER_PARAMS (GicIrsParser)
);
break;
}
case EFI_ACPI_6_7_GIC_ITSV5:
{
ParseAcpi (
TRUE,
2,
"GIC ITSv5",
InterruptContollerPtr,
*MadtInterruptControllerLength,
PARSER_PARAMS (GicItsV5Parser)
);
break;
}
case EFI_ACPI_6_7_GIC_ITSV5_TRANSLATE_FRAME:
{
ParseAcpi (
TRUE,
2,
"GIC ITSv5 Translate Frame",
InterruptContollerPtr,
*MadtInterruptControllerLength,
PARSER_PARAMS (GicItsV5TranslateFrameParser)
);
break;
}
default:
{
IncrementErrorCount ();

View file

@ -1,11 +1,11 @@
/** @file
SRAT table parser
Copyright (c) 2016 - 2024, Arm Limited. All rights reserved.
Copyright (c) 2016 - 2026, Arm Limited. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Reference(s):
- ACPI 6.3 Specification - January 2019
- ACPI 6.7 Specification
**/
#include <IndustryStandard/Acpi.h>
@ -341,6 +341,19 @@ STATIC CONST ACPI_PARSER SratX2ApciAffinityParser[] = {
{ L"Reserved", 4, 20, L"0x%x", NULL, NULL, NULL, NULL }
};
/**
An ACPI_PARSER array describing the GIC IRS Affinity structure.
**/
STATIC CONST ACPI_PARSER SratGicIrsAffinityParser[] = {
{ L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL },
{ L"Length", 1, 1, L"0x%x", NULL, NULL, NULL, NULL },
{ L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL },
{ L"Proximity Domain", 4, 4, L"0x%x", NULL, NULL, NULL, NULL },
{ L"IRS Id", 4, 8, L"0x%x", NULL, NULL, NULL, NULL },
{ L"Reserved", 4, 12, L"0x%x", NULL, NULL, NULL, NULL },
};
/**
This function parses the ACPI SRAT table.
When trace is enabled this function parses the SRAT table and
@ -376,10 +389,12 @@ ParseAcpiSrat (
UINT32 MemoryAffinityIndex;
UINT32 ApicSapicAffinityIndex;
UINT32 X2ApicAffinityIndex;
UINT32 GicIrsAffinityIndex;
CHAR8 Buffer[80]; // Used for AsciiName param of ParseAcpi
GicCAffinityIndex = 0;
GicITSAffinityIndex = 0;
GicIrsAffinityIndex = 0;
GenericInitiatorAffinityIndex = 0;
MemoryAffinityIndex = 0;
ApicSapicAffinityIndex = 0;
@ -542,6 +557,23 @@ ParseAcpiSrat (
);
break;
case EFI_ACPI_6_7_GIC_IRS_AFFINITY:
AsciiSPrint (
Buffer,
sizeof (Buffer),
"GIC IRS Affinity Structure [%d]",
GicIrsAffinityIndex++
);
ParseAcpi (
TRUE,
2,
Buffer,
ResourcePtr,
*SratRALength,
PARSER_PARAMS (SratGicIrsAffinityParser)
);
break;
default:
IncrementErrorCount ();
Print (L"ERROR: Unknown SRAT Affinity type = 0x%x\n", *SratRAType);