--- /dev/null
+/** @file\r
+ MCFG Table Generator\r
+\r
+ Copyright (c) 2017 - 2019, ARM Limited. All rights reserved.\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+ @par Reference(s):\r
+ - PCI Firmware Specification - Revision 3.2, January 26, 2015.\r
+\r
+**/\r
+\r
+#include <IndustryStandard/MemoryMappedConfigurationSpaceAccessTable.h>\r
+#include <Library/AcpiLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Protocol/AcpiTable.h>\r
+\r
+// Module specific include files.\r
+#include <AcpiTableGenerator.h>\r
+#include <ConfigurationManagerObject.h>\r
+#include <ConfigurationManagerHelper.h>\r
+#include <Library/TableHelperLib.h>\r
+#include <Protocol/ConfigurationManagerProtocol.h>\r
+\r
+/** ARM standard MCFG Generator\r
+\r
+Requirements:\r
+ The following Configuration Manager Object(s) are required by\r
+ this Generator:\r
+ - EArmObjPciConfigSpaceInfo\r
+*/\r
+\r
+#pragma pack(1)\r
+\r
+/** This typedef is used to shorten the name of the MCFG Table\r
+ header structure.\r
+*/\r
+typedef\r
+ EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE_HEADER\r
+ MCFG_TABLE;\r
+\r
+/** This typedef is used to shorten the name of the Enhanced\r
+ Configuration Space address structure.\r
+*/\r
+typedef\r
+ EFI_ACPI_MEMORY_MAPPED_ENHANCED_CONFIGURATION_SPACE_BASE_ADDRESS_ALLOCATION_STRUCTURE\r
+ MCFG_CFG_SPACE_ADDR;\r
+\r
+#pragma pack()\r
+\r
+/** Retrieve the PCI Configuration Space Information.\r
+*/\r
+GET_OBJECT_LIST (\r
+ EObjNameSpaceArm,\r
+ EArmObjPciConfigSpaceInfo,\r
+ CM_ARM_PCI_CONFIG_SPACE_INFO\r
+ );\r
+\r
+/** Add the PCI Enhanced Configuration Space Information to the MCFG Table.\r
+\r
+ @param [in] Mcfg Pointer to MCFG Table.\r
+ @param [in] PciCfgSpaceOffset Offset for the PCI Configuration Space\r
+ Info structure in the MCFG Table.\r
+ @param [in] PciCfgSpaceInfoList Pointer to the PCI Configuration Space\r
+ Info List.\r
+ @param [in] PciCfgSpaceCount Count of PCI Configuration Space Info.\r
+**/\r
+STATIC\r
+VOID\r
+AddPciConfigurationSpaceList (\r
+ IN MCFG_TABLE * CONST Mcfg,\r
+ IN CONST UINT32 PciCfgSpaceOffset,\r
+ IN CONST CM_ARM_PCI_CONFIG_SPACE_INFO * PciCfgSpaceInfoList,\r
+ IN UINT32 PciCfgSpaceCount\r
+)\r
+{\r
+ MCFG_CFG_SPACE_ADDR * PciCfgSpace;\r
+\r
+ ASSERT (Mcfg != NULL);\r
+ ASSERT (PciCfgSpaceInfoList != NULL);\r
+\r
+ PciCfgSpace = (MCFG_CFG_SPACE_ADDR *)((UINT8*)Mcfg + PciCfgSpaceOffset);\r
+\r
+ while (PciCfgSpaceCount-- != 0) {\r
+ // Add PCI Configuration Space entry\r
+ PciCfgSpace->BaseAddress = PciCfgSpaceInfoList->BaseAddress;\r
+ PciCfgSpace->PciSegmentGroupNumber =\r
+ PciCfgSpaceInfoList->PciSegmentGroupNumber;\r
+ PciCfgSpace->StartBusNumber = PciCfgSpaceInfoList->StartBusNumber;\r
+ PciCfgSpace->EndBusNumber = PciCfgSpaceInfoList->EndBusNumber;\r
+ PciCfgSpace->Reserved = EFI_ACPI_RESERVED_DWORD;\r
+ PciCfgSpace++;\r
+ PciCfgSpaceInfoList++;\r
+ }\r
+}\r
+\r
+/** Construct the MCFG ACPI table.\r
+\r
+ This function invokes the Configuration Manager protocol interface\r
+ to get the required hardware information for generating the ACPI\r
+ table.\r
+\r
+ If this function allocates any resources then they must be freed\r
+ in the FreeXXXXTableResources function.\r
+\r
+ @param [in] This Pointer to the table generator.\r
+ @param [in] AcpiTableInfo Pointer to the ACPI Table Info.\r
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
+ Protocol Interface.\r
+ @param [out] Table Pointer to the constructed ACPI Table.\r
+\r
+ @retval EFI_SUCCESS Table generated successfully.\r
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
+ @retval EFI_NOT_FOUND The required object was not found.\r
+ @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration\r
+ Manager is less than the Object size for the\r
+ requested object.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+BuildMcfgTable (\r
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,\r
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,\r
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
+ OUT EFI_ACPI_DESCRIPTION_HEADER ** CONST Table\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 TableSize;\r
+ UINT32 ConfigurationSpaceCount;\r
+ CM_ARM_PCI_CONFIG_SPACE_INFO * PciConfigSpaceInfoList;\r
+ MCFG_TABLE * Mcfg;\r
+\r
+ ASSERT (This != NULL);\r
+ ASSERT (AcpiTableInfo != NULL);\r
+ ASSERT (CfgMgrProtocol != NULL);\r
+ ASSERT (Table != NULL);\r
+ ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);\r
+ ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);\r
+\r
+ if ((AcpiTableInfo->AcpiTableRevision < This->MinAcpiTableRevision) ||\r
+ (AcpiTableInfo->AcpiTableRevision > This->AcpiTableRevision)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: MCFG: Requested table revision = %d, is not supported."\r
+ "Supported table revision: Minimum = %d, Maximum = %d\n",\r
+ AcpiTableInfo->AcpiTableRevision,\r
+ This->MinAcpiTableRevision,\r
+ This->AcpiTableRevision\r
+ ));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *Table = NULL;\r
+ Status = GetEArmObjPciConfigSpaceInfo (\r
+ CfgMgrProtocol,\r
+ CM_NULL_TOKEN,\r
+ &PciConfigSpaceInfoList,\r
+ &ConfigurationSpaceCount\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR,\r
+ "ERROR: MCFG: Failed to get PCI Configuration Space Information." \\r
+ " Status = %r\n",\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+\r
+ if (ConfigurationSpaceCount == 0) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: MCFG: Configuration Space Count = %d\n",\r
+ ConfigurationSpaceCount\r
+ ));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ ASSERT (ConfigurationSpaceCount != 0);\r
+ goto error_handler;\r
+ }\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "MCFG: Configuration Space Count = %d\n",\r
+ ConfigurationSpaceCount\r
+ ));\r
+\r
+ // Calculate the MCFG Table Size\r
+ TableSize = sizeof (MCFG_TABLE) +\r
+ ((sizeof (MCFG_CFG_SPACE_ADDR) * ConfigurationSpaceCount));\r
+\r
+ *Table = (EFI_ACPI_DESCRIPTION_HEADER*)AllocateZeroPool (TableSize);\r
+ if (*Table == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: MCFG: Failed to allocate memory for MCFG Table, Size = %d," \\r
+ " Status = %r\n",\r
+ TableSize,\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+\r
+ Mcfg = (MCFG_TABLE*)*Table;\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "MCFG: Mcfg = 0x%p TableSize = 0x%x\n",\r
+ Mcfg,\r
+ TableSize\r
+ ));\r
+\r
+ Status = AddAcpiHeader (\r
+ CfgMgrProtocol,\r
+ This,\r
+ &Mcfg->Header,\r
+ AcpiTableInfo->AcpiTableRevision,\r
+ TableSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "ERROR: MCFG: Failed to add ACPI header. Status = %r\n",\r
+ Status\r
+ ));\r
+ goto error_handler;\r
+ }\r
+\r
+ Mcfg->Reserved = EFI_ACPI_RESERVED_QWORD;\r
+\r
+ AddPciConfigurationSpaceList (\r
+ Mcfg,\r
+ sizeof (MCFG_TABLE),\r
+ PciConfigSpaceInfoList,\r
+ ConfigurationSpaceCount\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+\r
+error_handler:\r
+ if (*Table != NULL) {\r
+ FreePool (*Table);\r
+ *Table = NULL;\r
+ }\r
+ return Status;\r
+}\r
+\r
+/** Free any resources allocated for constructing the MCFG\r
+\r
+ @param [in] This Pointer to the table generator.\r
+ @param [in] AcpiTableInfo Pointer to the ACPI Table Info.\r
+ @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
+ Protocol Interface.\r
+ @param [in, out] Table Pointer to the ACPI Table.\r
+\r
+ @retval EFI_SUCCESS The resources were freed successfully.\r
+ @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+FreeMcfgTableResources (\r
+ IN CONST ACPI_TABLE_GENERATOR * CONST This,\r
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,\r
+ IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
+ IN OUT EFI_ACPI_DESCRIPTION_HEADER ** CONST Table\r
+ )\r
+{\r
+ ASSERT (This != NULL);\r
+ ASSERT (AcpiTableInfo != NULL);\r
+ ASSERT (CfgMgrProtocol != NULL);\r
+ ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);\r
+ ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);\r
+\r
+ if ((Table == NULL) || (*Table == NULL)) {\r
+ DEBUG ((DEBUG_ERROR, "ERROR: MCFG: Invalid Table Pointer\n"));\r
+ ASSERT ((Table != NULL) && (*Table != NULL));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ FreePool (*Table);\r
+ *Table = NULL;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/** This macro defines the MCFG Table Generator revision.\r
+*/\r
+#define MCFG_GENERATOR_REVISION CREATE_REVISION (1, 0)\r
+\r
+/** The interface for the MCFG Table Generator.\r
+*/\r
+STATIC\r
+CONST\r
+ACPI_TABLE_GENERATOR McfgGenerator = {\r
+ // Generator ID\r
+ CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdMcfg),\r
+ // Generator Description\r
+ L"ACPI.STD.MCFG.GENERATOR",\r
+ // ACPI Table Signature\r
+ EFI_ACPI_6_2_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE,\r
+ // ACPI Table Revision supported by this Generator\r
+ EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_SPACE_ACCESS_TABLE_REVISION,\r
+ // Minimum supported ACPI Table Revision\r
+ EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_SPACE_ACCESS_TABLE_REVISION,\r
+ // Creator ID\r
+ TABLE_GENERATOR_CREATOR_ID_ARM,\r
+ // Creator Revision\r
+ MCFG_GENERATOR_REVISION,\r
+ // Build Table function\r
+ BuildMcfgTable,\r
+ // Free Resource function\r
+ FreeMcfgTableResources,\r
+ // Extended build function not needed\r
+ NULL,\r
+ // Extended build function not implemented by the generator.\r
+ // Hence extended free resource function is not required.\r
+ NULL\r
+};\r
+\r
+/** Register the Generator with the ACPI Table Factory.\r
+\r
+ @param [in] ImageHandle The handle to the image.\r
+ @param [in] SystemTable Pointer to the System Table.\r
+\r
+ @retval EFI_SUCCESS The Generator is registered.\r
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
+ @retval EFI_ALREADY_STARTED The Generator for the Table ID\r
+ is already registered.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AcpiMcfgLibConstructor (\r
+ IN CONST EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE * CONST SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ Status = RegisterAcpiTableGenerator (&McfgGenerator);\r
+ DEBUG ((DEBUG_INFO, "MCFG: Register Generator. Status = %r\n", Status));\r
+ ASSERT_EFI_ERROR (Status);\r
+ return Status;\r
+}\r
+\r
+/** Deregister the Generator from the ACPI Table Factory.\r
+\r
+ @param [in] ImageHandle The handle to the image.\r
+ @param [in] SystemTable Pointer to the System Table.\r
+\r
+ @retval EFI_SUCCESS The Generator is deregistered.\r
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
+ @retval EFI_NOT_FOUND The Generator is not registered.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AcpiMcfgLibDestructor (\r
+ IN CONST EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE * CONST SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ Status = DeregisterAcpiTableGenerator (&McfgGenerator);\r
+ DEBUG ((DEBUG_INFO, "MCFG: Deregister Generator. Status = %r\n", Status));\r
+ ASSERT_EFI_ERROR (Status);\r
+ return Status;\r
+}\r