| /** @file | |
| SMBIOS Table Builder. | |
| Copyright (c) 2017 - 2019, ARM Limited. All rights reserved. | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include <Library/DebugLib.h> | |
| #include <Library/UefiLib.h> | |
| #include <Library/PcdLib.h> | |
| #include <Library/UefiBootServicesTableLib.h> | |
| #include <Protocol/Smbios.h> | |
| #include <Library/BaseMemoryLib.h> | |
| // Module specific include files. | |
| #include <ConfigurationManagerObject.h> | |
| #include <ConfigurationManagerHelper.h> | |
| #include <DeviceTreeTableGenerator.h> | |
| #include <Library/TableHelperLib.h> | |
| #include <Protocol/ConfigurationManagerProtocol.h> | |
| #include <Protocol/DynamicTableFactoryProtocol.h> | |
| #include <SmbiosTableGenerator.h> | |
| #include <SmbiosTableDispatcher.h> | |
| /** This macro expands to a function that retrieves the SMBIOS Table | |
| List from the Configuration Manager. | |
| */ | |
| GET_OBJECT_LIST ( | |
| EObjNameSpaceStandard, | |
| EStdObjSmbiosTableList, | |
| CM_STD_OBJ_SMBIOS_TABLE_INFO | |
| ) | |
| /** A helper function to build and install an SMBIOS table. | |
| This is a helper function that invokes the Table generator interface | |
| for building an SMBIOS table. It uses the SmbiosProtocol to install the | |
| table, then frees the resources allocated for generating it. | |
| @param [in] TableFactoryProtocol Pointer to the Table Factory Protocol | |
| interface. | |
| @param [in] CfgMgrProtocol Pointer to the Configuration Manager | |
| Protocol Interface. | |
| @param [in] Generator Pointer to the SMBIOS table Generator. | |
| @param [in] SmbiosProtocol Pointer to the SMBIOS protocol. | |
| @param [in] SmbiosTableInfo Pointer to the SMBIOS table Info. | |
| @retval EFI_SUCCESS Success. | |
| @retval EFI_INVALID_PARAMETER A parameter is invalid. | |
| @retval EFI_NOT_FOUND Required object is not found. | |
| @retval EFI_BAD_BUFFER_SIZE Size returned by the Configuration Manager | |
| is less than the Object size for the | |
| requested object. | |
| **/ | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| BuildAndInstallSingleSmbiosTable ( | |
| IN CONST EDKII_DYNAMIC_TABLE_FACTORY_PROTOCOL *CONST TableFactoryProtocol, | |
| IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol, | |
| IN CONST SMBIOS_TABLE_GENERATOR *CONST Generator, | |
| IN EFI_SMBIOS_PROTOCOL *SmbiosProtocol, | |
| IN CM_STD_OBJ_SMBIOS_TABLE_INFO *CONST SmbiosTableInfo | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_STATUS Status1; | |
| SMBIOS_STRUCTURE *SmbiosTable; | |
| CM_OBJECT_TOKEN CmObjToken; | |
| EFI_SMBIOS_HANDLE TableHandle; | |
| SmbiosTable = NULL; | |
| Status = Generator->BuildSmbiosTable ( | |
| Generator, | |
| TableFactoryProtocol, | |
| SmbiosTableInfo, | |
| CfgMgrProtocol, | |
| &SmbiosTable, | |
| &CmObjToken | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: Failed to Build Table." \ | |
| " TableGeneratorId = 0x%x. Status = %r\n", | |
| SmbiosTableInfo->TableGeneratorId, | |
| Status | |
| )); | |
| // Free any allocated resources. | |
| goto exit_handler; | |
| } | |
| if (SmbiosTable == NULL) { | |
| Status = EFI_NOT_FOUND; | |
| goto exit_handler; | |
| } | |
| TableHandle = SMBIOS_HANDLE_PI_RESERVED; | |
| // Install SMBIOS table | |
| Status = SmbiosProtocol->Add ( | |
| SmbiosProtocol, | |
| NULL, | |
| &TableHandle, | |
| SmbiosTable | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: Failed to Install SMBIOS Table. Status = %r\n", | |
| Status | |
| )); | |
| // Free any allocated resources. | |
| goto exit_handler; | |
| } | |
| Status = TableFactoryProtocol->AddSmbiosHandle ( | |
| SmbiosProtocol, | |
| &TableHandle, | |
| CmObjToken, | |
| SmbiosTableInfo->TableGeneratorId | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: Failed to Add SMBIOS Handle. Status = %r\n", | |
| Status | |
| )); | |
| // Free any allocated resources. | |
| goto exit_handler; | |
| } | |
| DEBUG (( | |
| DEBUG_INFO, | |
| "INFO: SMBIOS Table installed. Status = %r\n", | |
| Status | |
| )); | |
| exit_handler: | |
| // Free any resources allocated for generating the tables. | |
| if (Generator->FreeTableResources != NULL) { | |
| Status1 = Generator->FreeTableResources ( | |
| Generator, | |
| TableFactoryProtocol, | |
| SmbiosTableInfo, | |
| CfgMgrProtocol, | |
| &SmbiosTable | |
| ); | |
| if (EFI_ERROR (Status1)) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: Failed to Free Table Resources." \ | |
| "TableGeneratorId = 0x%x. Status = %r\n", | |
| SmbiosTableInfo->TableGeneratorId, | |
| Status1 | |
| )); | |
| } | |
| // Return the first error status in case of failure | |
| if (!EFI_ERROR (Status)) { | |
| Status = Status1; | |
| } | |
| } | |
| return Status; | |
| } | |
| /** A helper function to build and install multiple SMBIOS tables. | |
| This is a helper function that invokes the Table generator interface | |
| for building SMBIOS tables. It uses the SmbiosProtocol to install the | |
| tables, then frees the resources allocated for generating it. | |
| @param [in] TableFactoryProtocol Pointer to the Table Factory Protocol | |
| interface. | |
| @param [in] CfgMgrProtocol Pointer to the Configuration Manager | |
| Protocol Interface. | |
| @param [in] Generator Pointer to the SmbiosTable generator. | |
| @param [in] SmbiosProtocol Pointer to the Smbios protocol. | |
| @param [in] SmbiosTableInfo Pointer to the SMBIOS table Info. | |
| @retval EFI_SUCCESS Success. | |
| @retval EFI_INVALID_PARAMETER A parameter is invalid. | |
| @retval EFI_NOT_FOUND Required object is not found. | |
| @retval EFI_BAD_BUFFER_SIZE Size returned by the Configuration Manager | |
| is less than the Object size for the | |
| requested object. | |
| **/ | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| BuildAndInstallMultipleSmbiosTables ( | |
| IN CONST EDKII_DYNAMIC_TABLE_FACTORY_PROTOCOL *CONST TableFactoryProtocol, | |
| IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol, | |
| IN CONST SMBIOS_TABLE_GENERATOR *CONST Generator, | |
| IN EFI_SMBIOS_PROTOCOL *SmbiosProtocol, | |
| IN CM_STD_OBJ_SMBIOS_TABLE_INFO *CONST SmbiosTableInfo | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_STATUS Status1; | |
| SMBIOS_STRUCTURE **SmbiosTable; | |
| CM_OBJECT_TOKEN *CmObjToken; | |
| EFI_SMBIOS_HANDLE TableHandle; | |
| UINTN TableCount; | |
| UINTN Index; | |
| TableCount = 0; | |
| Status = Generator->BuildSmbiosTableEx ( | |
| Generator, | |
| TableFactoryProtocol, | |
| SmbiosTableInfo, | |
| CfgMgrProtocol, | |
| &SmbiosTable, | |
| &CmObjToken, | |
| &TableCount | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: Failed to Build Table." \ | |
| " TableGeneratorId = 0x%x. Status = %r\n", | |
| SmbiosTableInfo->TableGeneratorId, | |
| Status | |
| )); | |
| // Free any allocated resources. | |
| goto exit_handler; | |
| } | |
| if ((SmbiosTable == NULL) || (TableCount == 0)) { | |
| Status = EFI_NOT_FOUND; | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "%a: TableCount %u SmbiosTable %p \n", | |
| __func__, | |
| TableCount, | |
| SmbiosTable | |
| )); | |
| goto exit_handler; | |
| } | |
| for (Index = 0; Index < TableCount; Index++) { | |
| TableHandle = SMBIOS_HANDLE_PI_RESERVED; | |
| // Install SMBIOS table | |
| Status = SmbiosProtocol->Add ( | |
| SmbiosProtocol, | |
| NULL, | |
| &TableHandle, | |
| SmbiosTable[Index] | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: Failed to Install SMBIOS Table. Status = %r\n", | |
| Status | |
| )); | |
| // Free any allocated resources. | |
| goto exit_handler; | |
| } | |
| Status = TableFactoryProtocol->AddSmbiosHandle ( | |
| SmbiosProtocol, | |
| &TableHandle, | |
| CmObjToken ? CmObjToken[Index] : CM_NULL_TOKEN, | |
| SmbiosTableInfo->TableGeneratorId | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: Failed to Add SMBIOS Handle. Status = %r\n", | |
| Status | |
| )); | |
| // Free any allocated resources. | |
| goto exit_handler; | |
| } | |
| DEBUG (( | |
| DEBUG_INFO, | |
| "INFO: SMBIOS Table installed. Status = %r\n", | |
| Status | |
| )); | |
| } | |
| exit_handler: | |
| // Free any resources allocated for generating the tables. | |
| if (Generator->FreeTableResourcesEx != NULL) { | |
| Status1 = Generator->FreeTableResourcesEx ( | |
| Generator, | |
| TableFactoryProtocol, | |
| SmbiosTableInfo, | |
| CfgMgrProtocol, | |
| &SmbiosTable, | |
| &CmObjToken, | |
| TableCount | |
| ); | |
| if (EFI_ERROR (Status1)) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: Failed to Free Table Resources." \ | |
| "TableGeneratorId = 0x%x. Status = %r\n", | |
| SmbiosTableInfo->TableGeneratorId, | |
| Status1 | |
| )); | |
| } | |
| // Return the first error status in case of failure | |
| if (!EFI_ERROR (Status)) { | |
| Status = Status1; | |
| } | |
| } | |
| return Status; | |
| } | |
| /** A helper function to invoke a Table generator | |
| This is a helper function that invokes the Table generator interface | |
| for building an SMBIOS table. It uses the SmbiosProtocol to install the | |
| table, then frees the resources allocated for generating it. | |
| @param [in] TableFactoryProtocol Pointer to the Table Factory Protocol | |
| interface. | |
| @param [in] CfgMgrProtocol Pointer to the Configuration Manager | |
| Protocol Interface. | |
| @param [in] SmbiosProtocol Pointer to the SMBIOS protocol. | |
| @param [in] SmbiosTableInfo Pointer to the SMBIOS table Info. | |
| @retval EFI_SUCCESS Success. | |
| @retval EFI_INVALID_PARAMETER A parameter is invalid. | |
| @retval EFI_NOT_FOUND Required object is not found. | |
| @retval EFI_BAD_BUFFER_SIZE Size returned by the Configuration Manager | |
| is less than the Object size for the | |
| requested object. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| BuildAndInstallSmbiosTable ( | |
| IN CONST EDKII_DYNAMIC_TABLE_FACTORY_PROTOCOL *CONST TableFactoryProtocol, | |
| IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol, | |
| IN EFI_SMBIOS_PROTOCOL *SmbiosProtocol, | |
| IN CM_STD_OBJ_SMBIOS_TABLE_INFO *CONST SmbiosTableInfo | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| CONST SMBIOS_TABLE_GENERATOR *Generator; | |
| ASSERT (TableFactoryProtocol != NULL); | |
| ASSERT (CfgMgrProtocol != NULL); | |
| ASSERT (SmbiosProtocol != NULL); | |
| ASSERT (SmbiosTableInfo != NULL); | |
| DEBUG (( | |
| DEBUG_INFO, | |
| "INFO: EStdObjSmbiosTableList: Address = 0x%p," \ | |
| " TableGeneratorId = 0x%x\n", | |
| SmbiosTableInfo, | |
| SmbiosTableInfo->TableGeneratorId | |
| )); | |
| Generator = NULL; | |
| Status = TableFactoryProtocol->GetSmbiosTableGenerator ( | |
| TableFactoryProtocol, | |
| SmbiosTableInfo->TableGeneratorId, | |
| &Generator | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: Table Generator not found." \ | |
| " TableGeneratorId = 0x%x. Status = %r\n", | |
| SmbiosTableInfo->TableGeneratorId, | |
| Status | |
| )); | |
| return Status; | |
| } | |
| if (Generator == NULL) { | |
| return EFI_NOT_FOUND; | |
| } | |
| DEBUG (( | |
| DEBUG_INFO, | |
| "INFO: Generator found : %s\n", | |
| Generator->Description | |
| )); | |
| if (Generator->BuildSmbiosTableEx != NULL) { | |
| Status = BuildAndInstallMultipleSmbiosTables ( | |
| TableFactoryProtocol, | |
| CfgMgrProtocol, | |
| Generator, | |
| SmbiosProtocol, | |
| SmbiosTableInfo | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: Failed to find build and install SMBIOS Tables." \ | |
| " Status = %r\n", | |
| Status | |
| )); | |
| } | |
| } else if (Generator->BuildSmbiosTable != NULL) { | |
| Status = BuildAndInstallSingleSmbiosTable ( | |
| TableFactoryProtocol, | |
| CfgMgrProtocol, | |
| Generator, | |
| SmbiosProtocol, | |
| SmbiosTableInfo | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: Failed to find build and install SMBIOS Table." \ | |
| " Status = %r\n", | |
| Status | |
| )); | |
| } | |
| } else { | |
| Status = EFI_INVALID_PARAMETER; | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: Table Generator does not implement the" \ | |
| "SMBIOS_TABLE_GENERATOR_BUILD_TABLE interface." \ | |
| " TableGeneratorId = 0x%x. Status = %r\n", | |
| SmbiosTableInfo->TableGeneratorId, | |
| Status | |
| )); | |
| } | |
| return Status; | |
| } | |
| /** Generate and install SMBIOS tables. | |
| The function gathers the information necessary for installing the | |
| SMBIOS tables from the Configuration Manager, invokes the generators | |
| and installs them (via BuildAndInstallAcpiTable). | |
| @param [in] TableFactoryProtocol Pointer to the Table Factory Protocol | |
| interface. | |
| @param [in] CfgMgrProtocol Pointer to the Configuration Manager | |
| Protocol Interface. | |
| @retval EFI_SUCCESS Success. | |
| @retval EFI_NOT_FOUND If a mandatory table or a generator is not found. | |
| **/ | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| ProcessSmbiosTables ( | |
| IN CONST EDKII_DYNAMIC_TABLE_FACTORY_PROTOCOL *CONST TableFactoryProtocol, | |
| IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL *CONST CfgMgrProtocol | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_SMBIOS_PROTOCOL *SmbiosProtocol; | |
| CM_STD_OBJ_SMBIOS_TABLE_INFO *SmbiosTableInfo; | |
| UINT32 SmbiosTableCount; | |
| Status = gBS->LocateProtocol ( | |
| &gEfiSmbiosProtocolGuid, | |
| NULL, | |
| (VOID **)&SmbiosProtocol | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "Could not locate SMBIOS protocol. %r\n", Status)); | |
| return Status; | |
| } | |
| Status = GetEStdObjSmbiosTableList ( | |
| CfgMgrProtocol, | |
| CM_NULL_TOKEN, | |
| &SmbiosTableInfo, | |
| &SmbiosTableCount | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| if (Status == EFI_NOT_FOUND) { | |
| // If the SMBIOS table list is not found the platform | |
| // may not be publishing SMBIOS tables | |
| // Log a warning and return success. | |
| DEBUG (( | |
| DEBUG_WARN, | |
| "WARNING: Failed to get SMBIOS table List. Status = %r\n", | |
| Status | |
| )); | |
| Status = EFI_SUCCESS; | |
| } else { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: Failed to get SMBIOS Table List. Status = %r\n", | |
| Status | |
| )); | |
| } | |
| return Status; | |
| } | |
| if (SmbiosTableCount == 0) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: EStdObjSmbiosTableList: SmbiosTableCount = %d\n", | |
| SmbiosTableCount | |
| )); | |
| return EFI_NOT_FOUND; | |
| } | |
| DEBUG (( | |
| DEBUG_INFO, | |
| "INFO: EStdObjSmbiosTableList: SmbiosTableCount = %d\n", | |
| SmbiosTableCount | |
| )); | |
| InitSmbiosTableDispatcher (SmbiosTableInfo, SmbiosTableCount); | |
| Status = DispatchSmbiosTables ( | |
| TableFactoryProtocol, | |
| CfgMgrProtocol, | |
| SmbiosProtocol, | |
| SmbiosTableInfo, | |
| SmbiosTableCount | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: Failed to install SMBIOS Tables.Status = %r\n", | |
| Status | |
| )); | |
| } | |
| return Status; | |
| } | |
| /** SMBIOS table Protocol ready event handler. | |
| This event notification indicates that the SMBIOS protocol is ready. | |
| Therefore, dispatch the building of the SMBIOS tables. | |
| @param [in] Event The Event that is signalled. | |
| @param [in] Context The Context information. | |
| @retval None | |
| **/ | |
| VOID | |
| EFIAPI | |
| SmbiosProtocolReady ( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EDKII_CONFIGURATION_MANAGER_PROTOCOL *CfgMgrProtocol; | |
| CM_STD_OBJ_CONFIGURATION_MANAGER_INFO *CfgMfrInfo; | |
| EDKII_DYNAMIC_TABLE_FACTORY_PROTOCOL *TableFactoryProtocol; | |
| // Locate the Dynamic Table Factory | |
| Status = gBS->LocateProtocol ( | |
| &gEdkiiDynamicTableFactoryProtocolGuid, | |
| NULL, | |
| (VOID **)&TableFactoryProtocol | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: Failed to find Dynamic Table Factory protocol." \ | |
| " Status = %r\n", | |
| Status | |
| )); | |
| return; | |
| } | |
| // Locate the Configuration Manager for the Platform | |
| Status = gBS->LocateProtocol ( | |
| &gEdkiiConfigurationManagerProtocolGuid, | |
| NULL, | |
| (VOID **)&CfgMgrProtocol | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: Failed to find Configuration Manager protocol. Status = %r\n", | |
| Status | |
| )); | |
| return; | |
| } | |
| Status = GetCgfMgrInfo (CfgMgrProtocol, &CfgMfrInfo); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: Failed to get Configuration Manager info. Status = %r\n", | |
| Status | |
| )); | |
| return; | |
| } | |
| DEBUG (( | |
| DEBUG_INFO, | |
| "INFO: Configuration Manager Version = 0x%x, OemID = %c%c%c%c%c%c\n", | |
| CfgMfrInfo->Revision, | |
| CfgMfrInfo->OemId[0], | |
| CfgMfrInfo->OemId[1], | |
| CfgMfrInfo->OemId[2], | |
| CfgMfrInfo->OemId[3], | |
| CfgMfrInfo->OemId[4], | |
| CfgMfrInfo->OemId[5] | |
| )); | |
| Status = ProcessSmbiosTables (TableFactoryProtocol, CfgMgrProtocol); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "ERROR: SMBIOS Table processing failure. Status = %r\n", | |
| Status | |
| )); | |
| } | |
| Status = gBS->CloseEvent (Event); | |
| ASSERT_EFI_ERROR (Status); | |
| } |