summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAbdul Lateef Attar <AbdulLateef.Attar@amd.com>2025-06-11 10:34:44 +0000
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2025-06-19 17:43:41 +0000
commitf93da0727748fa2102e17e85bb43a28ff9007fe5 (patch)
treeddc0f99e5c577e5f3286d871d75e0d31ccd3a27d
parente4e29690f11f492ef929916dd1fa862f5ac25e2d (diff)
downloadedk2-f93da0727748fa2102e17e85bb43a28ff9007fe5.zip
edk2-f93da0727748fa2102e17e85bb43a28ff9007fe5.tar.gz
edk2-f93da0727748fa2102e17e85bb43a28ff9007fe5.tar.bz2
DynamicTablesPkg: Enhance SPCR support for interrupt and terminal types
Introduce optional configuration objects to specify interrupt and terminal types. When the platform supplies this information, the SPCR table is updated to reflect the provided values. If the interrupt type is 8259, the corresponding IRQ number is set in the SPCR table. Signed-off-by: Abdul Lateef Attar <AbdulLateef.Attar@amd.com>
-rw-r--r--DynamicTablesPkg/Include/ArchCommonNameSpaceObjects.h15
-rw-r--r--DynamicTablesPkg/Library/Acpi/Common/AcpiSpcrLib/SpcrGenerator.c247
-rw-r--r--DynamicTablesPkg/Library/Common/TableHelperLib/ConfigurationManagerObjectParser.c8
3 files changed, 270 insertions, 0 deletions
diff --git a/DynamicTablesPkg/Include/ArchCommonNameSpaceObjects.h b/DynamicTablesPkg/Include/ArchCommonNameSpaceObjects.h
index 2e0b5ee..a642aec 100644
--- a/DynamicTablesPkg/Include/ArchCommonNameSpaceObjects.h
+++ b/DynamicTablesPkg/Include/ArchCommonNameSpaceObjects.h
@@ -70,6 +70,7 @@ typedef enum ArchCommonObjectID {
EArchCommonObjMemoryProximityDomainAttrInfo, ///< 42 - Memory Proximity Domain Attribute
EArchCommonObjMemoryLatBwInfo, ///< 43 - Memory Latency Bandwidth Info
EArchCommonObjMemoryCacheInfo, ///< 44 - Memory Cache Info
+ EArchCommonObjSpcrInfo, ///< 45 - Serial Terminal and Interrupt Info
EArchCommonObjMax
} EARCH_COMMON_OBJECT_ID;
@@ -1048,6 +1049,20 @@ typedef struct CmArchCommonMemoryCacheInfo {
/// @todo but will be in a near future.
} CM_ARCH_COMMON_MEMORY_CACHE_INFO;
+/** A structure that describes the Serial Terminal and Interrupt Information.
+
+ This structure provides details about the interrupt type and terminal type
+ associated with a console device, used for the SPCR Table.
+
+ ID: EArchCommonObjSpcrInfo
+*/
+typedef struct CmArchCommonObjSpcrInfo {
+ /// Specifies the type of interrupt used by the console device.
+ UINT8 InterruptType;
+ /// Specifies the terminal type used by the console device.
+ UINT8 TerminalType;
+} CM_ARCH_COMMON_SPCR_INFO;
+
#pragma pack()
#endif // ARCH_COMMON_NAMESPACE_OBJECTS_H_
diff --git a/DynamicTablesPkg/Library/Acpi/Common/AcpiSpcrLib/SpcrGenerator.c b/DynamicTablesPkg/Library/Acpi/Common/AcpiSpcrLib/SpcrGenerator.c
index 3dbfc3e..421594b 100644
--- a/DynamicTablesPkg/Library/Acpi/Common/AcpiSpcrLib/SpcrGenerator.c
+++ b/DynamicTablesPkg/Library/Acpi/Common/AcpiSpcrLib/SpcrGenerator.c
@@ -2,6 +2,7 @@
SPCR Table Generator
Copyright (c) 2017 - 2021, Arm Limited. All rights reserved.<BR>
+ Copyright (C) 2025, Advanced Micro Devices, Inc. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -35,6 +36,8 @@ Requirements:
The following Configuration Manager Object(s) are required by
this Generator:
- EArchCommonObjConsolePortInfo
+ - EArchCommonObjSpcrInfo (OPTIONAL)
+
NOTE: This implementation ignores the possibility that the Serial settings may
be modified from the UEFI Shell. A more complex handler would be needed
@@ -44,6 +47,14 @@ NOTE: This implementation ignores the possibility that the Serial settings may
#pragma pack(1)
+/** Valid SPCR interrupt types
+*/
+#define SPCR_VALID_INTERRUPT_TYPES \
+ (EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERRUPT_TYPE_8259 | \
+ EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERRUPT_TYPE_APIC | \
+ EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERRUPT_TYPE_SAPIC | \
+ EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERRUPT_TYPE_GIC)
+
/** A string representing the name of the SPCR port.
*/
#define NAME_STR_SPCR_PORT "COM1"
@@ -107,6 +118,187 @@ GET_OBJECT_LIST (
CM_ARCH_COMMON_SERIAL_PORT_INFO
)
+/** This macro expands to a function that retrieves the Serial
+ Terminal and Interrupt Information from the Configuration Manager.
+ This object is optional.
+*/
+GET_OBJECT_LIST (
+ EObjNameSpaceArchCommon,
+ EArchCommonObjSpcrInfo,
+ CM_ARCH_COMMON_SPCR_INFO
+ )
+
+/** Validate the Serial Port Terminal Interrupt Information.
+
+ @param [in] SerialPortInfo Pointer to the Serial Port Information.
+ @param [in] SpcrInfo Pointer to the SPCR additional Information.
+
+ @retval EFI_SUCCESS The information is valid.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+ValidateSerialTerminalInterruptInfo (
+ IN CM_ARCH_COMMON_SERIAL_PORT_INFO *SerialPortInfo,
+ IN CM_ARCH_COMMON_SPCR_INFO *SpcrInfo
+ )
+{
+ EFI_STATUS Status;
+
+ if ((SerialPortInfo == NULL) || (SpcrInfo == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ if ((SpcrInfo->TerminalType != EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_TERMINAL_TYPE_VT100) &&
+ (SpcrInfo->TerminalType != EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_TERMINAL_TYPE_VT100_PLUS) &&
+ (SpcrInfo->TerminalType != EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_TERMINAL_TYPE_VT_UTF8) &&
+ (SpcrInfo->TerminalType != EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_TERMINAL_TYPE_ANSI))
+ {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SPCR: Invalid terminal type %d for serial terminal.\n",
+ SpcrInfo->TerminalType
+ ));
+ Status |= EFI_INVALID_PARAMETER;
+ }
+
+ if ((SerialPortInfo->PortSubtype == EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_FULL_16550) &&
+ (SerialPortInfo->AccessSize > EFI_ACPI_6_3_UNDEFINED))
+ {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SPCR: Access size must be %d for legacy 16550 UART.\n",
+ EFI_ACPI_6_3_UNDEFINED
+ ));
+ Status |= EFI_INVALID_PARAMETER;
+ }
+
+ if (SerialPortInfo->PortSubtype == EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_16550_WITH_GAS) {
+ if ((SerialPortInfo->AccessSize <= EFI_ACPI_6_3_UNDEFINED) ||
+ (SerialPortInfo->AccessSize >= EFI_ACPI_6_3_QWORD))
+ {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SPCR: Access size must be > %d and < %d for 16550 with GAS.\n",
+ EFI_ACPI_6_3_UNDEFINED,
+ EFI_ACPI_6_3_QWORD
+ ));
+ Status |= EFI_INVALID_PARAMETER;
+ }
+ }
+
+ if (SpcrInfo->InterruptType != 0) {
+ // Check that reserved bits [5:7] are zero
+ if ((SpcrInfo->InterruptType & ~(SPCR_VALID_INTERRUPT_TYPES)) != 0) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SPCR: Reserved bits [5:7] must be zero in interrupt type (0x%02x).\n",
+ SpcrInfo->InterruptType
+ ));
+ Status |= EFI_INVALID_PARAMETER;
+ }
+
+ if ((((SpcrInfo->InterruptType) &
+ (EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERRUPT_TYPE_GIC)) != 0) &&
+ (SpcrInfo->InterruptType !=
+ EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERRUPT_TYPE_GIC))
+ {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SPCR: %d GIC interrupt type cannot be combined with others.\n",
+ SpcrInfo->InterruptType
+ ));
+ Status |= EFI_INVALID_PARAMETER;
+ }
+
+ if ((SpcrInfo->InterruptType &
+ EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERRUPT_TYPE_APIC) != 0)
+ {
+ if ((SpcrInfo->InterruptType &
+ ~(EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERRUPT_TYPE_8259 |
+ EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERRUPT_TYPE_APIC)) != 0)
+ {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SPCR: %d Invalid APIC interrupt type.\n",
+ SpcrInfo->InterruptType
+ ));
+ Status |= EFI_INVALID_PARAMETER;
+ }
+ }
+
+ if ((SpcrInfo->InterruptType &
+ EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERRUPT_TYPE_SAPIC) != 0)
+ {
+ if ((SpcrInfo->InterruptType &
+ ~(EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERRUPT_TYPE_8259 | \
+ EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERRUPT_TYPE_SAPIC)) != 0)
+ {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SPCR: %d Invalid SAPIC interrupt type.\n",
+ SpcrInfo->InterruptType
+ ));
+ Status |= EFI_INVALID_PARAMETER;
+ }
+ }
+
+ if ((SpcrInfo->InterruptType & EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERRUPT_TYPE_8259) != 0) {
+ // For legacy devices, only GSIs below 32 are used.
+ // Valid IRQs: 2-7, 9-12, 14-15. Reserved: 0-1, 8, 13, 16-255.
+ if (!(((SerialPortInfo->Interrupt >= 2) && (SerialPortInfo->Interrupt <= 7)) ||
+ ((SerialPortInfo->Interrupt >= 9) && (SerialPortInfo->Interrupt <= 12)) ||
+ ((SerialPortInfo->Interrupt >= 14) && (SerialPortInfo->Interrupt <= 15))))
+ {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SPCR: Invalid IRQ %d for 8259 interrupt type.\n",
+ SerialPortInfo->Interrupt
+ ));
+ Status |= EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ return Status;
+}
+
+/** Update the SPCR table with the terminal interrupt type and terminal information.
+
+ @param [in, out] SpcrTable Pointer to the SPCR table.
+ @param [in] SpcrInfo Pointer to the Serial Terminal Interrupt Information.
+ @param [in] SerialPortInfo Pointer to the Serial Port Information.
+
+ @retval EFI_SUCCESS The information was updated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+UpdateTerminalInterruptTypeInfo (
+ IN OUT EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_4 *SpcrTable,
+ IN CM_ARCH_COMMON_SPCR_INFO *SpcrInfo,
+ IN CM_ARCH_COMMON_SERIAL_PORT_INFO *SerialPortInfo
+ )
+{
+ if ((SpcrTable == NULL) || (SpcrInfo == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SpcrTable->InterruptType = SpcrInfo->InterruptType;
+ SpcrTable->TerminalType = SpcrInfo->TerminalType;
+
+ if ((SpcrInfo->InterruptType &
+ EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERRUPT_TYPE_8259) != 0)
+ {
+ SpcrTable->Irq = (SerialPortInfo->Interrupt & MAX_UINT8);
+ }
+
+ return EFI_SUCCESS;
+}
+
/** Free any resources allocated for constructing the tables.
@param [in] This Pointer to the ACPI table generator.
@@ -209,6 +401,8 @@ BuildSpcrTableEx (
UINT32 SerialPortCount;
EFI_ACPI_DESCRIPTION_HEADER **TableList;
UINT32 Size;
+ CM_ARCH_COMMON_SPCR_INFO *SpcrInfo;
+ UINT32 SpcrInfoCount;
ASSERT (This != NULL);
ASSERT (AcpiTableInfo != NULL);
@@ -258,6 +452,37 @@ BuildSpcrTableEx (
return EFI_NOT_FOUND;
}
+ SpcrInfo = NULL;
+ SpcrInfoCount = 0;
+ Status = GetEArchCommonObjSpcrInfo (
+ CfgMgrProtocol,
+ CM_NULL_TOKEN,
+ &SpcrInfo,
+ &SpcrInfoCount
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Status = ValidateSerialTerminalInterruptInfo (
+ SerialPortInfo,
+ SpcrInfo
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SPCR: Invalid serial terminal interrupt information. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+ } else {
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "SPCR: Continue with default interrupt type (0x%x) and terminal type (0x%x).\n",
+ EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_INTERRUPT_TYPE_GIC,
+ EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_TERMINAL_TYPE_ANSI
+ ));
+ }
+
// Validate the SerialPort info. Only one SPCR port can be described.
// If platform provides description for multiple SPCR ports, use the
// first SPCR port information.
@@ -343,6 +568,12 @@ BuildSpcrTableEx (
// and some ConfigurationManager implementations
// may not be providing this field data
AcpiSpcr.BaseAddress.AccessSize = EFI_ACPI_6_3_DWORD;
+ if (SerialPortInfo->PortSubtype == EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_FULL_16550) {
+ AcpiSpcr.BaseAddress.AddressSpaceId = EFI_ACPI_6_3_SYSTEM_IO;
+ AcpiSpcr.BaseAddress.RegisterBitWidth = 8;
+ AcpiSpcr.BaseAddress.RegisterBitOffset = 0;
+ AcpiSpcr.BaseAddress.AccessSize = EFI_ACPI_6_3_UNDEFINED;
+ }
} else {
AcpiSpcr.BaseAddress.AccessSize = SerialPortInfo->AccessSize;
}
@@ -397,6 +628,22 @@ BuildSpcrTableEx (
AsciiStrCpyS (AcpiSpcr.NameSpaceString, sizeof (NAME_STR_SPCR_PORT), NAME_STR_SPCR_PORT);
}
+ if (SpcrInfoCount != 0) {
+ Status = UpdateTerminalInterruptTypeInfo (
+ &AcpiSpcr,
+ SpcrInfo,
+ SerialPortInfo
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SPCR: Failed to update interrupt terminal type info. Status = %r\n",
+ Status
+ ));
+ goto error_handler;
+ }
+ }
+
TableList[0] = (EFI_ACPI_DESCRIPTION_HEADER *)&AcpiSpcr;
// Build a SSDT table describing the serial port.
diff --git a/DynamicTablesPkg/Library/Common/TableHelperLib/ConfigurationManagerObjectParser.c b/DynamicTablesPkg/Library/Common/TableHelperLib/ConfigurationManagerObjectParser.c
index c61caf8..a0f00ce 100644
--- a/DynamicTablesPkg/Library/Common/TableHelperLib/ConfigurationManagerObjectParser.c
+++ b/DynamicTablesPkg/Library/Common/TableHelperLib/ConfigurationManagerObjectParser.c
@@ -874,6 +874,13 @@ STATIC CONST CM_OBJ_PARSER CmArchCommonMemoryCacheInfo[] = {
{ "CacheAttributes", 4, "0x%x", NULL,},
};
+/** A parser for EArchCommonObjSpcrInfo.
+*/
+STATIC CONST CM_OBJ_PARSER CmArchCommonObjSpcrInfoParser[] = {
+ { "InterruptType", 1, "0x%x", NULL },
+ { "TerminalType", 1, "0x%x", NULL }
+};
+
/** A parser for Arch Common namespace objects.
*/
STATIC CONST CM_OBJ_PARSER_ARRAY ArchCommonNamespaceObjectParser[] = {
@@ -922,6 +929,7 @@ STATIC CONST CM_OBJ_PARSER_ARRAY ArchCommonNamespaceObjectParser[] = {
CM_PARSER_ADD_OBJECT (EArchCommonObjMemoryProximityDomainAttrInfo,CmArchCommonMemoryProximityDomainAttrInfo),
CM_PARSER_ADD_OBJECT (EArchCommonObjMemoryLatBwInfo, CmArchCommonMemoryLatBwInfo),
CM_PARSER_ADD_OBJECT (EArchCommonObjMemoryCacheInfo, CmArchCommonMemoryCacheInfo),
+ CM_PARSER_ADD_OBJECT (EArchCommonObjSpcrInfo, CmArchCommonObjSpcrInfoParser),
CM_PARSER_ADD_OBJECT_RESERVED (EArchCommonObjMax)
};