/** @file Sample ACPI Platform Driver Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include /** 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; }