mirror of
https://github.com/reactos/reactos.git
synced 2024-08-19 01:48:11 +00:00
![Timo Kreuzer](/assets/img/avatar_default.png)
* Add an NDK header to define INIT_FUNCTION/INIT_SECTION globally * Use _declspec(allocate(x)) and _declspec(code_seg(x)) on MSVC versions that support it * Use INIT_FUNCTION on functions only and INIT_SECTION on data only (required by MSVC) * Place INIT_FUNCTION before the return type (required by MSVC) * Make sure declarations and implementations share the same modifiers (required by MSVC) * Add a global linker option to suppress warnings about defined but unused INIT section * Merge INIT section into .text in freeldr
1116 lines
31 KiB
C
1116 lines
31 KiB
C
/*
|
|
* PROJECT: ReactOS HAL
|
|
* LICENSE: BSD - See COPYING.ARM in the top level directory
|
|
* FILE: hal/halx86/acpi/halacpi.c
|
|
* PURPOSE: HAL ACPI Code
|
|
* PROGRAMMERS: ReactOS Portable Systems Group
|
|
*/
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
#include <hal.h>
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* GLOBALS ********************************************************************/
|
|
|
|
LIST_ENTRY HalpAcpiTableCacheList;
|
|
FAST_MUTEX HalpAcpiTableCacheLock;
|
|
|
|
BOOLEAN HalpProcessedACPIPhase0;
|
|
BOOLEAN HalpPhysicalMemoryMayAppearAbove4GB;
|
|
|
|
FADT HalpFixedAcpiDescTable;
|
|
PDEBUG_PORT_TABLE HalpDebugPortTable;
|
|
PACPI_SRAT HalpAcpiSrat;
|
|
PBOOT_TABLE HalpSimpleBootFlagTable;
|
|
|
|
PHYSICAL_ADDRESS HalpMaxHotPlugMemoryAddress;
|
|
PHYSICAL_ADDRESS HalpLowStubPhysicalAddress;
|
|
PHARDWARE_PTE HalpPteForFlush;
|
|
PVOID HalpVirtAddrForFlush;
|
|
PVOID HalpLowStub;
|
|
|
|
PACPI_BIOS_MULTI_NODE HalpAcpiMultiNode;
|
|
|
|
LIST_ENTRY HalpAcpiTableMatchList;
|
|
|
|
ULONG HalpInvalidAcpiTable;
|
|
|
|
ULONG HalpPicVectorRedirect[] = {0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15};
|
|
|
|
/* This determines the HAL type */
|
|
BOOLEAN HalDisableFirmwareMapper = TRUE;
|
|
PWCHAR HalHardwareIdString = L"acpipic_up";
|
|
PWCHAR HalName = L"ACPI Compatible Eisa/Isa HAL";
|
|
|
|
/* PRIVATE FUNCTIONS **********************************************************/
|
|
|
|
PDESCRIPTION_HEADER
|
|
NTAPI
|
|
HalpAcpiGetCachedTable(IN ULONG Signature)
|
|
{
|
|
PLIST_ENTRY ListHead, NextEntry;
|
|
PACPI_CACHED_TABLE CachedTable;
|
|
|
|
/* Loop cached tables */
|
|
ListHead = &HalpAcpiTableCacheList;
|
|
NextEntry = ListHead->Flink;
|
|
while (NextEntry != ListHead)
|
|
{
|
|
/* Get the table */
|
|
CachedTable = CONTAINING_RECORD(NextEntry, ACPI_CACHED_TABLE, Links);
|
|
|
|
/* Compare signatures */
|
|
if (CachedTable->Header.Signature == Signature) return &CachedTable->Header;
|
|
|
|
/* Keep going */
|
|
NextEntry = NextEntry->Flink;
|
|
}
|
|
|
|
/* Nothing found */
|
|
return NULL;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
HalpAcpiCacheTable(IN PDESCRIPTION_HEADER TableHeader)
|
|
{
|
|
PACPI_CACHED_TABLE CachedTable;
|
|
|
|
/* Get the cached table and link it */
|
|
CachedTable = CONTAINING_RECORD(TableHeader, ACPI_CACHED_TABLE, Header);
|
|
InsertTailList(&HalpAcpiTableCacheList, &CachedTable->Links);
|
|
}
|
|
|
|
PVOID
|
|
NTAPI
|
|
HalpAcpiCopyBiosTable(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
|
|
IN PDESCRIPTION_HEADER TableHeader)
|
|
{
|
|
ULONG Size;
|
|
PFN_COUNT PageCount;
|
|
PHYSICAL_ADDRESS PhysAddress;
|
|
PACPI_CACHED_TABLE CachedTable;
|
|
PDESCRIPTION_HEADER CopiedTable;
|
|
|
|
/* Size we'll need for the cached table */
|
|
Size = TableHeader->Length + FIELD_OFFSET(ACPI_CACHED_TABLE, Header);
|
|
if (LoaderBlock)
|
|
{
|
|
/* Phase 0: Convert to pages and use the HAL heap */
|
|
PageCount = BYTES_TO_PAGES(Size);
|
|
PhysAddress.QuadPart = HalpAllocPhysicalMemory(LoaderBlock,
|
|
0x1000000,
|
|
PageCount,
|
|
FALSE);
|
|
if (PhysAddress.QuadPart)
|
|
{
|
|
/* Map it */
|
|
CachedTable = HalpMapPhysicalMemory64(PhysAddress, PageCount);
|
|
}
|
|
else
|
|
{
|
|
/* No memory, so nothing to map */
|
|
CachedTable = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Use Mm pool */
|
|
CachedTable = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_HAL);
|
|
}
|
|
|
|
/* Do we have the cached table? */
|
|
if (CachedTable)
|
|
{
|
|
/* Copy the data */
|
|
CopiedTable = &CachedTable->Header;
|
|
RtlCopyMemory(CopiedTable, TableHeader, TableHeader->Length);
|
|
}
|
|
else
|
|
{
|
|
/* Nothing to return */
|
|
CopiedTable = NULL;
|
|
}
|
|
|
|
/* Return the table */
|
|
return CopiedTable;
|
|
}
|
|
|
|
PVOID
|
|
NTAPI
|
|
HalpAcpiGetTableFromBios(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
|
|
IN ULONG Signature)
|
|
{
|
|
PHYSICAL_ADDRESS PhysicalAddress;
|
|
PXSDT Xsdt;
|
|
PRSDT Rsdt;
|
|
PFADT Fadt;
|
|
PDESCRIPTION_HEADER Header = NULL;
|
|
ULONG TableLength;
|
|
CHAR CheckSum = 0;
|
|
ULONG Offset;
|
|
ULONG EntryCount, CurrentEntry;
|
|
PCHAR CurrentByte;
|
|
PFN_COUNT PageCount;
|
|
|
|
/* Should not query the RSDT/XSDT by itself */
|
|
if ((Signature == RSDT_SIGNATURE) || (Signature == XSDT_SIGNATURE)) return NULL;
|
|
|
|
/* Special case request for DSDT, because the FADT points to it */
|
|
if (Signature == DSDT_SIGNATURE)
|
|
{
|
|
/* Grab the FADT */
|
|
Fadt = HalpAcpiGetTable(LoaderBlock, FADT_SIGNATURE);
|
|
if (Fadt)
|
|
{
|
|
/* Grab the DSDT address and assume 2 pages */
|
|
PhysicalAddress.HighPart = 0;
|
|
PhysicalAddress.LowPart = Fadt->dsdt;
|
|
TableLength = 2 * PAGE_SIZE;
|
|
|
|
/* Map it */
|
|
if (LoaderBlock)
|
|
{
|
|
/* Phase 0, use HAL heap */
|
|
Header = HalpMapPhysicalMemory64(PhysicalAddress, 2u);
|
|
}
|
|
else
|
|
{
|
|
/* Phase 1, use Mm */
|
|
Header = MmMapIoSpace(PhysicalAddress, 2 * PAGE_SIZE, 0);
|
|
}
|
|
|
|
/* Fail if we couldn't map it */
|
|
if (!Header)
|
|
{
|
|
DPRINT1("HAL: Failed to map ACPI table.\n");
|
|
return NULL;
|
|
}
|
|
|
|
/* Validate the signature */
|
|
if (Header->Signature != DSDT_SIGNATURE)
|
|
{
|
|
/* Fail and unmap */
|
|
if (LoaderBlock)
|
|
{
|
|
/* Using HAL heap */
|
|
HalpUnmapVirtualAddress(Header, 2);
|
|
}
|
|
else
|
|
{
|
|
/* Using Mm */
|
|
MmUnmapIoSpace(Header, 2 * PAGE_SIZE);
|
|
}
|
|
|
|
/* Didn't find anything */
|
|
return NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Couldn't find it */
|
|
return NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* To find tables, we need the RSDT */
|
|
Rsdt = HalpAcpiGetTable(LoaderBlock, RSDT_SIGNATURE);
|
|
if (Rsdt)
|
|
{
|
|
/* Won't be using the XSDT */
|
|
Xsdt = NULL;
|
|
}
|
|
else
|
|
{
|
|
/* Only other choice is to use the XSDT */
|
|
Xsdt = HalpAcpiGetTable(LoaderBlock, XSDT_SIGNATURE);
|
|
if (!Xsdt) return NULL;
|
|
|
|
/* Won't be using the RSDT */
|
|
Rsdt = NULL;
|
|
}
|
|
|
|
/* Smallest RSDT/XSDT is one without table entries */
|
|
Offset = FIELD_OFFSET(RSDT, Tables);
|
|
if (Xsdt)
|
|
{
|
|
/* Figure out total size of table and the offset */
|
|
TableLength = Xsdt->Header.Length;
|
|
if (TableLength < Offset) Offset = Xsdt->Header.Length;
|
|
|
|
/* The entries are each 64-bits, so count them */
|
|
EntryCount = (TableLength - Offset) / sizeof(PHYSICAL_ADDRESS);
|
|
}
|
|
else
|
|
{
|
|
/* Figure out total size of table and the offset */
|
|
TableLength = Rsdt->Header.Length;
|
|
if (TableLength < Offset) Offset = Rsdt->Header.Length;
|
|
|
|
/* The entries are each 32-bits, so count them */
|
|
EntryCount = (TableLength - Offset) / sizeof(ULONG);
|
|
}
|
|
|
|
/* Start at the beginning of the array and loop it */
|
|
for (CurrentEntry = 0; CurrentEntry < EntryCount; CurrentEntry++)
|
|
{
|
|
/* Are we using the XSDT? */
|
|
if (!Xsdt)
|
|
{
|
|
/* Read the 32-bit physical address */
|
|
PhysicalAddress.LowPart = Rsdt->Tables[CurrentEntry];
|
|
PhysicalAddress.HighPart = 0;
|
|
}
|
|
else
|
|
{
|
|
/* Read the 64-bit physical address */
|
|
PhysicalAddress = Xsdt->Tables[CurrentEntry];
|
|
}
|
|
|
|
/* Had we already mapped a table? */
|
|
if (Header)
|
|
{
|
|
/* Yes, unmap it */
|
|
if (LoaderBlock)
|
|
{
|
|
/* Using HAL heap */
|
|
HalpUnmapVirtualAddress(Header, 2);
|
|
}
|
|
else
|
|
{
|
|
/* Using Mm */
|
|
MmUnmapIoSpace(Header, 2 * PAGE_SIZE);
|
|
}
|
|
}
|
|
|
|
/* Now map this table */
|
|
if (!LoaderBlock)
|
|
{
|
|
/* Phase 1: Use HAL heap */
|
|
Header = MmMapIoSpace(PhysicalAddress, 2 * PAGE_SIZE, MmNonCached);
|
|
}
|
|
else
|
|
{
|
|
/* Phase 0: Use Mm */
|
|
Header = HalpMapPhysicalMemory64(PhysicalAddress, 2);
|
|
}
|
|
|
|
/* Check if we mapped it */
|
|
if (!Header)
|
|
{
|
|
/* Game over */
|
|
DPRINT1("HAL: Failed to map ACPI table.\n");
|
|
return NULL;
|
|
}
|
|
|
|
/* We found it, break out */
|
|
DPRINT("Found ACPI table %c%c%c%c at 0x%p\n",
|
|
Header->Signature & 0xFF,
|
|
(Header->Signature & 0xFF00) >> 8,
|
|
(Header->Signature & 0xFF0000) >> 16,
|
|
(Header->Signature & 0xFF000000) >> 24,
|
|
Header);
|
|
if (Header->Signature == Signature) break;
|
|
}
|
|
|
|
/* Did we end up here back at the last entry? */
|
|
if (CurrentEntry == EntryCount)
|
|
{
|
|
/* Yes, unmap the last table we processed */
|
|
if (LoaderBlock)
|
|
{
|
|
/* Using HAL heap */
|
|
HalpUnmapVirtualAddress(Header, 2);
|
|
}
|
|
else
|
|
{
|
|
/* Using Mm */
|
|
MmUnmapIoSpace(Header, 2 * PAGE_SIZE);
|
|
}
|
|
|
|
/* Didn't find anything */
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/* Past this point, we assume something was found */
|
|
ASSERT(Header);
|
|
|
|
/* How many pages do we need? */
|
|
PageCount = BYTES_TO_PAGES(Header->Length);
|
|
if (PageCount != 2)
|
|
{
|
|
/* We assumed two, but this is not the case, free the current mapping */
|
|
if (LoaderBlock)
|
|
{
|
|
/* Using HAL heap */
|
|
HalpUnmapVirtualAddress(Header, 2);
|
|
}
|
|
else
|
|
{
|
|
/* Using Mm */
|
|
MmUnmapIoSpace(Header, 2 * PAGE_SIZE);
|
|
}
|
|
|
|
/* Now map this table using its correct size */
|
|
if (!LoaderBlock)
|
|
{
|
|
/* Phase 1: Use HAL heap */
|
|
Header = MmMapIoSpace(PhysicalAddress, PageCount << PAGE_SHIFT, MmNonCached);
|
|
}
|
|
else
|
|
{
|
|
/* Phase 0: Use Mm */
|
|
Header = HalpMapPhysicalMemory64(PhysicalAddress, PageCount);
|
|
}
|
|
}
|
|
|
|
/* Fail if the remapped failed */
|
|
if (!Header) return NULL;
|
|
|
|
/* All tables in ACPI 3.0 other than the FACP should have correct checksum */
|
|
if ((Header->Signature != FADT_SIGNATURE) || (Header->Revision > 2))
|
|
{
|
|
/* Go to the end of the table */
|
|
CheckSum = 0;
|
|
CurrentByte = (PCHAR)Header + Header->Length;
|
|
while (CurrentByte-- != (PCHAR)Header)
|
|
{
|
|
/* Add this byte */
|
|
CheckSum += *CurrentByte;
|
|
}
|
|
|
|
/* The correct checksum is always 0, anything else is illegal */
|
|
if (CheckSum)
|
|
{
|
|
HalpInvalidAcpiTable = Header->Signature;
|
|
DPRINT1("Checksum failed on ACPI table %c%c%c%c\n",
|
|
(Signature & 0xFF),
|
|
(Signature & 0xFF00) >> 8,
|
|
(Signature & 0xFF0000) >> 16,
|
|
(Signature & 0xFF000000) >> 24);
|
|
}
|
|
}
|
|
|
|
/* Return the table */
|
|
return Header;
|
|
}
|
|
|
|
PVOID
|
|
NTAPI
|
|
HalpAcpiGetTable(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
|
|
IN ULONG Signature)
|
|
{
|
|
PFN_COUNT PageCount;
|
|
PDESCRIPTION_HEADER TableAddress, BiosCopy;
|
|
|
|
/* See if we have a cached table? */
|
|
TableAddress = HalpAcpiGetCachedTable(Signature);
|
|
if (!TableAddress)
|
|
{
|
|
/* No cache, search the BIOS */
|
|
TableAddress = HalpAcpiGetTableFromBios(LoaderBlock, Signature);
|
|
if (TableAddress)
|
|
{
|
|
/* Found it, copy it into our own memory */
|
|
BiosCopy = HalpAcpiCopyBiosTable(LoaderBlock, TableAddress);
|
|
|
|
/* Get the pages, and unmap the BIOS copy */
|
|
PageCount = BYTES_TO_PAGES(TableAddress->Length);
|
|
if (LoaderBlock)
|
|
{
|
|
/* Phase 0, use the HAL heap */
|
|
HalpUnmapVirtualAddress(TableAddress, PageCount);
|
|
}
|
|
else
|
|
{
|
|
/* Phase 1, use Mm */
|
|
MmUnmapIoSpace(TableAddress, PageCount << PAGE_SHIFT);
|
|
}
|
|
|
|
/* Cache the bios copy */
|
|
TableAddress = BiosCopy;
|
|
if (BiosCopy) HalpAcpiCacheTable(BiosCopy);
|
|
}
|
|
}
|
|
|
|
/* Return the table */
|
|
return TableAddress;
|
|
}
|
|
|
|
PVOID
|
|
NTAPI
|
|
HalAcpiGetTable(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
|
|
IN ULONG Signature)
|
|
{
|
|
PDESCRIPTION_HEADER TableHeader;
|
|
|
|
/* Is this phase0 */
|
|
if (LoaderBlock)
|
|
{
|
|
/* Initialize the cache first */
|
|
if (!NT_SUCCESS(HalpAcpiTableCacheInit(LoaderBlock))) return NULL;
|
|
}
|
|
else
|
|
{
|
|
/* Lock the cache */
|
|
ExAcquireFastMutex(&HalpAcpiTableCacheLock);
|
|
}
|
|
|
|
/* Get the table */
|
|
TableHeader = HalpAcpiGetTable(LoaderBlock, Signature);
|
|
|
|
/* Release the lock in phase 1 */
|
|
if (!LoaderBlock) ExReleaseFastMutex(&HalpAcpiTableCacheLock);
|
|
|
|
/* Return the table */
|
|
return TableHeader;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
HalpNumaInitializeStaticConfiguration(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
|
|
{
|
|
PACPI_SRAT SratTable;
|
|
|
|
/* Get the SRAT, bail out if it doesn't exist */
|
|
SratTable = HalAcpiGetTable(LoaderBlock, SRAT_SIGNATURE);
|
|
HalpAcpiSrat = SratTable;
|
|
if (!SratTable) return;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
HalpGetHotPlugMemoryInfo(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
|
|
{
|
|
PACPI_SRAT SratTable;
|
|
|
|
/* Get the SRAT, bail out if it doesn't exist */
|
|
SratTable = HalAcpiGetTable(LoaderBlock, SRAT_SIGNATURE);
|
|
HalpAcpiSrat = SratTable;
|
|
if (!SratTable) return;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
HalpDynamicSystemResourceConfiguration(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
|
|
{
|
|
/* For this HAL, it means to get hot plug memory information */
|
|
HalpGetHotPlugMemoryInfo(LoaderBlock);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
HalpAcpiDetectMachineSpecificActions(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
|
|
IN PFADT DescriptionTable)
|
|
{
|
|
/* Does this HAL specify something? */
|
|
if (HalpAcpiTableMatchList.Flink)
|
|
{
|
|
/* Great, but we don't support it */
|
|
DPRINT1("WARNING: Your HAL has specific ACPI hacks to apply!\n");
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
HalpInitBootTable(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
|
|
{
|
|
PBOOT_TABLE BootTable;
|
|
|
|
/* Get the boot table */
|
|
BootTable = HalAcpiGetTable(LoaderBlock, BOOT_SIGNATURE);
|
|
HalpSimpleBootFlagTable = BootTable;
|
|
|
|
/* Validate it */
|
|
if ((BootTable) &&
|
|
(BootTable->Header.Length >= sizeof(BOOT_TABLE)) &&
|
|
(BootTable->CMOSIndex >= 9))
|
|
{
|
|
DPRINT1("ACPI Boot table found, but not supported!\n");
|
|
}
|
|
else
|
|
{
|
|
/* Invalid or doesn't exist, ignore it */
|
|
HalpSimpleBootFlagTable = 0;
|
|
}
|
|
|
|
/* Install the end of boot handler */
|
|
// HalEndOfBoot = HalpEndOfBoot;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
HalpAcpiFindRsdtPhase0(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
|
|
OUT PACPI_BIOS_MULTI_NODE* AcpiMultiNode)
|
|
{
|
|
PCONFIGURATION_COMPONENT_DATA ComponentEntry;
|
|
PCONFIGURATION_COMPONENT_DATA Next = NULL;
|
|
PCM_PARTIAL_RESOURCE_LIST ResourceList;
|
|
PACPI_BIOS_MULTI_NODE NodeData;
|
|
SIZE_T NodeLength;
|
|
PFN_COUNT PageCount;
|
|
PVOID MappedAddress;
|
|
PHYSICAL_ADDRESS PhysicalAddress;
|
|
|
|
/* Did we already do this once? */
|
|
if (HalpAcpiMultiNode)
|
|
{
|
|
/* Return what we know */
|
|
*AcpiMultiNode = HalpAcpiMultiNode;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* Assume failure */
|
|
*AcpiMultiNode = NULL;
|
|
|
|
/* Find the multi function adapter key */
|
|
ComponentEntry = KeFindConfigurationNextEntry(LoaderBlock->ConfigurationRoot,
|
|
AdapterClass,
|
|
MultiFunctionAdapter,
|
|
0,
|
|
&Next);
|
|
while (ComponentEntry)
|
|
{
|
|
/* Find the ACPI BIOS key */
|
|
if (!_stricmp(ComponentEntry->ComponentEntry.Identifier, "ACPI BIOS"))
|
|
{
|
|
/* Found it */
|
|
break;
|
|
}
|
|
|
|
/* Keep searching */
|
|
Next = ComponentEntry;
|
|
ComponentEntry = KeFindConfigurationNextEntry(LoaderBlock->ConfigurationRoot,
|
|
AdapterClass,
|
|
MultiFunctionAdapter,
|
|
NULL,
|
|
&Next);
|
|
}
|
|
|
|
/* Make sure we found it */
|
|
if (!ComponentEntry)
|
|
{
|
|
DPRINT1("**** HalpAcpiFindRsdtPhase0: did NOT find RSDT\n");
|
|
return STATUS_NOT_FOUND;
|
|
}
|
|
|
|
/* The configuration data is a resource list, and the BIOS node follows */
|
|
ResourceList = ComponentEntry->ConfigurationData;
|
|
NodeData = (PACPI_BIOS_MULTI_NODE)(ResourceList + 1);
|
|
|
|
/* How many E820 memory entries are there? */
|
|
NodeLength = sizeof(ACPI_BIOS_MULTI_NODE) +
|
|
(NodeData->Count - 1) * sizeof(ACPI_E820_ENTRY);
|
|
|
|
/* Convert to pages */
|
|
PageCount = (PFN_COUNT)BYTES_TO_PAGES(NodeLength);
|
|
|
|
/* Allocate the memory */
|
|
PhysicalAddress.QuadPart = HalpAllocPhysicalMemory(LoaderBlock,
|
|
0x1000000,
|
|
PageCount,
|
|
FALSE);
|
|
if (PhysicalAddress.QuadPart)
|
|
{
|
|
/* Map it if the allocation worked */
|
|
MappedAddress = HalpMapPhysicalMemory64(PhysicalAddress, PageCount);
|
|
}
|
|
else
|
|
{
|
|
/* Otherwise we'll have to fail */
|
|
MappedAddress = NULL;
|
|
}
|
|
|
|
/* Save the multi node, bail out if we didn't find it */
|
|
HalpAcpiMultiNode = MappedAddress;
|
|
if (!MappedAddress) return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
/* Copy the multi-node data */
|
|
RtlCopyMemory(MappedAddress, NodeData, NodeLength);
|
|
|
|
/* Return the data */
|
|
*AcpiMultiNode = HalpAcpiMultiNode;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
HalpAcpiTableCacheInit(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
|
|
{
|
|
PACPI_BIOS_MULTI_NODE AcpiMultiNode;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PHYSICAL_ADDRESS PhysicalAddress;
|
|
PVOID MappedAddress;
|
|
ULONG TableLength;
|
|
PRSDT Rsdt;
|
|
PLOADER_PARAMETER_EXTENSION LoaderExtension;
|
|
|
|
/* Only initialize once */
|
|
if (HalpAcpiTableCacheList.Flink) return Status;
|
|
|
|
/* Setup the lock and table */
|
|
ExInitializeFastMutex(&HalpAcpiTableCacheLock);
|
|
InitializeListHead(&HalpAcpiTableCacheList);
|
|
|
|
/* Find the RSDT */
|
|
Status = HalpAcpiFindRsdtPhase0(LoaderBlock, &AcpiMultiNode);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
PhysicalAddress.QuadPart = AcpiMultiNode->RsdtAddress.QuadPart;
|
|
|
|
/* Map the RSDT */
|
|
if (LoaderBlock)
|
|
{
|
|
/* Phase0: Use HAL Heap to map the RSDT, we assume it's about 2 pages */
|
|
MappedAddress = HalpMapPhysicalMemory64(PhysicalAddress, 2);
|
|
}
|
|
else
|
|
{
|
|
/* Use an I/O map */
|
|
MappedAddress = MmMapIoSpace(PhysicalAddress, PAGE_SIZE * 2, MmNonCached);
|
|
}
|
|
|
|
/* Get the RSDT */
|
|
Rsdt = MappedAddress;
|
|
if (!MappedAddress)
|
|
{
|
|
/* Fail, no memory */
|
|
DPRINT1("HAL: Failed to map RSDT\n");
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
/* Validate it */
|
|
if ((Rsdt->Header.Signature != RSDT_SIGNATURE) &&
|
|
(Rsdt->Header.Signature != XSDT_SIGNATURE))
|
|
{
|
|
/* Very bad: crash */
|
|
HalDisplayString("Bad RSDT pointer\r\n");
|
|
KeBugCheckEx(MISMATCHED_HAL, 4, __LINE__, 0, 0);
|
|
}
|
|
|
|
/* We assumed two pages -- do we need less or more? */
|
|
TableLength = ADDRESS_AND_SIZE_TO_SPAN_PAGES(PhysicalAddress.LowPart,
|
|
Rsdt->Header.Length);
|
|
if (TableLength != 2)
|
|
{
|
|
/* Are we in phase 0 or 1? */
|
|
if (!LoaderBlock)
|
|
{
|
|
/* Unmap the old table, remap the new one, using Mm I/O space */
|
|
MmUnmapIoSpace(MappedAddress, 2 * PAGE_SIZE);
|
|
MappedAddress = MmMapIoSpace(PhysicalAddress,
|
|
TableLength << PAGE_SHIFT,
|
|
MmNonCached);
|
|
}
|
|
else
|
|
{
|
|
/* Unmap the old table, remap the new one, using HAL heap */
|
|
HalpUnmapVirtualAddress(MappedAddress, 2);
|
|
MappedAddress = HalpMapPhysicalMemory64(PhysicalAddress, TableLength);
|
|
}
|
|
|
|
/* Get the remapped table */
|
|
Rsdt = MappedAddress;
|
|
if (!MappedAddress)
|
|
{
|
|
/* Fail, no memory */
|
|
DPRINT1("HAL: Couldn't remap RSDT\n");
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
|
|
/* Now take the BIOS copy and make our own local copy */
|
|
Rsdt = HalpAcpiCopyBiosTable(LoaderBlock, &Rsdt->Header);
|
|
if (!Rsdt)
|
|
{
|
|
/* Fail, no memory */
|
|
DPRINT1("HAL: Couldn't remap RSDT\n");
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
/* Get rid of the BIOS mapping */
|
|
if (LoaderBlock)
|
|
{
|
|
/* Use HAL heap */
|
|
HalpUnmapVirtualAddress(MappedAddress, TableLength);
|
|
|
|
LoaderExtension = LoaderBlock->Extension;
|
|
}
|
|
else
|
|
{
|
|
/* Use Mm */
|
|
MmUnmapIoSpace(MappedAddress, TableLength << PAGE_SHIFT);
|
|
|
|
LoaderExtension = NULL;
|
|
}
|
|
|
|
/* Cache the RSDT */
|
|
HalpAcpiCacheTable(&Rsdt->Header);
|
|
|
|
/* Check for compatible loader block extension */
|
|
if (LoaderExtension && (LoaderExtension->Size >= 0x58))
|
|
{
|
|
/* Compatible loader: did it provide an ACPI table override? */
|
|
if ((LoaderExtension->AcpiTable) && (LoaderExtension->AcpiTableSize))
|
|
{
|
|
/* Great, because we don't support it! */
|
|
DPRINT1("ACPI Table Overrides Not Supported!\n");
|
|
}
|
|
}
|
|
|
|
/* Done */
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
HaliAcpiTimerInit(IN ULONG TimerPort,
|
|
IN ULONG TimerValExt)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
/* Is this in the init phase? */
|
|
if (!TimerPort)
|
|
{
|
|
/* Get the data from the FADT */
|
|
TimerPort = HalpFixedAcpiDescTable.pm_tmr_blk_io_port;
|
|
TimerValExt = HalpFixedAcpiDescTable.flags & ACPI_TMR_VAL_EXT;
|
|
DPRINT1("ACPI Timer at: %Xh (EXT: %d)\n", TimerPort, TimerValExt);
|
|
}
|
|
|
|
/* FIXME: Now proceed to the timer initialization */
|
|
//HalaAcpiTimerInit(TimerPort, TimerValExt);
|
|
}
|
|
|
|
INIT_FUNCTION
|
|
NTSTATUS
|
|
NTAPI
|
|
HalpSetupAcpiPhase0(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
|
|
{
|
|
NTSTATUS Status;
|
|
PFADT Fadt;
|
|
ULONG TableLength;
|
|
PHYSICAL_ADDRESS PhysicalAddress;
|
|
|
|
/* Only do this once */
|
|
if (HalpProcessedACPIPhase0) return STATUS_SUCCESS;
|
|
|
|
/* Setup the ACPI table cache */
|
|
Status = HalpAcpiTableCacheInit(LoaderBlock);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
/* Grab the FADT */
|
|
Fadt = HalAcpiGetTable(LoaderBlock, FADT_SIGNATURE);
|
|
if (!Fadt)
|
|
{
|
|
/* Fail */
|
|
DPRINT1("HAL: Didn't find the FACP\n");
|
|
return STATUS_NOT_FOUND;
|
|
}
|
|
|
|
/* Assume typical size, otherwise whatever the descriptor table says */
|
|
TableLength = sizeof(FADT);
|
|
if (Fadt->Header.Length < sizeof(FADT)) TableLength = Fadt->Header.Length;
|
|
|
|
/* Copy it in the HAL static buffer */
|
|
RtlCopyMemory(&HalpFixedAcpiDescTable, Fadt, TableLength);
|
|
|
|
/* Anything special this HAL needs to do? */
|
|
HalpAcpiDetectMachineSpecificActions(LoaderBlock, &HalpFixedAcpiDescTable);
|
|
|
|
/* Get the debug table for KD */
|
|
HalpDebugPortTable = HalAcpiGetTable(LoaderBlock, DBGP_SIGNATURE);
|
|
|
|
/* Initialize NUMA through the SRAT */
|
|
HalpNumaInitializeStaticConfiguration(LoaderBlock);
|
|
|
|
/* Initialize hotplug through the SRAT */
|
|
HalpDynamicSystemResourceConfiguration(LoaderBlock);
|
|
if (HalpAcpiSrat)
|
|
{
|
|
DPRINT1("Your machine has a SRAT, but NUMA/HotPlug are not supported!\n");
|
|
}
|
|
|
|
/* Can there be memory higher than 4GB? */
|
|
if (HalpMaxHotPlugMemoryAddress.HighPart >= 1)
|
|
{
|
|
/* We'll need this for DMA later */
|
|
HalpPhysicalMemoryMayAppearAbove4GB = TRUE;
|
|
}
|
|
|
|
/* Setup the ACPI timer */
|
|
HaliAcpiTimerInit(0, 0);
|
|
|
|
/* Do we have a low stub address yet? */
|
|
if (!HalpLowStubPhysicalAddress.QuadPart)
|
|
{
|
|
/* Allocate it */
|
|
HalpLowStubPhysicalAddress.QuadPart = HalpAllocPhysicalMemory(LoaderBlock,
|
|
0x100000,
|
|
1,
|
|
FALSE);
|
|
if (HalpLowStubPhysicalAddress.QuadPart)
|
|
{
|
|
/* Map it */
|
|
HalpLowStub = HalpMapPhysicalMemory64(HalpLowStubPhysicalAddress, 1);
|
|
}
|
|
}
|
|
|
|
/* Grab a page for flushes */
|
|
PhysicalAddress.QuadPart = 0x100000;
|
|
HalpVirtAddrForFlush = HalpMapPhysicalMemory64(PhysicalAddress, 1);
|
|
HalpPteForFlush = HalAddressToPte(HalpVirtAddrForFlush);
|
|
|
|
/* Don't do this again */
|
|
HalpProcessedACPIPhase0 = TRUE;
|
|
|
|
/* Setup the boot table */
|
|
HalpInitBootTable(LoaderBlock);
|
|
|
|
/* Debugging code */
|
|
{
|
|
PLIST_ENTRY ListHead, NextEntry;
|
|
PACPI_CACHED_TABLE CachedTable;
|
|
|
|
/* Loop cached tables */
|
|
ListHead = &HalpAcpiTableCacheList;
|
|
NextEntry = ListHead->Flink;
|
|
while (NextEntry != ListHead)
|
|
{
|
|
/* Get the table */
|
|
CachedTable = CONTAINING_RECORD(NextEntry, ACPI_CACHED_TABLE, Links);
|
|
|
|
/* Compare signatures */
|
|
if ((CachedTable->Header.Signature == RSDT_SIGNATURE) ||
|
|
(CachedTable->Header.Signature == XSDT_SIGNATURE))
|
|
{
|
|
DPRINT1("ACPI %d.0 Detected. Tables: ", (CachedTable->Header.Revision + 1));
|
|
}
|
|
|
|
DbgPrint("[%c%c%c%c] ",
|
|
(CachedTable->Header.Signature & 0xFF),
|
|
(CachedTable->Header.Signature & 0xFF00) >> 8,
|
|
(CachedTable->Header.Signature & 0xFF0000) >> 16,
|
|
(CachedTable->Header.Signature & 0xFF000000) >> 24);
|
|
|
|
/* Keep going */
|
|
NextEntry = NextEntry->Flink;
|
|
}
|
|
DbgPrint("\n");
|
|
}
|
|
|
|
/* Return success */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
INIT_FUNCTION
|
|
VOID
|
|
NTAPI
|
|
HalpInitializePciBus(VOID)
|
|
{
|
|
/* Setup the PCI stub support */
|
|
HalpInitializePciStubs();
|
|
|
|
/* Set the NMI crash flag */
|
|
HalpGetNMICrashFlag();
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
HalpInitNonBusHandler(VOID)
|
|
{
|
|
/* These should be written by the PCI driver later, but we give defaults */
|
|
HalPciTranslateBusAddress = HalpTranslateBusAddress;
|
|
HalPciAssignSlotResources = HalpAssignSlotResources;
|
|
HalFindBusAddressTranslation = HalpFindBusAddressTranslation;
|
|
}
|
|
|
|
INIT_FUNCTION
|
|
VOID
|
|
NTAPI
|
|
HalpInitBusHandlers(VOID)
|
|
{
|
|
/* On ACPI, we only have a fake PCI bus to worry about */
|
|
HalpInitNonBusHandler();
|
|
}
|
|
|
|
INIT_FUNCTION
|
|
VOID
|
|
NTAPI
|
|
HalpBuildAddressMap(VOID)
|
|
{
|
|
/* ACPI is magic baby */
|
|
}
|
|
|
|
INIT_FUNCTION
|
|
BOOLEAN
|
|
NTAPI
|
|
HalpGetDebugPortTable(VOID)
|
|
{
|
|
return ((HalpDebugPortTable) &&
|
|
(HalpDebugPortTable->BaseAddress.AddressSpaceID == 1));
|
|
}
|
|
|
|
INIT_FUNCTION
|
|
ULONG
|
|
NTAPI
|
|
HalpIs16BitPortDecodeSupported(VOID)
|
|
{
|
|
/* All ACPI systems are at least "EISA" so they support this */
|
|
return CM_RESOURCE_PORT_16_BIT_DECODE;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
HalpAcpiDetectResourceListSize(OUT PULONG ListSize)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
/* One element if there is a SCI */
|
|
*ListSize = HalpFixedAcpiDescTable.sci_int_vector ? 1: 0;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
HalpBuildAcpiResourceList(IN PIO_RESOURCE_REQUIREMENTS_LIST ResourceList)
|
|
{
|
|
ULONG Interrupt;
|
|
PAGED_CODE();
|
|
ASSERT(ResourceList != NULL);
|
|
|
|
/* Initialize the list */
|
|
ResourceList->BusNumber = -1;
|
|
ResourceList->AlternativeLists = 1;
|
|
ResourceList->InterfaceType = PNPBus;
|
|
ResourceList->List[0].Version = 1;
|
|
ResourceList->List[0].Revision = 1;
|
|
ResourceList->List[0].Count = 0;
|
|
|
|
/* Is there a SCI? */
|
|
if (HalpFixedAcpiDescTable.sci_int_vector)
|
|
{
|
|
/* Fill out the entry for it */
|
|
ResourceList->List[0].Descriptors[0].Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
|
|
ResourceList->List[0].Descriptors[0].Type = CmResourceTypeInterrupt;
|
|
ResourceList->List[0].Descriptors[0].ShareDisposition = CmResourceShareShared;
|
|
|
|
/* Get the interrupt number */
|
|
Interrupt = HalpPicVectorRedirect[HalpFixedAcpiDescTable.sci_int_vector];
|
|
ResourceList->List[0].Descriptors[0].u.Interrupt.MinimumVector = Interrupt;
|
|
ResourceList->List[0].Descriptors[0].u.Interrupt.MaximumVector = Interrupt;
|
|
|
|
/* One more */
|
|
++ResourceList->List[0].Count;
|
|
}
|
|
|
|
/* All good */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
HalpQueryAcpiResourceRequirements(OUT PIO_RESOURCE_REQUIREMENTS_LIST *Requirements)
|
|
{
|
|
PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
|
|
ULONG Count = 0, ListSize;
|
|
NTSTATUS Status;
|
|
PAGED_CODE();
|
|
|
|
/* Get ACPI resources */
|
|
HalpAcpiDetectResourceListSize(&Count);
|
|
DPRINT("Resource count: %d\n", Count);
|
|
|
|
/* Compute size of the list and allocate it */
|
|
ListSize = FIELD_OFFSET(IO_RESOURCE_REQUIREMENTS_LIST, List[0].Descriptors) +
|
|
(Count * sizeof(IO_RESOURCE_DESCRIPTOR));
|
|
DPRINT("Resource list size: %d\n", ListSize);
|
|
RequirementsList = ExAllocatePoolWithTag(PagedPool, ListSize, TAG_HAL);
|
|
if (RequirementsList)
|
|
{
|
|
/* Initialize it */
|
|
RtlZeroMemory(RequirementsList, ListSize);
|
|
RequirementsList->ListSize = ListSize;
|
|
|
|
/* Build it */
|
|
Status = HalpBuildAcpiResourceList(RequirementsList);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* It worked, return it */
|
|
*Requirements = RequirementsList;
|
|
|
|
/* Validate the list */
|
|
ASSERT(RequirementsList->List[0].Count == Count);
|
|
}
|
|
else
|
|
{
|
|
/* Fail */
|
|
ExFreePoolWithTag(RequirementsList, TAG_HAL);
|
|
Status = STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Not enough memory */
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
/* Return the status */
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
INIT_FUNCTION
|
|
VOID
|
|
NTAPI
|
|
HalReportResourceUsage(VOID)
|
|
{
|
|
INTERFACE_TYPE InterfaceType;
|
|
UNICODE_STRING HalString;
|
|
|
|
/* FIXME: Initialize DMA 64-bit support */
|
|
|
|
/* FIXME: Initialize MCA bus */
|
|
|
|
/* Initialize PCI bus. */
|
|
HalpInitializePciBus();
|
|
|
|
/* What kind of bus is this? */
|
|
switch (HalpBusType)
|
|
{
|
|
/* ISA Machine */
|
|
case MACHINE_TYPE_ISA:
|
|
InterfaceType = Isa;
|
|
break;
|
|
|
|
/* EISA Machine */
|
|
case MACHINE_TYPE_EISA:
|
|
InterfaceType = Eisa;
|
|
break;
|
|
|
|
/* MCA Machine */
|
|
case MACHINE_TYPE_MCA:
|
|
InterfaceType = MicroChannel;
|
|
break;
|
|
|
|
/* Unknown */
|
|
default:
|
|
InterfaceType = Internal;
|
|
break;
|
|
}
|
|
|
|
/* Build HAL usage */
|
|
RtlInitUnicodeString(&HalString, HalName);
|
|
HalpReportResourceUsage(&HalString, InterfaceType);
|
|
|
|
/* Setup PCI debugging and Hibernation */
|
|
HalpRegisterPciDebuggingDeviceInfo();
|
|
}
|
|
|
|
/* EOF */
|