|
@@ -0,0 +1,367 @@
|
|
|
+/** @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->TableGeneratorId == This->GeneratorID);
|
|
|
+ ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);
|
|
|
+ ASSERT (CfgMgrProtocol != NULL);
|
|
|
+ ASSERT (AcpiTableInfo != NULL);
|
|
|
+
|
|
|
+ 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[] = "COMx";
|
|
|
+ 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;
|
|
|
+
|
|
|
+ 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;
|
|
|
+}
|