diff options
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatform.c')
-rw-r--r-- | src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatform.c | 455 |
1 files changed, 455 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatform.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatform.c new file mode 100644 index 00000000..112a01d2 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Universal/Acpi/AcpiPlatformDxe/AcpiPlatform.c @@ -0,0 +1,455 @@ +/** @file + Sample ACPI Platform Driver + + Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiDxe.h> + +#include <Protocol/AcpiTable.h> +#include <Protocol/FirmwareVolume2.h> + +#include <Library/BaseLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/DebugLib.h> +#include <Library/PcdLib.h> + +#include <IndustryStandard/Acpi.h> + +/** + 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 Instance Return pointer to the first instance of the protocol + + @return EFI_SUCCESS The function completed successfully. + @return EFI_NOT_FOUND The protocol could not be located. + @return EFI_OUT_OF_RESOURCES There are not enough resources to find the protocol. + +**/ +EFI_STATUS +LocateFvInstanceWithTables ( + OUT EFI_FIRMWARE_VOLUME2_PROTOCOL **Instance + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN NumberOfHandles; + EFI_FV_FILETYPE FileType; + UINT32 FvStatus; + EFI_FV_FILE_ATTRIBUTES Attributes; + UINTN Size; + UINTN Index; + EFI_FIRMWARE_VOLUME2_PROTOCOL *FvInstance; + + FvStatus = 0; + + // + // Locate protocol. + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareVolume2ProtocolGuid, + 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], + &gEfiFirmwareVolume2ProtocolGuid, + (VOID**) &FvInstance + ); + ASSERT_EFI_ERROR (Status); + + // + // See if it has the ACPI storage file + // + Status = FvInstance->ReadFile ( + FvInstance, + (EFI_GUID*)PcdGetPtr (PcdAcpiTableStorageFile), + NULL, + &Size, + &FileType, + &Attributes, + &FvStatus + ); + + // + // If we found it, then we are done + // + if (Status == EFI_SUCCESS) { + *Instance = FvInstance; + 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 + // + gBS->FreePool (HandleBuffer); + + return Status; +} + + +/** + This function calculates and updates an UINT8 checksum. + + @param Buffer Pointer to buffer to checksum + @param Size Number of bytes to checksum + +**/ +VOID +AcpiPlatformChecksum ( + IN UINT8 *Buffer, + IN UINTN Size + ) +{ + UINTN ChecksumOffset; + + ChecksumOffset = OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum); + + // + // Set checksum to 0 first + // + Buffer[ChecksumOffset] = 0; + + // + // Update checksum value + // + Buffer[ChecksumOffset] = CalculateCheckSum8(Buffer, Size); +} + + +#ifdef VBOX + +/* Disables the old code only copying a selection of tables, missing out a bunch of things available in the XSDT/RSDT. */ +# define ACPI_NO_STATIC_TABLES_SELECTION 1 + +# define ACPI_RSD_PTR SIGNATURE_64('R', 'S', 'D', ' ', 'P', 'T', 'R', ' ') +# define EBDA_BASE (0x9FC0 << 4) + +VOID * +FindAcpiRsdPtr(VOID) +{ + UINTN Address; + UINTN Index; + + // + // First Search 0x0e0000 - 0x0fffff for RSD Ptr + // + for (Address = 0xe0000; Address < 0xfffff; Address += 0x10) { + if (*(UINT64 *)(Address) == ACPI_RSD_PTR) { + return (VOID *)Address; + } + } + + // + // Search EBDA + // + Address = EBDA_BASE; + for (Index = 0; Index < 0x400 ; Index += 16) { + if (*(UINT64 *)(Address + Index) == ACPI_RSD_PTR) { + return (VOID *)Address; + } + } + return NULL; +} + +#ifndef ACPI_NO_STATIC_TABLES_SELECTION +VOID *FindSignature(VOID* Start, UINT32 Signature, BOOLEAN NoChecksum) +{ + UINT8 *Ptr = (UINT8*)Start; + UINT32 Count = 0x10000; // 16 pages + + while (Count-- > 0) { + if ( *(UINT32*)Ptr == Signature + && ((EFI_ACPI_DESCRIPTION_HEADER *)Ptr)->Length <= Count + && (NoChecksum || + CalculateCheckSum8(Ptr, ((EFI_ACPI_DESCRIPTION_HEADER *)Ptr)->Length) == 0 + )) { + return Ptr; + } + + Ptr++; + } + return NULL; +} +#endif + +VOID +FillSysTablesInfo(VOID **Tables, UINT32 TablesSize) +{ + UINT32 Table = 0; + EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *RsdPtr; +#ifndef ACPI_NO_STATIC_TABLES_SELECTION + VOID *TablesPage; +#else + EFI_ACPI_DESCRIPTION_HEADER *RsdtTbl; +#endif + UINT64 *PtrTbl; + UINT32 Index; + + RsdPtr = (EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER*)FindAcpiRsdPtr(); + ASSERT(RsdPtr != NULL); + +#ifndef ACPI_NO_STATIC_TABLES_SELECTION +#define FLAG_OPTIONAL 1<<0 +#define FLAG_NO_CHECKSUM 1<<1 + static struct { + UINT32 Signature; + UINT32 Flags; + CHAR8* Name; + } TableInfo[] = { + // MADT, optional + { SIGNATURE_32('A', 'P', 'I', 'C'), FLAG_OPTIONAL, "MADT"}, + // FACP (also called FADT) + { SIGNATURE_32('F', 'A', 'C', 'P'), 0, "FADT"}, + // FACS, according 5.2.9 of ACPI v2. spec FACS doesn't have checksum field + { SIGNATURE_32('F', 'A', 'C', 'S'), FLAG_NO_CHECKSUM, "FACS"}, + // DSDT + { SIGNATURE_32('D', 'S', 'D', 'T'), 0, "DSDT"}, + // SSDT + { SIGNATURE_32('S', 'S', 'D', 'T'), FLAG_OPTIONAL, "SSDT"}, + // HPET + { SIGNATURE_32('H', 'P', 'E', 'T'), FLAG_OPTIONAL, "HPET"}, + // MCFG + { SIGNATURE_32('M', 'C', 'F', 'G'), FLAG_OPTIONAL, "MCFG"} + }; + + TablesPage = (VOID *)(UINTN)((RsdPtr->RsdtAddress) & ~0xfff); + DEBUG((DEBUG_INFO, "TablesPage:%p\n", TablesPage)); + + for (Index = 0; Index < sizeof TableInfo / sizeof TableInfo[0]; Index++) + { + VOID *Ptr = FindSignature(TablesPage, TableInfo[Index].Signature, + (BOOLEAN)((TableInfo[Index].Flags & FLAG_NO_CHECKSUM) != 0)); + if (TableInfo[Index].Signature == SIGNATURE_32('F', 'A', 'C', 'P')) + { + // we actually have 2 FADTs, see https://xtracker.innotek.de/index.php?bug=4082 + Ptr = FindSignature((UINT8*)Ptr+32, SIGNATURE_32('F', 'A', 'C', 'P'), FALSE); + } + if (!(TableInfo[Index].Flags & FLAG_OPTIONAL)) + { + if (!Ptr) + DEBUG((EFI_D_ERROR, "%a: isn't optional %p\n", TableInfo[Index].Name, Ptr)); + ASSERT(Ptr != NULL); + } + DEBUG((EFI_D_ERROR, "%a: %p\n", TableInfo[Index].Name, Ptr)); + if (Ptr) + Tables[Table++] = Ptr; + } +#else + RsdtTbl = (EFI_ACPI_DESCRIPTION_HEADER*)(UINTN)RsdPtr->XsdtAddress; + DEBUG((DEBUG_INFO, "RsdtTbl:%p\n", RsdtTbl)); + + PtrTbl = (UINT64 *)(RsdtTbl + 1); + for (Index = 0; Index < (RsdtTbl->Length - sizeof(*RsdtTbl)) / sizeof(UINT64); Index++) + { + EFI_ACPI_DESCRIPTION_HEADER *Header = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)*PtrTbl++; + DEBUG ((DEBUG_VERBOSE, "Table %p found \"%-4.4a\" size 0x%x\n", Header, (CONST CHAR8 *)&Header->Signature, Header->Length)); + + if (Header->Signature == SIGNATURE_32('F', 'A', 'C', 'P')) + { + /* Add the DSDT pointer from there. */ + EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *)Header; + DEBUG((DEBUG_INFO, "Found FACP: DSDT 0x%x FACS 0x%x XDsdt %p XFacs %p\n", Fadt->Dsdt, Fadt->FirmwareCtrl, Fadt->XDsdt, Fadt->XFirmwareCtrl)); + Tables[Table++] = (VOID *)(UINTN)Fadt->FirmwareCtrl; + Tables[Table++] = (VOID *)(UINTN)Fadt->Dsdt; + } + + Tables[Table++] = Header; + } +#endif + +#if 0 + // RSDT + ASSERT(Table < TablesSize); + Tables[Table] = FindSignature(TablesPage, SIGNATURE_32('R', 'S', 'D', 'T')); + DEBUG ((EFI_D_ERROR, "RSDT: %p\n", Tables[Table])); + ASSERT(Tables[Table] != NULL); + Table++; + + // XSDT + ASSERT(Table < TablesSize); + Tables[Table] = FindSignature(TablesPage, SIGNATURE_32('X', 'S', 'D', 'T')); + DEBUG ((EFI_D_ERROR, "XSDT: %p\n", Tables[Table])); + ASSERT(Tables[Table] != NULL); + Table++; +#endif + + DEBUG((DEBUG_INFO, "We found %d tables (max allowed %d)\n", Table, TablesSize)); + Tables[Table] = NULL; +} + +#endif /* VBOX */ + + +/** + Entrypoint of Acpi Platform driver. + + @param ImageHandle + @param SystemTable + + @return EFI_SUCCESS + @return EFI_LOAD_ERROR + @return EFI_OUT_OF_RESOURCES + +**/ +EFI_STATUS +EFIAPI +AcpiPlatformEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_ACPI_TABLE_PROTOCOL *AcpiTable; +#ifdef VBOX +# ifndef ACPI_NO_STATIC_TABLES_SELECTION + VOID *VBoxTables[10]; +# else + VOID *VBoxTables[128]; +# endif +#else + EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol; +#endif + INTN Instance; + EFI_ACPI_COMMON_HEADER *CurrentTable; + UINTN TableHandle; +#ifndef VBOX + UINT32 FvStatus; +#endif + UINTN TableSize; + UINTN Size; + + Instance = 0; + CurrentTable = NULL; + TableHandle = 0; + + // + // Find the AcpiTable protocol + // + Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID**)&AcpiTable); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + +#ifdef VBOX + // + // VBOX already has tables prepared in memory - just reuse them. + // + FillSysTablesInfo(VBoxTables, sizeof(VBoxTables)/sizeof(VBoxTables[0])); +#else + // + // + // Locate the firmware volume protocol + // + Status = LocateFvInstanceWithTables (&FwVol); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } +#endif + // + // Read tables from the storage file. + // + while (Status == EFI_SUCCESS) { + +#ifdef VBOX + CurrentTable = (EFI_ACPI_COMMON_HEADER *)VBoxTables[Instance]; + Status = (CurrentTable == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS; + if (CurrentTable) { + Size = CurrentTable->Length; + DEBUG((EFI_D_ERROR, "adding %p %d\n", CurrentTable, Size)); + } else + Size = 0; // Just to shut up the compiler. +#else + Status = FwVol->ReadSection ( + FwVol, + (EFI_GUID*)PcdGetPtr (PcdAcpiTableStorageFile), + EFI_SECTION_RAW, + Instance, + (VOID**) &CurrentTable, + &Size, + &FvStatus + ); +#endif + if (!EFI_ERROR(Status)) { + // + // Add the table + // + TableHandle = 0; + + TableSize = ((EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable)->Length; +#ifdef VBOX + DEBUG((DEBUG_INFO, "Size:%d, TableSize:%d\n", Size, TableSize)); +#endif + ASSERT (Size >= TableSize); + + // + // Checksum ACPI table + // + AcpiPlatformChecksum ((UINT8*)CurrentTable, TableSize); + + // + // Install ACPI table + // + Status = AcpiTable->InstallAcpiTable ( + AcpiTable, + CurrentTable, + TableSize, + &TableHandle + ); + +#ifndef VBOX /* In case we're reading ACPI tables from memory we haven't + allocated this memory, so it isn't required to free it */ + // + // Free memory allocated by ReadSection + // + gBS->FreePool (CurrentTable); + + if (EFI_ERROR(Status)) { + return EFI_ABORTED; + } +#endif + + // + // Increment the instance + // + Instance++; + CurrentTable = NULL; + } + } + + // + // The driver does not require to be kept loaded. + // + return EFI_REQUEST_UNLOAD_IMAGE; +} + |