mirror of
https://github.com/reactos/reactos.git
synced 2024-11-01 12:26:32 +00:00
516ccad340
Co-authored-by: Victor Perevertkin <victor.perevertkin@reactos.org> Introduce the initial changes needed to get other processors up and into kernel mode. This only supports x86 as of now but is the first real step towards using other system processors.
1117 lines
31 KiB
C
1117 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: %lXh (EXT: %lu)\n", TimerPort, TimerValExt);
|
|
}
|
|
|
|
/* FIXME: Now proceed to the timer initialization */
|
|
//HalaAcpiTimerInit(TimerPort, TimerValExt);
|
|
}
|
|
|
|
CODE_SEG("INIT")
|
|
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,
|
|
HALP_LOW_STUB_SIZE_IN_PAGES,
|
|
FALSE);
|
|
if (HalpLowStubPhysicalAddress.QuadPart)
|
|
{
|
|
/* Map it */
|
|
HalpLowStub = HalpMapPhysicalMemory64(HalpLowStubPhysicalAddress, HALP_LOW_STUB_SIZE_IN_PAGES);
|
|
}
|
|
}
|
|
|
|
/* 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 %u.0 Detected. Tables:", CachedTable->Header.Revision + 1);
|
|
}
|
|
|
|
DbgPrint(" [%c%c%c%c]",
|
|
CachedTable->Header.Signature & 0x000000FF,
|
|
(CachedTable->Header.Signature & 0x0000FF00) >> 8,
|
|
(CachedTable->Header.Signature & 0x00FF0000) >> 16,
|
|
(CachedTable->Header.Signature & 0xFF000000) >> 24);
|
|
|
|
/* Keep going */
|
|
NextEntry = NextEntry->Flink;
|
|
}
|
|
DbgPrint("\n");
|
|
}
|
|
|
|
/* Return success */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
CODE_SEG("INIT")
|
|
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;
|
|
}
|
|
|
|
CODE_SEG("INIT")
|
|
VOID
|
|
NTAPI
|
|
HalpInitBusHandlers(VOID)
|
|
{
|
|
/* On ACPI, we only have a fake PCI bus to worry about */
|
|
HalpInitNonBusHandler();
|
|
}
|
|
|
|
CODE_SEG("INIT")
|
|
VOID
|
|
NTAPI
|
|
HalpBuildAddressMap(VOID)
|
|
{
|
|
/* ACPI is magic baby */
|
|
}
|
|
|
|
CODE_SEG("INIT")
|
|
BOOLEAN
|
|
NTAPI
|
|
HalpGetDebugPortTable(VOID)
|
|
{
|
|
return ((HalpDebugPortTable) &&
|
|
(HalpDebugPortTable->BaseAddress.AddressSpaceID == 1));
|
|
}
|
|
|
|
CODE_SEG("INIT")
|
|
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, ListSize;
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
/* Get ACPI resources */
|
|
HalpAcpiDetectResourceListSize(&Count);
|
|
DPRINT("Resource count: %lu\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: %lu\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
|
|
*/
|
|
CODE_SEG("INIT")
|
|
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 */
|