[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
This commit is contained in:
Ahmed Arif
2026-07-09 01:40:17 +03:00
committed by GitHub
parent d7aa4ad3f3
commit 63deca5a96
2 changed files with 206 additions and 6 deletions
+193 -1
View File
@@ -6,16 +6,190 @@
#include "precomp.h"
#include <arc/arc.h>
#include <reactos/drivers/acpi/acpi.h>
#include <pseh/pseh2.h>
#define NDEBUG
#include <debug.h>
#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 <ndk/kefuncs.h> 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)
{
+13 -5
View File
@@ -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;
}