diff options
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtSerialPortLibArm/SsdtSerialPortGenerator.c')
-rw-r--r-- | src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtSerialPortLibArm/SsdtSerialPortGenerator.c | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtSerialPortLibArm/SsdtSerialPortGenerator.c b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtSerialPortLibArm/SsdtSerialPortGenerator.c new file mode 100644 index 00000000..0af74613 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtSerialPortLibArm/SsdtSerialPortGenerator.c @@ -0,0 +1,371 @@ +/** @file + SSDT Serial Port Table Generator. + + Copyright (c) 2020, Arm Limited. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include <IndustryStandard/DebugPort2Table.h> +#include <Library/AcpiLib.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Protocol/AcpiTable.h> + +// Module specific include files. +#include <AcpiTableGenerator.h> +#include <ConfigurationManagerObject.h> +#include <ConfigurationManagerHelper.h> +#include <Library/SsdtSerialPortFixupLib.h> +#include <Library/TableHelperLib.h> +#include <Protocol/ConfigurationManagerProtocol.h> + +/** ARM standard SSDT Serial Port Table Generator + + Constructs SSDT tables describing serial ports (other than the serial ports + used by the SPCR or DBG2 tables). + +Requirements: + The following Configuration Manager Object(s) are required by + this Generator: + - EArmObjSerialPortInfo +*/ + +/** This macro expands to a function that retrieves the Serial-port + information from the Configuration Manager. +*/ +GET_OBJECT_LIST ( + EObjNameSpaceArm, + EArmObjSerialPortInfo, + CM_ARM_SERIAL_PORT_INFO + ); + +/** Starting value for the UID to represent the serial ports. + Note: The UID 0 and 1 are reserved for use by DBG2 port and SPCR + respectively. So, the UIDs for serial ports for general use + start at 2. +*/ +#define SERIAL_PORT_START_UID 2 + +/** Maximum serial ports supported by this generator. + This generator supports a maximum of 14 (16 - 2) serial ports. + The -2 here reflects the reservation for serial ports for the DBG2 + and SPCR ports regardless of whether the DBG2 or SPCR port is enabled. + Note: This is not a hard limitation and can be extended if needed. + Corresponding changes would be needed to support the Name and + UID fields describing the serial port. + +*/ +#define MAX_SERIAL_PORTS_SUPPORTED 14 + +/** Free any resources allocated for constructing the tables. + + @param [in] This Pointer to the ACPI table generator. + @param [in] AcpiTableInfo Pointer to the ACPI Table Info. + @param [in] CfgMgrProtocol Pointer to the Configuration Manager + Protocol Interface. + @param [in, out] Table Pointer to 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 +EFIAPI +FreeSsdtSerialPortTableEx ( + 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 + ) +{ + EFI_STATUS Status; + EFI_ACPI_DESCRIPTION_HEADER ** TableList; + UINTN Index; + + ASSERT (This != NULL); + ASSERT (AcpiTableInfo != NULL); + ASSERT (CfgMgrProtocol != NULL); + ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID); + ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature); + + if ((Table == NULL) || + (*Table == NULL) || + (TableCount == 0)) { + DEBUG ((DEBUG_ERROR, "ERROR: SSDT-SERIAL-PORT: Invalid Table Pointer\n")); + return EFI_INVALID_PARAMETER; + } + + TableList = *Table; + + for (Index = 0; Index < TableCount; Index++) { + if ((TableList[Index] != NULL) && + (TableList[Index]->Signature == + EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE)) { + Status = FreeSsdtSerialPortTable (TableList[Index]); + } else { + Status = EFI_INVALID_PARAMETER; + } + + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SSDT-SERIAL-PORT: Could not free SSDT table at index %d." + " Status = %r\n", + Index, + Status + )); + return Status; + } + } //for + + // Free the table list. + FreePool (*Table); + + return EFI_SUCCESS; +} + +/** Construct SSDT tables describing serial-ports. + + This function invokes the Configuration Manager protocol interface + to get the required hardware information for generating the ACPI + table. + + If this function allocates any resources then they must be freed + in the FreeXXXXTableResourcesEx function. + + @param [in] This Pointer to the ACPI table generator. + @param [in] AcpiTableInfo Pointer to the ACPI table information. + @param [in] CfgMgrProtocol Pointer to the Configuration Manager + Protocol interface. + @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_BAD_BUFFER_SIZE The size returned by the Configuration + Manager is less than the Object size for + the requested object. + @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. + @retval EFI_UNSUPPORTED Unsupported configuration. +**/ +STATIC +EFI_STATUS +EFIAPI +BuildSsdtSerialPortTableEx ( + IN CONST ACPI_TABLE_GENERATOR * This, + IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo, + IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol, + OUT EFI_ACPI_DESCRIPTION_HEADER *** Table, + OUT UINTN * CONST TableCount + ) +{ + EFI_STATUS Status; + CM_ARM_SERIAL_PORT_INFO * SerialPortInfo; + UINT32 SerialPortCount; + UINTN Index; + CHAR8 NewName[5]; + UINT64 Uid; + EFI_ACPI_DESCRIPTION_HEADER ** TableList; + + ASSERT (This != NULL); + ASSERT (AcpiTableInfo != NULL); + ASSERT (CfgMgrProtocol != NULL); + ASSERT (Table != NULL); + ASSERT (TableCount != NULL); + ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID); + ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature); + + *Table = NULL; + + Status = GetEArmObjSerialPortInfo ( + CfgMgrProtocol, + CM_NULL_TOKEN, + &SerialPortInfo, + &SerialPortCount + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SSDT-SERIAL-PORT: Failed to get serial port information." + " Status = %r\n", + Status + )); + return Status; + } + + if (SerialPortCount > MAX_SERIAL_PORTS_SUPPORTED) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SSDT-SERIAL-PORT: Too many serial ports: %d." + " Maximum serial ports supported = %d.\n", + SerialPortCount, + MAX_SERIAL_PORTS_SUPPORTED + )); + return EFI_INVALID_PARAMETER; + } + + // Validate the SerialPort info. + Status = ValidateSerialPortInfo (SerialPortInfo, SerialPortCount); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SSDT-SERIAL-PORT: Invalid serial port information. Status = %r\n", + Status + )); + return Status; + } + + // Allocate a table to store pointers to the SSDT tables. + TableList = (EFI_ACPI_DESCRIPTION_HEADER**) + AllocateZeroPool ( + (sizeof (EFI_ACPI_DESCRIPTION_HEADER*) * SerialPortCount) + ); + if (TableList == NULL) { + Status = EFI_OUT_OF_RESOURCES; + DEBUG (( + DEBUG_ERROR, + "ERROR: SSDT-SERIAL-PORT: Failed to allocate memory for Table List." + " Status = %r\n", + Status + )); + return Status; + } + + // Setup the table list early so that that appropriate cleanup + // can be done in case of failure. + *Table = TableList; + + NewName[0] = 'C'; + NewName[1] = 'O'; + NewName[2] = 'M'; + NewName[4] = '\0'; + for (Index = 0; Index < SerialPortCount; Index++) { + Uid = SERIAL_PORT_START_UID + Index; + NewName[3] = AsciiFromHex ((UINT8)(Uid)); + + // Build a SSDT table describing the serial port. + Status = BuildSsdtSerialPortTable ( + AcpiTableInfo, + &SerialPortInfo[Index], + NewName, + Uid, + &TableList[Index] + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SSDT-SERIAL-PORT: Failed to build associated SSDT table." + " Status = %r\n", + Status + )); + goto error_handler; + } + + // Increment the table count here so that appropriate cleanup + // can be done in case of failure. + *TableCount += 1; + } // for + +error_handler: + // Note: Table list and Serial port count has been setup. The + // error handler does nothing here as the framework will invoke + // FreeSsdtSerialPortTableEx() even on failure. + return Status; +} + +/** This macro defines the SSDT Serial Port Table Generator revision. +*/ +#define SSDT_SERIAL_GENERATOR_REVISION CREATE_REVISION (1, 0) + +/** The interface for the SSDT Serial Port Table Generator. +*/ +STATIC +CONST +ACPI_TABLE_GENERATOR SsdtSerialPortGenerator = { + // Generator ID + CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdSsdtSerialPort), + // Generator Description + L"ACPI.STD.SSDT.SERIAL.PORT.GENERATOR", + // ACPI Table Signature + EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE, + // ACPI Table Revision - Unused + 0, + // Minimum ACPI Table Revision - Unused + 0, + // Creator ID + TABLE_GENERATOR_CREATOR_ID_ARM, + // Creator Revision + SSDT_SERIAL_GENERATOR_REVISION, + // Build table function. Use the extended version instead. + NULL, + // Free table function. Use the extended version instead. + NULL, + // Extended Build table function. + BuildSsdtSerialPortTableEx, + // Extended free function. + FreeSsdtSerialPortTableEx +}; + +/** Register the Generator with the ACPI Table Factory. + + @param [in] ImageHandle The handle to the image. + @param [in] SystemTable Pointer to the System Table. + + @retval EFI_SUCCESS The Generator is registered. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_ALREADY_STARTED The Generator for the Table ID + is already registered. +**/ +EFI_STATUS +EFIAPI +AcpiSsdtSerialPortLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE * SystemTable + ) +{ + EFI_STATUS Status; + Status = RegisterAcpiTableGenerator (&SsdtSerialPortGenerator); + DEBUG (( + DEBUG_INFO, + "SSDT-SERIAL-PORT: Register Generator. Status = %r\n", + Status + )); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** Deregister the Generator from the ACPI Table Factory. + + @param [in] ImageHandle The handle to the image. + @param [in] SystemTable Pointer to the System Table. + + @retval EFI_SUCCESS The Generator is deregistered. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_NOT_FOUND The Generator is not registered. +**/ +EFI_STATUS +EFIAPI +AcpiSsdtSerialPortLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE * SystemTable + ) +{ + EFI_STATUS Status; + Status = DeregisterAcpiTableGenerator (&SsdtSerialPortGenerator); + DEBUG (( + DEBUG_INFO, + "SSDT-SERIAL-PORT: Deregister Generator. Status = %r\n", + Status + )); + ASSERT_EFI_ERROR (Status); + return Status; +} |