diff --git a/DynamicTablesPkg/DynamicTables.dsc.inc b/DynamicTablesPkg/DynamicTables.dsc.inc index 928529f797..0063fc3c67 100644 --- a/DynamicTablesPkg/DynamicTables.dsc.inc +++ b/DynamicTablesPkg/DynamicTables.dsc.inc @@ -14,6 +14,7 @@ [LibraryClasses.common] AmlLib|DynamicTablesPkg/Library/Common/AmlLib/AmlLib.inf + SsdtSerialPortFixupLib|DynamicTablesPkg/Library/Common/SsdtSerialPortFixupLib/SsdtSerialPortFixupLib.inf TableHelperLib|DynamicTablesPkg/Library/Common/TableHelperLib/TableHelperLib.inf [Components.common] diff --git a/DynamicTablesPkg/DynamicTablesPkg.ci.yaml b/DynamicTablesPkg/DynamicTablesPkg.ci.yaml index 5ee2035732..c0d09e79fd 100644 --- a/DynamicTablesPkg/DynamicTablesPkg.ci.yaml +++ b/DynamicTablesPkg/DynamicTablesPkg.ci.yaml @@ -69,6 +69,8 @@ "IgnoreFiles": [], # use gitignore syntax to ignore errors # in matching files "ExtendWords": [ + "ARMHB", # ARMHB000 + "ARMLTD", "EISAID", "CCIDX", "CCSIDR", @@ -81,6 +83,7 @@ "MPIDR", "pytool", "Roadmap", + "ssdtserialporttemplate", "SMMUV", "standardised", "TABLEEX", diff --git a/DynamicTablesPkg/DynamicTablesPkg.dec b/DynamicTablesPkg/DynamicTablesPkg.dec index 57e6815fa1..f36a6e8bb7 100644 --- a/DynamicTablesPkg/DynamicTablesPkg.dec +++ b/DynamicTablesPkg/DynamicTablesPkg.dec @@ -20,6 +20,9 @@ ## @libraryclass Defines a set of APIs for Dynamic AML generation. AmlLib|Include/Library/AmlLib/AmlLib.h + ## @libraryclass Defines a set of methods for fixing up a SSDT Serial Port. + SsdtSerialPortFixupLib|Include/Library/SsdtSerialPortFixupLib.h + ## @libraryclass Defines a set of helper methods. TableHelperLib|Include/Library/TableHelperLib.h diff --git a/DynamicTablesPkg/DynamicTablesPkg.dsc b/DynamicTablesPkg/DynamicTablesPkg.dsc index add6b192ad..0232bda459 100644 --- a/DynamicTablesPkg/DynamicTablesPkg.dsc +++ b/DynamicTablesPkg/DynamicTablesPkg.dsc @@ -37,6 +37,7 @@ [Components.common] DynamicTablesPkg/Library/Common/AmlLib/AmlLib.inf + DynamicTablesPkg/Library/Common/SsdtSerialPortFixupLib/SsdtSerialPortFixupLib.inf DynamicTablesPkg/Library/Common/TableHelperLib/TableHelperLib.inf [BuildOptions] diff --git a/DynamicTablesPkg/Include/AcpiTableGenerator.h b/DynamicTablesPkg/Include/AcpiTableGenerator.h index b55feb4e75..ef5018c312 100644 --- a/DynamicTablesPkg/Include/AcpiTableGenerator.h +++ b/DynamicTablesPkg/Include/AcpiTableGenerator.h @@ -1,6 +1,6 @@ /** @file - Copyright (c) 2017 - 2019, ARM Limited. All rights reserved. + Copyright (c) 2017 - 2020, Arm Limited. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent @@ -55,6 +55,10 @@ The Dynamic Tables Framework implements the following ACPI table generators: the Configuration Manager and builds the PPTT table. - SRAT : The SRAT generator collates the system resource affinity information from the Configuration Manager and builds the SRAT table. + - SSDT Serial-Port: + The SSDT Serial generator collates the Serial port information + from the Configuration Manager and patches the SSDT Serial Port + template to build the SSDT Serial port table. */ /** The ACPI_TABLE_GENERATOR_ID type describes ACPI table generator ID. @@ -78,6 +82,7 @@ typedef enum StdAcpiTableId { EStdAcpiTableIdIort, ///< IORT Generator EStdAcpiTableIdPptt, ///< PPTT Generator EStdAcpiTableIdSrat, ///< SRAT Generator + EStdAcpiTableIdSsdtSerialPort, ///< SSDT Serial-Port Generator EStdAcpiTableIdMax } ESTD_ACPI_TABLE_ID; diff --git a/DynamicTablesPkg/Include/ArmNameSpaceObjects.h b/DynamicTablesPkg/Include/ArmNameSpaceObjects.h index 57a282d5cb..b2534a6505 100644 --- a/DynamicTablesPkg/Include/ArmNameSpaceObjects.h +++ b/DynamicTablesPkg/Include/ArmNameSpaceObjects.h @@ -1,6 +1,6 @@ /** @file - Copyright (c) 2017 - 2020, ARM Limited. All rights reserved. + Copyright (c) 2017 - 2020, Arm Limited. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent @@ -56,6 +56,7 @@ typedef enum ArmObjectID { EArmObjDeviceHandleAcpi, ///< 32 - Device Handle Acpi EArmObjDeviceHandlePci, ///< 33 - Device Handle Pci EArmObjGenericInitiatorAffinityInfo, ///< 34 - Generic Initiator Affinity + EArmObjSerialPortInfo, ///< 35 - Generic Serial Port Info EArmObjMax } EARM_OBJECT_ID; @@ -270,7 +271,8 @@ typedef struct CmArmGicItsInfo { Serial Port information for the Platform. ID: EArmObjSerialConsolePortInfo or - EArmObjSerialDebugPortInfo + EArmObjSerialDebugPortInfo or + EArmObjSerialPortInfo */ typedef struct CmArmSerialPortInfo { /// The physical base address for the serial port @@ -287,6 +289,9 @@ typedef struct CmArmSerialPortInfo { /// Serial Port subtype UINT16 PortSubtype; + + /// The Base address length + UINT64 BaseAddressLength; } CM_ARM_SERIAL_PORT_INFO; /** A structure that describes the diff --git a/DynamicTablesPkg/Include/Library/SsdtSerialPortFixupLib.h b/DynamicTablesPkg/Include/Library/SsdtSerialPortFixupLib.h new file mode 100644 index 0000000000..4605f3f34b --- /dev/null +++ b/DynamicTablesPkg/Include/Library/SsdtSerialPortFixupLib.h @@ -0,0 +1,68 @@ +/** @file + Ssdt Serial Port Fixup Library + + Copyright (c) 2020, Arm Limited. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef SSDT_SERIAL_PORT_LIB_H_ +#define SSDT_SERIAL_PORT_LIB_H_ + +/** Build a SSDT table describing the input serial port. + + The table created by this function must be freed by FreeSsdtSerialTable. + + @param [in] AcpiTableInfo Pointer to the ACPI table information. + @param [in] SerialPortInfo Serial port to describe in the SSDT table. + @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 Serial Port. + @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 +BuildSsdtSerialPortTable ( + IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * AcpiTableInfo, + IN CONST CM_ARM_SERIAL_PORT_INFO * SerialPortInfo, + IN CONST CHAR8 * Name, + IN CONST UINT64 Uid, + OUT EFI_ACPI_DESCRIPTION_HEADER ** Table + ); + +/** Free an SSDT table previously created by + the BuildSsdtSerialTable function. + + @param [in] Table Pointer to a SSDT table allocated by + the BuildSsdtSerialTable function. + + @retval EFI_SUCCESS Success. +**/ +EFI_STATUS +EFIAPI +FreeSsdtSerialPortTable ( + IN EFI_ACPI_DESCRIPTION_HEADER * Table + ); + +/** Validate the Serial Port Information. + + @param [in] SerialPortInfoTable Table of CM_ARM_SERIAL_PORT_INFO. + @param [in] SerialPortCount Count of SerialPort in the table. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. +**/ +EFI_STATUS +EFIAPI +ValidateSerialPortInfo ( + IN CONST CM_ARM_SERIAL_PORT_INFO * SerialPortInfoTable, + IN UINT32 SerialPortCount + ); + +#endif // SSDT_SERIAL_PORT_LIB_H_ diff --git a/DynamicTablesPkg/Library/Common/SsdtSerialPortFixupLib/SsdtSerialPortFixupLib.c b/DynamicTablesPkg/Library/Common/SsdtSerialPortFixupLib/SsdtSerialPortFixupLib.c new file mode 100644 index 0000000000..944bfd6eaa --- /dev/null +++ b/DynamicTablesPkg/Library/Common/SsdtSerialPortFixupLib/SsdtSerialPortFixupLib.c @@ -0,0 +1,524 @@ +/** @file + SSDT Serial Port Fixup Library. + + Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.
+ + 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. +**/ + +#include +#include +#include +#include +#include +#include +#include +#include + +// Module specific include files. +#include +#include +#include +#include +#include +#include + +/** C array containing the compiled AML template. + This symbol is defined in the auto generated C file + containing the AML bytecode array. +*/ +extern CHAR8 ssdtserialporttemplate_aml_code[]; + +/** UART address range length. +*/ +#define MIN_UART_ADDRESS_LENGTH 0x1000U + +/** Validate the Serial Port Information. + + @param [in] SerialPortInfoTable Table of CM_ARM_SERIAL_PORT_INFO. + @param [in] SerialPortCount Count of SerialPort in the table. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. +**/ +EFI_STATUS +EFIAPI +ValidateSerialPortInfo ( + IN CONST CM_ARM_SERIAL_PORT_INFO * SerialPortInfoTable, + IN UINT32 SerialPortCount + ) +{ + UINT32 Index; + CONST CM_ARM_SERIAL_PORT_INFO * SerialPortInfo; + + if ((SerialPortInfoTable == NULL) || + (SerialPortCount == 0)) { + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + for (Index = 0; Index < SerialPortCount; Index++) { + SerialPortInfo = &SerialPortInfoTable[Index]; + ASSERT (SerialPortInfo != NULL); + + if ((SerialPortInfo == NULL ) || + (SerialPortInfo->BaseAddress == 0)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: UART port base address is invalid. BaseAddress = 0x%llx\n", + SerialPortInfo->BaseAddress + )); + return EFI_INVALID_PARAMETER; + } + + if ((SerialPortInfo->PortSubtype != + EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_PL011_UART) && + (SerialPortInfo->PortSubtype != + EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_SBSA_GENERIC_UART_2X) && + (SerialPortInfo->PortSubtype != + EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_SBSA_GENERIC_UART) && + (SerialPortInfo->PortSubtype != + EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_DCC) && + (SerialPortInfo->PortSubtype != + EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_FULL_16550)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: UART port subtype is invalid." + " UART Base = 0x%llx, PortSubtype = 0x%x\n", + SerialPortInfo->BaseAddress, + SerialPortInfo->PortSubtype + )); + return EFI_INVALID_PARAMETER; + } + + DEBUG ((DEBUG_INFO, "UART Configuration:\n")); + DEBUG (( + DEBUG_INFO, + " UART Base = 0x%llx\n", SerialPortInfo->BaseAddress + )); + DEBUG (( + DEBUG_INFO, + " Length = 0x%llx\n", + SerialPortInfo->BaseAddressLength + )); + DEBUG ((DEBUG_INFO, " Clock = %lu\n", SerialPortInfo->Clock)); + DEBUG ((DEBUG_INFO, " BaudRate = %llu\n", SerialPortInfo->BaudRate)); + DEBUG ((DEBUG_INFO, " Interrupt = %lu\n", SerialPortInfo->Interrupt)); + } // for + + return EFI_SUCCESS; +} + +/** Fixup the Serial Port Ids (_UID, _HID, _CID). + + @param [in] RootNodeHandle Pointer to the root of an AML tree. + @param [in] Uid UID for the Serial Port. + @param [in] SerialPortInfo Pointer to a Serial Port Information + structure. + Get the Serial Port 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 +FixupIds ( + IN OUT AML_ROOT_NODE_HANDLE RootNodeHandle, + IN CONST UINT64 Uid, + IN CONST CM_ARM_SERIAL_PORT_INFO * SerialPortInfo + ) +{ + EFI_STATUS Status; + AML_OBJECT_NODE_HANDLE NameOpIdNode; + CONST CHAR8 * HidString; + CONST CHAR8 * CidString; + + // Get the _CID and _HID value to write. + switch (SerialPortInfo->PortSubtype) { + case EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_FULL_16550: + { + HidString = "PNP0501"; + CidString = "PNP0500"; + break; + } + case EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_PL011_UART: + { + HidString = "ARMH0011"; + CidString = "ARMHB000"; + break; + } + case EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_SBSA_GENERIC_UART: + case EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_SBSA_GENERIC_UART_2X: + { + HidString = "ARMH0011"; + CidString = ""; + break; + } + default: + { + return EFI_INVALID_PARAMETER; + } + } // switch + + // Get the _UID NameOp object defined by the "Name ()" statement, + // and update its value. + Status = AmlFindNode ( + RootNodeHandle, + "\\_SB_.COM0._UID", + &NameOpIdNode + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = AmlNameOpUpdateInteger (NameOpIdNode, (UINT64)Uid); + if (EFI_ERROR (Status)) { + return Status; + } + + // Get the _HID NameOp object defined by the "Name ()" statement, + // and update its value. + Status = AmlFindNode ( + RootNodeHandle, + "\\_SB_.COM0._HID", + &NameOpIdNode + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = AmlNameOpUpdateString (NameOpIdNode, HidString); + if (EFI_ERROR (Status)) { + return Status; + } + + // Get the _CID NameOp object defined by the "Name ()" statement, + // and update its value. + Status = AmlFindNode ( + RootNodeHandle, + "\\_SB_.COM0._CID", + &NameOpIdNode + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // If we have a CID then update a _CID node else delete the node. + if (AsciiStrLen (CidString) != 0) { + Status = AmlNameOpUpdateString (NameOpIdNode, CidString); + } else { + // First detach the node from the tree. + Status = AmlDetachNode (NameOpIdNode); + if (EFI_ERROR (Status)) { + return Status; + } + + // Delete the detached node. + Status = AmlDeleteTree (NameOpIdNode); + } + + return Status; +} + +/** Fixup the Serial Port _CRS values (BaseAddress, ...). + + @param [in] RootNodeHandle Pointer to the root of an AML tree. + @param [in] SerialPortInfo Pointer to a Serial Port Information + structure. + Get the Serial Port 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 +FixupCrs ( + IN OUT AML_ROOT_NODE_HANDLE RootNodeHandle, + IN CONST CM_ARM_SERIAL_PORT_INFO * SerialPortInfo + ) +{ + EFI_STATUS Status; + AML_OBJECT_NODE_HANDLE NameOpCrsNode; + AML_DATA_NODE_HANDLE QWordRdNode; + AML_DATA_NODE_HANDLE InterruptRdNode; + + // Get the "_CRS" object defined by the "Name ()" statement. + Status = AmlFindNode ( + RootNodeHandle, + "\\_SB_.COM0._CRS", + &NameOpCrsNode + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // Get the first Rd node in the "_CRS" object. + Status = AmlNameOpCrsGetFirstRdNode (NameOpCrsNode, &QWordRdNode); + if (EFI_ERROR (Status)) { + return Status; + } + + if (QWordRdNode == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Update the Serial Port base address and length. + Status = AmlUpdateRdQWord ( + QWordRdNode, + SerialPortInfo->BaseAddress, + ((SerialPortInfo->BaseAddressLength < MIN_UART_ADDRESS_LENGTH) ? + MIN_UART_ADDRESS_LENGTH: SerialPortInfo->BaseAddressLength) + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // Get the Interrupt node. + // It is the second Resource Data element in the NameOpCrsNode's + // variable list of arguments. + Status = AmlNameOpCrsGetNextRdNode (QWordRdNode, &InterruptRdNode); + if (EFI_ERROR (Status)) { + return Status; + } + + if (InterruptRdNode == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Update the interrupt number. + return AmlUpdateRdInterrupt (InterruptRdNode, SerialPortInfo->Interrupt); +} + +/** Fixup the Serial Port device name. + + @param [in] RootNodeHandle Pointer to the root of an AML tree. + @param [in] SerialPortInfo Pointer to a Serial Port Information + structure. + Get the Serial Port Information from there. + @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 +FixupName ( + IN OUT AML_ROOT_NODE_HANDLE RootNodeHandle, + IN CONST CM_ARM_SERIAL_PORT_INFO * SerialPortInfo, + 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_.COM0", &DeviceNode); + if (EFI_ERROR (Status)) { + return Status; + } + + // Update the Device's name. + return AmlDeviceOpUpdateName (DeviceNode, (CHAR8*)Name); +} + +/** Fixup the Serial Port Information 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] SerialPortInfo Pointer to a Serial Port Information + structure. + Get the Serial Port Information from there. + @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 Serial Port. + @param [out] Table If success, contains the serialized + SSDT table. + + @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 +FixupSerialPortInfo ( + IN OUT AML_ROOT_NODE_HANDLE RootNodeHandle, + IN CONST CM_ARM_SERIAL_PORT_INFO * SerialPortInfo, + IN CONST CHAR8 * Name, + IN CONST UINT64 Uid, + OUT EFI_ACPI_DESCRIPTION_HEADER ** Table + ) +{ + EFI_STATUS Status; + + ASSERT (RootNodeHandle != NULL); + ASSERT (SerialPortInfo != NULL); + ASSERT (Name != NULL); + ASSERT (Table != NULL); + + // Fixup the _UID, _HID and _CID values. + Status = FixupIds (RootNodeHandle, Uid, SerialPortInfo); + if (EFI_ERROR (Status)) { + return Status; + } + + // Fixup the _CRS values. + Status = FixupCrs (RootNodeHandle, SerialPortInfo); + if (EFI_ERROR (Status)) { + return Status; + } + + // Fixup the serial-port name. + // This MUST be done at the end, otherwise AML paths won't be valid anymore. + return FixupName (RootNodeHandle, SerialPortInfo, Name); +} + +/** Free an SSDT table previously created by + the BuildSsdtSerialTable function. + + @param [in] Table Pointer to a SSDT table allocated by + the BuildSsdtSerialTable function. + + @retval EFI_SUCCESS Success. +**/ +EFI_STATUS +EFIAPI +FreeSsdtSerialPortTable ( + IN EFI_ACPI_DESCRIPTION_HEADER * Table + ) +{ + ASSERT (Table != NULL); + FreePool (Table); + return EFI_SUCCESS; +} + +/** Build a SSDT table describing the input serial port. + + The table created by this function must be freed by FreeSsdtSerialTable. + + @param [in] AcpiTableInfo Pointer to the ACPI table information. + @param [in] SerialPortInfo Serial port to describe in the SSDT table. + @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 Serial Port. + @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 +BuildSsdtSerialPortTable ( + IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * AcpiTableInfo, + IN CONST CM_ARM_SERIAL_PORT_INFO * SerialPortInfo, + IN CONST CHAR8 * Name, + IN CONST UINT64 Uid, + OUT EFI_ACPI_DESCRIPTION_HEADER ** Table + ) +{ + EFI_STATUS Status; + EFI_STATUS Status1; + AML_ROOT_NODE_HANDLE RootNodeHandle; + + ASSERT (AcpiTableInfo != NULL); + ASSERT (SerialPortInfo != NULL); + ASSERT (Name != NULL); + ASSERT (Table != NULL); + + // Validate the Serial Port Info. + Status = ValidateSerialPortInfo (SerialPortInfo, 1); + if (EFI_ERROR (Status)) { + return Status; + } + + // Parse the SSDT Serial Port Template. + Status = AmlParseDefinitionBlock ( + (EFI_ACPI_DESCRIPTION_HEADER*)ssdtserialporttemplate_aml_code, + &RootNodeHandle + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SSDT-SERIAL-PORT-FIXUP:" + " Failed to parse SSDT Serial Port Template. Status = %r\n", + Status + )); + return Status; + } + + // Fixup the template values. + Status = FixupSerialPortInfo ( + RootNodeHandle, + SerialPortInfo, + Name, + Uid, + Table + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SSDT-SERIAL-PORT-FIXUP: Failed to fixup SSDT Serial Port Table." + " Status = %r\n", + Status + )); + goto exit_handler; + } + + // Serialize the tree. + Status = AmlSerializeDefinitionBlock ( + RootNodeHandle, + Table + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SSDT-SERIAL-PORT-FIXUP: Failed to Serialize SSDT Table Data." + " Status = %r\n", + Status + )); + } + +exit_handler: + // Cleanup + if (RootNodeHandle != NULL) { + Status1 = AmlDeleteTree (RootNodeHandle); + if (EFI_ERROR (Status1)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SSDT-SERIAL-PORT-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; +} diff --git a/DynamicTablesPkg/Library/Common/SsdtSerialPortFixupLib/SsdtSerialPortFixupLib.inf b/DynamicTablesPkg/Library/Common/SsdtSerialPortFixupLib/SsdtSerialPortFixupLib.inf new file mode 100644 index 0000000000..af3d404393 --- /dev/null +++ b/DynamicTablesPkg/Library/Common/SsdtSerialPortFixupLib/SsdtSerialPortFixupLib.inf @@ -0,0 +1,30 @@ +## @file +# SSDT Serial Port fixup Library +# +# Copyright (c) 2020, Arm Limited. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x0001001B + BASE_NAME = DynamicSsdtSerialPortFixupLib + FILE_GUID = AC5978CC-5B62-4466-AD04-23644C2C38C2 + VERSION_STRING = 1.0 + MODULE_TYPE = DXE_DRIVER + LIBRARY_CLASS = SsdtSerialPortFixupLib + +[Sources] + SsdtSerialPortFixupLib.c + SsdtSerialPortTemplate.asl + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + EmbeddedPkg/EmbeddedPkg.dec + DynamicTablesPkg/DynamicTablesPkg.dec + +[LibraryClasses] + AmlLib + BaseLib + diff --git a/DynamicTablesPkg/Library/Common/SsdtSerialPortFixupLib/SsdtSerialPortTemplate.asl b/DynamicTablesPkg/Library/Common/SsdtSerialPortFixupLib/SsdtSerialPortTemplate.asl new file mode 100644 index 0000000000..fcae2160ac --- /dev/null +++ b/DynamicTablesPkg/Library/Common/SsdtSerialPortFixupLib/SsdtSerialPortTemplate.asl @@ -0,0 +1,60 @@ +/** @file + SSDT Serial Template + + Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - Arm Server Base Boot Requirements (SBBR), s4.2.1.8 "SPCR". + + @par Glossary: + - {template} - Data fixed up using AML Fixup APIs. +**/ + +DefinitionBlock ("SsdtSerialPortTemplate.aml", "SSDT", 2, "ARMLTD", "SERIAL", 1) { + Scope (_SB) { + // UART PL011 + Device (COM0) { // {template} + Name (_UID, 0x0) // {template} + Name (_HID, "HID0000") // {template} + Name (_CID, "CID0000") // {template} + + Method(_STA) { + Return(0xF) + } + + Name (_CRS, ResourceTemplate() { + QWordMemory ( + , // ResourceUsage + , // Decode + , // IsMinFixed + , // IsMaxFixed + , // Cacheable + ReadWrite, // ReadAndWrite + 0x0, // AddressGranularity + 0xA0000000, // AddressMinimum // {template} + 0xAFFFFFFF, // AddressMaximum // {template} + 0, // AddressTranslation + 0x10000000, // RangeLength // {template} + , // ResourceSourceIndex + , // ResourceSource + , // DescriptorName + , // MemoryRangeType + // TranslationType + ) // QWordMemory + Interrupt ( + ResourceConsumer, // ResourceUsage + Level, // EdgeLevel + ActiveHigh, // ActiveLevel + Exclusive, // Shared + , // ResourceSourceIndex + , // ResourceSource + // DescriptorName + ) { + 0xA5 // {template} + } // Interrupt + }) // Name + } // Device + } // Scope (_SB) +}