/** @file Board ACPI Driver @copyright INTEL CONFIDENTIAL Copyright 2018 Intel Corporation. The source code contained or described herein and all documents related to the source code ("Material") are owned by Intel Corporation or its suppliers or licensors. Title to the Material remains with Intel Corporation or its suppliers and licensors. The Material may contain trade secrets and proprietary and confidential information of Intel Corporation and its suppliers and licensors, and is protected by worldwide copyright and trade secret laws and treaty provisions. No part of the Material may be used, copied, reproduced, modified, published, uploaded, posted, transmitted, distributed, or disclosed in any way without Intel's prior express written permission. No license under any patent, copyright, trade secret or other intellectual property right is granted to or conferred upon you by disclosure or delivery of the Materials, either expressly, by implication, inducement, estoppel or otherwise. Any license under such intellectual property rights must be express and approved by Intel in writing. Unless otherwise agreed by Intel in writing, you may not remove or alter this notice or any other notice embedded in Materials by Intel or Intel's suppliers or licensors in any way. This file contains a 'Sample Driver' and is licensed as such under the terms of your license agreement with Intel or your vendor. This file may be modified by the user, subject to the additional terms of the license agreement. @par Specification Reference: **/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include GLOBAL_REMOVE_IF_UNREFERENCED PLATFORM_NVS_AREA_PROTOCOL mPlatformNvsAreaProtocol; /** @brief Global NVS initialize. @param[in] PlatformNvsAreaPtr - Pointer of global NVS area @retval EFI_SUCCESS - Allocate Global NVS completed. @retval EFI_OUT_OF_RESOURCES - Failed to allocate required page for GNVS. **/ EFI_STATUS EFIAPI AcpiGnvsInit ( IN OUT VOID **PlatformNvsAreaPtr ); VOID UpdateDsdt ( IN VOID *Table ); // // Function implementations // /** Locate the first instance of a protocol. If the protocol requested is an FV protocol, then it will return the first FV that contains the ACPI table storage file. @param[in] Protocol The protocol to find. @param[in] Instance Return pointer to the first instance of the protocol. @param[in] Type TRUE if the desired protocol is a FV protocol. @retval EFI_SUCCESS The function completed successfully. @retval EFI_NOT_FOUND The protocol could not be located. @retval EFI_OUT_OF_RESOURCES There are not enough resources to find the protocol. **/ EFI_STATUS LocateSupportProtocol ( IN EFI_GUID *Protocol, IN EFI_GUID *gEfiAcpiMultiTableStorageGuid, OUT VOID **Instance, IN BOOLEAN Type ) { EFI_STATUS Status; EFI_HANDLE *HandleBuffer; UINTN NumberOfHandles; EFI_FV_FILETYPE FileType; UINT32 FvStatus; EFI_FV_FILE_ATTRIBUTES Attributes; UINTN Size; UINTN Index; // // Locate protocol. // Status = gBS->LocateHandleBuffer ( ByProtocol, Protocol, NULL, &NumberOfHandles, &HandleBuffer ); if (EFI_ERROR (Status)) { // // Defined errors at this time are not found and out of resources. // return Status; } // // Looking for FV with ACPI storage file // for (Index = 0; Index < NumberOfHandles; Index++) { // // Get the protocol on this handle // This should not fail because of LocateHandleBuffer // Status = gBS->HandleProtocol ( HandleBuffer[Index], Protocol, Instance ); ASSERT_EFI_ERROR (Status); if (!Type) { // // Not looking for the FV protocol, so find the first instance of the // protocol. There should not be any errors because our handle buffer // should always contain at least one or LocateHandleBuffer would have // returned not found. // break; } // // See if it has the ACPI storage file // Size = 0; FvStatus = 0; Status = ((EFI_FIRMWARE_VOLUME2_PROTOCOL *) (*Instance))->ReadFile ( *Instance, gEfiAcpiMultiTableStorageGuid, NULL, &Size, &FileType, &Attributes, &FvStatus ); // // If we found it, then we are done // if (Status == EFI_SUCCESS) { break; } } // // Our exit status is determined by the success of the previous operations // If the protocol was found, Instance already points to it. // // // Free any allocated buffers // FreePool (HandleBuffer); return Status; } EFI_STATUS PublishAcpiTablesFromFv ( IN EFI_GUID *gEfiAcpiMultiTableStorageGuid ) { EFI_STATUS Status; EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol; EFI_ACPI_COMMON_HEADER *CurrentTable; UINT32 FvStatus; UINTN Size; EFI_ACPI_TABLE_VERSION Version; UINTN TableHandle; INTN Instance; EFI_ACPI_TABLE_PROTOCOL *AcpiTable; Instance = 0; TableHandle = 0; CurrentTable = NULL; FwVol = NULL; // // Find the AcpiSupport protocol // Status = LocateSupportProtocol ( &gEfiAcpiTableProtocolGuid, gEfiAcpiMultiTableStorageGuid, (VOID **) &AcpiTable, FALSE ); ASSERT_EFI_ERROR (Status); // // Locate the firmware volume protocol // Status = LocateSupportProtocol ( &gEfiFirmwareVolume2ProtocolGuid, gEfiAcpiMultiTableStorageGuid, (VOID **) &FwVol, TRUE ); // // Read tables from the storage file. // while (Status == EFI_SUCCESS) { Status = FwVol->ReadSection ( FwVol, gEfiAcpiMultiTableStorageGuid, EFI_SECTION_RAW, Instance, (VOID **) &CurrentTable, &Size, &FvStatus ); if (!EFI_ERROR (Status)) { // // Perform any table specific updates. // if (CurrentTable->Signature == EFI_ACPI_2_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) { UpdateDsdt (CurrentTable); } BoardUpdateAcpiTable (CurrentTable, &Version); // // Add the table // TableHandle = 0; if (Version != EFI_ACPI_TABLE_VERSION_NONE) { Status = AcpiTable->InstallAcpiTable ( AcpiTable, CurrentTable, CurrentTable->Length, &TableHandle ); } ASSERT_EFI_ERROR (Status); // // Increment the instance // Instance++; CurrentTable = NULL; } } // // Finished // return EFI_SUCCESS; } /** ACPI Platform driver installation function. @param[in] ImageHandle Handle for this drivers loaded image protocol. @param[in] SystemTable EFI system table. @retval EFI_SUCCESS The driver installed without error. @retval EFI_ABORTED The driver encountered an error and could not complete installation of the ACPI tables. **/ EFI_STATUS EFIAPI InstallAcpiBoard ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; EFI_HANDLE Handle; AcpiGnvsInit((VOID **) &mPlatformNvsAreaProtocol.Area); // // This PCD set must be done before PublishAcpiTablesFromFv. // The PCD data will be used there. // PcdSet64S (PcdAcpiGnvsAddress, (UINT64)(UINTN)mPlatformNvsAreaProtocol.Area); // // Platform ACPI Tables // PublishAcpiTablesFromFv (&gEfiCallerIdGuid); // // This protocol publish must be done after PublishAcpiTablesFromFv. // The NVS data is be updated there. // Handle = NULL; Status = gBS->InstallMultipleProtocolInterfaces ( &Handle, &gPlatformNvsAreaProtocolGuid, &mPlatformNvsAreaProtocol, NULL ); ASSERT_EFI_ERROR (Status); return EFI_SUCCESS; }