From 63deca5a962ce8b84332108c3bb0018180174cac Mon Sep 17 00:00:00 2001 From: Ahmed Arif Date: Thu, 9 Jul 2026 00:40:17 +0200 Subject: [PATCH] [ACPI][UEFI] Use bootloader-provided ACPI root pointer in OSL (#8980) Fix ACPI table discovery on the UEFI boot path by teaching the ACPI OSL to use the loader-provided ACPI root table information instead of relying only on legacy BIOS RSDP scanning: - Build a synthetic RSDP from the ACPI BIOS configuration node populated by the bootloader - Fallback to the old scan only if that data is unavailable - Keep full 64-bit physical addresses when mapping ACPI tables - Improve failure diagnostics if initialization still fails This lets ACPICA initialize from the UEFI-provided RSDT/XSDT path. CORE-11954 So QEMU Q35 on UEFI is now able to discover ACPI tables through the loader- provided root table path, which fixes 0x7B INACCESSIBLE_BOOT_DEVICE bugcheck: https://github.com/user-attachments/assets/25d4d9c9-4197-496b-84f9-e5642c65809d --- drivers/bus/acpi/osl.c | 194 ++++++++++++++++++++++++++++++++++++++++- drivers/bus/acpi/pnp.c | 18 ++-- 2 files changed, 206 insertions(+), 6 deletions(-) diff --git a/drivers/bus/acpi/osl.c b/drivers/bus/acpi/osl.c index 8b8176cbde0..49c3486b963 100644 --- a/drivers/bus/acpi/osl.c +++ b/drivers/bus/acpi/osl.c @@ -6,16 +6,190 @@ #include "precomp.h" +#include +#include #include #define NDEBUG #include +#define TAG_ACPI_LOADER_RSDP_TABLE 'RpcA' + static PKINTERRUPT AcpiInterrupt; static BOOLEAN AcpiInterruptHandlerRegistered = FALSE; static ACPI_OSD_HANDLER AcpiIrqHandler = NULL; static PVOID AcpiIrqContext = NULL; static ULONG AcpiIrqNumber = 0; +/* TODO: Replace these local declarations with once the + * acpi.sys build context can consume the required NDK dependencies cleanly. + */ +extern NTSYSAPI PLOADER_PARAMETER_BLOCK KeLoaderBlock; +extern NTSYSAPI +PCONFIGURATION_COMPONENT_DATA +NTAPI +KeFindConfigurationNextEntry( + _In_ PCONFIGURATION_COMPONENT_DATA Child, + _In_ CONFIGURATION_CLASS Class, + _In_ CONFIGURATION_TYPE Type, + _In_opt_ PULONG ComponentKey, + _Inout_ PCONFIGURATION_COMPONENT_DATA *NextLink); + +static ACPI_TABLE_RSDP *AcpiLoaderRsdp = NULL; + +static +UCHAR +AcpiChecksumBuffer( + _In_reads_bytes_(Length) const UCHAR *Buffer, + _In_ ULONG Length) +{ + ULONG Index; + UCHAR Sum; + + Sum = 0; + for (Index = 0; Index < Length; ++Index) + Sum = (UCHAR)(Sum + Buffer[Index]); + + return (UCHAR)(0 - Sum); +} + +static +PACPI_BIOS_MULTI_NODE +AcpiGetLoaderAcpiBiosNode(VOID) +{ + PCONFIGURATION_COMPONENT_DATA ComponentEntry = NULL; + PCONFIGURATION_COMPONENT_DATA Next = NULL; + PCM_PARTIAL_RESOURCE_LIST ResourceList; + + if (!KeLoaderBlock || !KeLoaderBlock->ConfigurationRoot) + return NULL; + + ComponentEntry = KeFindConfigurationNextEntry(KeLoaderBlock->ConfigurationRoot, + AdapterClass, + MultiFunctionAdapter, + NULL, + &Next); + while (ComponentEntry) + { + if ((ComponentEntry->ComponentEntry.Identifier != NULL) && + !_stricmp(ComponentEntry->ComponentEntry.Identifier, "ACPI BIOS")) + { + break; + } + + Next = ComponentEntry; + ComponentEntry = KeFindConfigurationNextEntry(KeLoaderBlock->ConfigurationRoot, + AdapterClass, + MultiFunctionAdapter, + NULL, + &Next); + } + + if (!ComponentEntry) + return NULL; + + ResourceList = ComponentEntry->ConfigurationData; + if (!ResourceList || + (ComponentEntry->ComponentEntry.ConfigurationDataLength < + FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors[1]) + + FIELD_OFFSET(ACPI_BIOS_MULTI_NODE, E820Entry)) || + (ResourceList->Count < 1) || + (ResourceList->PartialDescriptors[0].Type != CmResourceTypeDeviceSpecific)) + { + DPRINT1("Loader ACPI BIOS node is missing valid device-specific data\n"); + return NULL; + } + + return (PACPI_BIOS_MULTI_NODE)(ResourceList + 1); +} + +static +ACPI_PHYSICAL_ADDRESS +AcpiBuildLoaderRootPointer(VOID) +{ + PACPI_BIOS_MULTI_NODE NodeData; + ACPI_TABLE_HEADER *RootTable; + PHYSICAL_ADDRESS PhysicalAddress; + + if (AcpiLoaderRsdp != NULL) + { + PhysicalAddress = MmGetPhysicalAddress(AcpiLoaderRsdp); + return (ACPI_PHYSICAL_ADDRESS)PhysicalAddress.QuadPart; + } + + NodeData = AcpiGetLoaderAcpiBiosNode(); + if (!NodeData || (NodeData->RsdtAddress.QuadPart == 0)) + goto Failure; + + RootTable = MmMapIoSpace(NodeData->RsdtAddress, sizeof(*RootTable), MmNonCached); + if (!RootTable) + { + DPRINT1("Unable to map loader ACPI root table at 0x%I64x\n", + NodeData->RsdtAddress.QuadPart); + goto Failure; + } + + AcpiLoaderRsdp = ExAllocatePoolZero(NonPagedPool, + sizeof(*AcpiLoaderRsdp), + TAG_ACPI_LOADER_RSDP_TABLE); + if (!AcpiLoaderRsdp) + { + DPRINT1("Unable to allocate synthetic RSDP for loader ACPI tables\n"); + goto Failure; + } + + RtlCopyMemory(AcpiLoaderRsdp->Signature, + ACPI_SIG_RSDP, + sizeof(AcpiLoaderRsdp->Signature)); + RtlCopyMemory(AcpiLoaderRsdp->OemId, "ROS ", sizeof(AcpiLoaderRsdp->OemId)); + + if (RtlEqualMemory(RootTable->Signature, ACPI_SIG_XSDT, ACPI_NAMESEG_SIZE)) + { + AcpiLoaderRsdp->Revision = 2; + AcpiLoaderRsdp->Length = sizeof(*AcpiLoaderRsdp); + AcpiLoaderRsdp->XsdtPhysicalAddress = NodeData->RsdtAddress.QuadPart; + } + else if (RtlEqualMemory(RootTable->Signature, ACPI_SIG_RSDT, ACPI_NAMESEG_SIZE)) + { + if (NodeData->RsdtAddress.QuadPart > MAXULONG) + { + DPRINT1("Loader RSDT address does not fit in 32 bits: 0x%I64x\n", + NodeData->RsdtAddress.QuadPart); + goto Failure; + } + + AcpiLoaderRsdp->Revision = 0; + AcpiLoaderRsdp->RsdtPhysicalAddress = NodeData->RsdtAddress.LowPart; + } + else + { + DPRINT1("Loader ACPI root table has unexpected signature '%.4s'\n", + RootTable->Signature); + goto Failure; + } + + AcpiLoaderRsdp->Checksum = AcpiChecksumBuffer((const UCHAR *)AcpiLoaderRsdp, + ACPI_RSDP_CHECKSUM_LENGTH); + if (AcpiLoaderRsdp->Revision >= 2) + { + AcpiLoaderRsdp->ExtendedChecksum = + AcpiChecksumBuffer((const UCHAR *)AcpiLoaderRsdp, + sizeof(*AcpiLoaderRsdp)); + } + + MmUnmapIoSpace(RootTable, sizeof(*RootTable)); + PhysicalAddress = MmGetPhysicalAddress(AcpiLoaderRsdp); + return (ACPI_PHYSICAL_ADDRESS)PhysicalAddress.QuadPart; + +Failure: + if (AcpiLoaderRsdp) + { + ExFreePoolWithTag(AcpiLoaderRsdp, TAG_ACPI_LOADER_RSDP_TABLE); + AcpiLoaderRsdp = NULL; + } + if (RootTable) + MmUnmapIoSpace(RootTable, sizeof(*RootTable)); + return 0; +} ACPI_STATUS AcpiOsInitialize (void) @@ -28,6 +202,8 @@ AcpiOsInitialize (void) AcpiDbgLayer = 0xFFFFFFFF; #endif + (VOID)AcpiBuildLoaderRootPointer(); + return AE_OK; } @@ -36,6 +212,15 @@ AcpiOsTerminate(void) { DPRINT("AcpiOsTerminate() called\n"); + /* Release the synthetic RSDP built from the loader-provided ACPI tables. + * ACPICA has already torn down its table mappings (AcpiUtSubsystemShutdown) + * by the time it calls us, so nothing references this buffer anymore. */ + if (AcpiLoaderRsdp != NULL) + { + ExFreePoolWithTag(AcpiLoaderRsdp, TAG_ACPI_LOADER_RSDP_TABLE); + AcpiLoaderRsdp = NULL; + } + return AE_OK; } @@ -44,9 +229,16 @@ AcpiOsGetRootPointer ( void) { ACPI_PHYSICAL_ADDRESS pa = 0; + PHYSICAL_ADDRESS PhysicalAddress; DPRINT("AcpiOsGetRootPointer\n"); + if (AcpiLoaderRsdp != NULL) + { + PhysicalAddress = MmGetPhysicalAddress(AcpiLoaderRsdp); + return (ACPI_PHYSICAL_ADDRESS)PhysicalAddress.QuadPart; + } + AcpiFindRootPointer(&pa); return pa; } @@ -114,7 +306,7 @@ AcpiOsMapMemory ( DPRINT("AcpiOsMapMemory(phys 0x%p size 0x%X)\n", phys, length); - Address.QuadPart = (ULONG)phys; + Address.QuadPart = (ULONGLONG)phys; Ptr = MmMapIoSpace(Address, length, MmNonCached); if (!Ptr) { diff --git a/drivers/bus/acpi/pnp.c b/drivers/bus/acpi/pnp.c index ef342ce4e2a..9c87bbb02aa 100644 --- a/drivers/bus/acpi/pnp.c +++ b/drivers/bus/acpi/pnp.c @@ -282,19 +282,25 @@ Bus_StartFdo ( AcpiStatus = AcpiInitializeSubsystem(); if(ACPI_FAILURE(AcpiStatus)){ - DPRINT1("Unable to AcpiInitializeSubsystem\n"); + DPRINT1("Unable to AcpiInitializeSubsystem: %s (0x%08X)\n", + AcpiFormatException(AcpiStatus), + AcpiStatus); return STATUS_UNSUCCESSFUL; } AcpiStatus = AcpiInitializeTables(NULL, 16, 0); if (ACPI_FAILURE(AcpiStatus)){ - DPRINT1("Unable to AcpiInitializeTables\n"); - return STATUS_UNSUCCESSFUL; + DPRINT1("Unable to AcpiInitializeTables: %s (0x%08X)\n", + AcpiFormatException(AcpiStatus), + AcpiStatus); + return STATUS_UNSUCCESSFUL; } AcpiStatus = AcpiLoadTables(); if(ACPI_FAILURE(AcpiStatus)){ - DPRINT1("Unable to AcpiLoadTables\n"); + DPRINT1("Unable to AcpiLoadTables: %s (0x%08X)\n", + AcpiFormatException(AcpiStatus), + AcpiStatus); AcpiTerminate(); return STATUS_UNSUCCESSFUL; } @@ -309,7 +315,9 @@ Bus_StartFdo ( /* Initialize ACPI bus manager */ AcpiStatus = acpi_init(); if (!ACPI_SUCCESS(AcpiStatus)) { - DPRINT1("acpi_init() failed with status 0x%X\n", AcpiStatus); + DPRINT1("acpi_init() failed: %s (0x%08X)\n", + AcpiFormatException(AcpiStatus), + AcpiStatus); AcpiTerminate(); return STATUS_UNSUCCESSFUL; }