You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1223 lines
34 KiB
1223 lines
34 KiB
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
loaddsdt.c
|
|
|
|
Abstract:
|
|
|
|
This handles loading the DSDT table and all steps leading up to it
|
|
|
|
Author:
|
|
|
|
Stephane Plante (splante)
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
02-Jun-97 Initial Revision
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
#include "amlreg.h"
|
|
#include <stdio.h>
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE,ACPILoadFindRSDT)
|
|
#pragma alloc_text(PAGE,ACPILoadProcessDSDT)
|
|
#pragma alloc_text(PAGE,ACPILoadProcessFADT)
|
|
#pragma alloc_text(PAGE,ACPILoadProcessFACS)
|
|
#pragma alloc_text(PAGE,ACPILoadProcessRSDT)
|
|
#pragma alloc_text(PAGE,ACPILoadTableCheckSum)
|
|
#endif
|
|
|
|
#if DBG
|
|
BOOLEAN AcpiLoadSimulatorTable = TRUE;
|
|
#else
|
|
BOOLEAN AcpiLoadSimulatorTable = FALSE;
|
|
#endif
|
|
|
|
|
|
PRSDT
|
|
ACPILoadFindRSDT(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine looks at the registry to find the value stored there by
|
|
ntdetect.com
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Pointer to the RSDT
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
PACPI_BIOS_MULTI_NODE rsdpMulti;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR cmPartialDesc;
|
|
PCM_PARTIAL_RESOURCE_LIST cmPartialList;
|
|
PHYSICAL_ADDRESS PhysAddress = {0};
|
|
PKEY_VALUE_PARTIAL_INFORMATION_ALIGN64 keyInfo;
|
|
PRSDT rsdtBuffer = NULL;
|
|
PRSDT rsdtPointer;
|
|
ULONG MemSpace = 0;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Read the key for that AcpiConfigurationData
|
|
//
|
|
status = OSReadAcpiConfigurationData( &keyInfo );
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPILoadFindRSDT: Cannot open Configuration Data - 0x%08lx\n",
|
|
status
|
|
) );
|
|
ACPIBreakPoint();
|
|
return NULL;
|
|
|
|
}
|
|
|
|
//
|
|
// Crack the structure
|
|
//
|
|
cmPartialList = (PCM_PARTIAL_RESOURCE_LIST) (keyInfo->Data);
|
|
cmPartialDesc = &(cmPartialList->PartialDescriptors[0]);
|
|
rsdpMulti = (PACPI_BIOS_MULTI_NODE) ( (PUCHAR) cmPartialDesc +
|
|
sizeof(CM_PARTIAL_RESOURCE_LIST) );
|
|
|
|
//
|
|
// Read the Header part of the table
|
|
//
|
|
|
|
PhysAddress.QuadPart = rsdpMulti->RsdtAddress.QuadPart;
|
|
rsdtPointer = MmMapIoSpace(
|
|
PhysAddress,
|
|
sizeof(DESCRIPTION_HEADER),
|
|
MmNonCached
|
|
);
|
|
|
|
if (rsdtPointer == NULL) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPILoadFindRsdt: Cannot Map RSDT Pointer 0x%08lx\n",
|
|
rsdpMulti->RsdtAddress.LowPart
|
|
) );
|
|
ACPIBreakPoint();
|
|
goto RsdtDone;
|
|
|
|
} else if ((rsdtPointer->Header.Signature != RSDT_SIGNATURE) &&
|
|
(rsdtPointer->Header.Signature != XSDT_SIGNATURE)) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPILoadFindRsdt: RSDT 0x%08lx has invalid signature\n",
|
|
rsdtPointer
|
|
) );
|
|
ACPIBreakPoint();
|
|
goto RsdtDone;
|
|
|
|
}
|
|
|
|
//
|
|
// Read the entire RSDT
|
|
//
|
|
rsdtBuffer = MmMapIoSpace(
|
|
PhysAddress,
|
|
rsdtPointer->Header.Length,
|
|
MmNonCached
|
|
);
|
|
|
|
//
|
|
// Give back a PTE now that we're done with the rsdtPointer.
|
|
//
|
|
MmUnmapIoSpace(rsdtPointer, sizeof(DESCRIPTION_HEADER));
|
|
|
|
//
|
|
// did we find the right rsdt buffer?
|
|
//
|
|
if (rsdtBuffer == NULL) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPILoadFindRsdt: Cannot Map RSDT Pointer 0x%08lx\n",
|
|
rsdpMulti->RsdtAddress.LowPart
|
|
) );
|
|
ACPIBreakPoint();
|
|
goto RsdtDone;
|
|
|
|
}
|
|
|
|
RsdtDone:
|
|
//
|
|
// Done with these buffers
|
|
//
|
|
|
|
ExFreePool( keyInfo );
|
|
|
|
//
|
|
// return the RSDT
|
|
//
|
|
return rsdtBuffer;
|
|
}
|
|
|
|
NTSTATUS
|
|
ACPILoadProcessDSDT(
|
|
ULONG_PTR Address
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine loads the DSDT (a pointer is stored in the FADT) and forces
|
|
the interpreter to process it
|
|
|
|
Arguments:
|
|
|
|
Address - Where the DSDT is located in memory
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
|
|
BOOLEAN foundOverride;
|
|
PDSDT linAddress;
|
|
ULONG index;
|
|
ULONG length;
|
|
ULONG MemSpace = 0;
|
|
PHYSICAL_ADDRESS PhysAddress = {0};
|
|
|
|
//
|
|
// Map the header in virtual address space to get the length
|
|
//
|
|
PhysAddress.QuadPart = (ULONGLONG) Address;
|
|
linAddress = MmMapIoSpace(
|
|
PhysAddress,
|
|
sizeof(DESCRIPTION_HEADER),
|
|
MmNonCached
|
|
);
|
|
if (linAddress == NULL) {
|
|
|
|
ASSERT (linAddress != NULL);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
if ( linAddress->Header.Signature != DSDT_SIGNATURE) {
|
|
|
|
//
|
|
// Signature should have matched DSDT but didn't !
|
|
//
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPILoadProcessDSDT: 0x%08lx does not have DSDT signature\n",
|
|
linAddress
|
|
) );
|
|
return STATUS_ACPI_INVALID_TABLE;
|
|
|
|
}
|
|
|
|
//
|
|
// Determine the size of the DSDT
|
|
//
|
|
length = linAddress->Header.Length;
|
|
|
|
//
|
|
// Now map the whole thing.
|
|
//
|
|
MmUnmapIoSpace(linAddress, sizeof(DESCRIPTION_HEADER));
|
|
linAddress = MmMapIoSpace(
|
|
PhysAddress,
|
|
length,
|
|
MmNonCached
|
|
);
|
|
if (linAddress == NULL) {
|
|
|
|
ASSERT (linAddress != NULL);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
//
|
|
// Look at the RsdtInformation to determine the index of the last
|
|
// element in the table. We know that we can use that space to store
|
|
// the information about this table
|
|
//
|
|
index = RsdtInformation->NumElements;
|
|
if (index == 0) {
|
|
|
|
return STATUS_ACPI_NOT_INITIALIZED;
|
|
|
|
}
|
|
index--;
|
|
|
|
//
|
|
// Try to read the DSDT from the registry
|
|
//
|
|
foundOverride = ACPIRegReadAMLRegistryEntry( &linAddress, TRUE );
|
|
if (foundOverride) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_WARNING,
|
|
"ACPILoadProcessDSDT: DSDT Overloaded from registry (0x%08lx)\n",
|
|
linAddress
|
|
) );
|
|
RsdtInformation->Tables[index].Flags |= RSDTELEMENT_OVERRIDEN;
|
|
|
|
}
|
|
|
|
//
|
|
// Store a pointer to the DSDT
|
|
//
|
|
AcpiInformation->DiffSystemDescTable = linAddress;
|
|
|
|
//
|
|
// Remember this address and that we need to unmap it
|
|
//
|
|
RsdtInformation->Tables[index].Flags |=
|
|
(RSDTELEMENT_MAPPED | RSDTELEMENT_LOADABLE);
|
|
RsdtInformation->Tables[index].Address = linAddress;
|
|
|
|
//
|
|
// Done
|
|
//
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
ACPILoadProcessFACS(
|
|
ULONG_PTR Address
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles the FACS
|
|
|
|
Arguments:
|
|
|
|
Address - Where the FACS is located
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PFACS linAddress;
|
|
ULONG MemSpace = 0;
|
|
PHYSICAL_ADDRESS PhysAddress = {0};
|
|
|
|
// Note: On Alpha, the FACS is optional.
|
|
//
|
|
// Return if FACS address is not valid.
|
|
//
|
|
if (!Address) {
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
//
|
|
// Map the FACS into virtual address space.
|
|
//
|
|
PhysAddress.QuadPart = (ULONGLONG) Address;
|
|
|
|
linAddress = MmMapIoSpace(
|
|
PhysAddress,
|
|
sizeof(FACS),
|
|
MmNonCached
|
|
);
|
|
if (linAddress == NULL) {
|
|
|
|
ASSERT (linAddress != NULL);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
if (linAddress->Signature != FACS_SIGNATURE) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPILoadProcessFACS: 0x%08lx does not have FACS signature\n",
|
|
linAddress
|
|
) );
|
|
return STATUS_ACPI_INVALID_TABLE;
|
|
|
|
}
|
|
|
|
if (linAddress->Length != sizeof(FACS)) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPILoadProcessFACS: 0x%08lx does not have correct FACS length\n",
|
|
linAddress
|
|
) );
|
|
return STATUS_ACPI_INVALID_TABLE;
|
|
|
|
}
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_LOADING,
|
|
"ACPILoadProcessFACS: FACS located at 0x%8lx\n",
|
|
linAddress
|
|
) );
|
|
AcpiInformation->FirmwareACPIControlStructure = linAddress;
|
|
|
|
//
|
|
// And store the address of the GlobalLock structure that lives within
|
|
// the FACS
|
|
//
|
|
AcpiInformation->GlobalLock = &(ULONG)(linAddress->GlobalLock);
|
|
ACPIPrint( (
|
|
ACPI_PRINT_LOADING,
|
|
"ACPILoadProcessFACS: Initial GlobalLock state: 0x%8lx\n",
|
|
*(AcpiInformation->GlobalLock)
|
|
) );
|
|
|
|
//
|
|
// At this point, we are successfull
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
ULONG_PTR
|
|
GetFadtTablePointerEntry(
|
|
PFADT Fadt,
|
|
PULONG LegacyAddress,
|
|
PGEN_ADDR NonLegacyAddress,
|
|
SIZE_T Size
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine reads an address field from the FADT. If the Fadt revision
|
|
is too old, we use the legacy address. If it's new enough, the generic
|
|
register address data is used. If necessary, the address is mapped into
|
|
memory.
|
|
|
|
KB. Do not access NonLegacyAddress if the table revision does not support
|
|
the NonLegacyAddress, as this will be pointing to a bogus memory location
|
|
and could cause an illegal memory access.
|
|
|
|
Arguments:
|
|
|
|
Fadt - Pointer to the Fadt
|
|
LegacyAddress - Pointer to legacy address.
|
|
NonLegacyAddress - Pointer to non-legacy address.
|
|
Size - size of entry that address points to.
|
|
|
|
Return Value:
|
|
|
|
a valid pointer to the table entry, or NULL if it's invalid.
|
|
|
|
--*/
|
|
{
|
|
ULONG_PTR ReturnValue;
|
|
|
|
//
|
|
// revision 3 and greater of FADT define a generic register address
|
|
// structure. Before that version we just have to use the legacy address.
|
|
//
|
|
if (Fadt->Header.Revision < 3) {
|
|
ReturnValue = *LegacyAddress;
|
|
} else {
|
|
|
|
switch(NonLegacyAddress->AddressSpaceID) {
|
|
|
|
case AcpiGenericSpaceIO:
|
|
ReturnValue = (ULONG_PTR)NonLegacyAddress->Address.QuadPart;
|
|
break;
|
|
|
|
case AcpiGenericSpaceMemory:
|
|
//
|
|
// MmMapIoSpace hates it if you pass in zero, so guard against
|
|
// this.
|
|
//
|
|
if (NonLegacyAddress->Address.QuadPart == 0) {
|
|
ReturnValue = (ULONG_PTR)0;
|
|
} else {
|
|
ReturnValue = (ULONG_PTR)MmMapIoSpace(
|
|
NonLegacyAddress->Address,
|
|
Size,
|
|
MmNonCached );
|
|
|
|
//
|
|
// right now, assume all or nothing -- if any of the
|
|
// items in the FADT are marked as MMIO space, they
|
|
// all are, and we must use register-based access to
|
|
// access the backing hardware.
|
|
//
|
|
if ( ReturnValue &&
|
|
(AcpiReadRegisterRoutine == DefPortReadAcpiRegister) &&
|
|
(AcpiWriteRegisterRoutine == DefPortWriteAcpiRegister) ) {
|
|
AcpiReadRegisterRoutine = DefRegisterReadAcpiRegister;
|
|
AcpiWriteRegisterRoutine = DefRegisterWriteAcpiRegister;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ASSERT(FALSE);
|
|
ReturnValue = 0;
|
|
}
|
|
}
|
|
|
|
|
|
#ifndef IA64
|
|
//
|
|
// We don't want to support this part of acpi 2.0 for anything other
|
|
// than ia64 for the windows server release. we don't want to risk
|
|
// breaking bios's that get this table information incorrect. we will turn
|
|
// this on when we have a full testing cycle available.
|
|
//
|
|
ReturnValue = *LegacyAddress;
|
|
|
|
if ( (AcpiReadRegisterRoutine == DefRegisterReadAcpiRegister) &&
|
|
(AcpiWriteRegisterRoutine == DefRegisterWriteAcpiRegister)) {
|
|
AcpiReadRegisterRoutine = DefPortReadAcpiRegister;
|
|
AcpiWriteRegisterRoutine = DefPortWriteAcpiRegister;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
return(ReturnValue);
|
|
|
|
}
|
|
|
|
|
|
#define GET_FADT_TABLE_ENTRY(_fadt,_legacyaddr,_nonlegacyaddr,_size) \
|
|
( GetFadtTablePointerEntry( _fadt, &_fadt->_legacyaddr, &_fadt->_nonlegacyaddr, _size ) )
|
|
|
|
|
|
NTSTATUS
|
|
ACPILoadProcessFADT(
|
|
PFADT Fadt
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This reads the FADT and stores some useful information in the
|
|
information structure
|
|
|
|
Arguments:
|
|
|
|
Fadt - Pointer to the Fadt
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
KAFFINITY processors;
|
|
NTSTATUS status;
|
|
PUCHAR gpeTable;
|
|
PDSDT linAddress;
|
|
ULONG length;
|
|
ULONG totalSize;
|
|
ULONG MemSpace = 0;
|
|
PHYSICAL_ADDRESS PhysAddress = {0};
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// This is a 2.0-level FADT.
|
|
//
|
|
|
|
//
|
|
// Handle the FACS part of the FADT. We must do this before the DSDT
|
|
// so that we have the global lock mapped and initialized.
|
|
//
|
|
#ifdef IA64
|
|
status = ACPILoadProcessFACS( (Fadt->Header.Revision < 3)
|
|
? Fadt->facs
|
|
: (ULONG_PTR)Fadt->x_firmware_ctrl.QuadPart );
|
|
#else
|
|
//
|
|
// get rid of this ifdef once we have a full testing cycle available for
|
|
// catching any broken firmware
|
|
//
|
|
status = ACPILoadProcessFACS(Fadt->facs);
|
|
#endif
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
//
|
|
// Store the I/O addresses of PM1a_BLK, PM1b_BLK, PM1a_CNT, PM1b_CNT,
|
|
// PM2_CNT, PM_TMR
|
|
//
|
|
|
|
AcpiInformation->PM1a_BLK = GET_FADT_TABLE_ENTRY(Fadt,
|
|
pm1a_evt_blk_io_port,
|
|
x_pm1a_evt_blk,
|
|
sizeof(ULONG_PTR));
|
|
|
|
AcpiInformation->PM1b_BLK = GET_FADT_TABLE_ENTRY(Fadt,
|
|
pm1b_evt_blk_io_port,
|
|
x_pm1b_evt_blk,
|
|
sizeof(ULONG_PTR));
|
|
|
|
AcpiInformation->PM1a_CTRL_BLK = GET_FADT_TABLE_ENTRY(Fadt,
|
|
pm1a_ctrl_blk_io_port,
|
|
x_pm1a_ctrl_blk,
|
|
sizeof(ULONG_PTR));
|
|
|
|
AcpiInformation->PM1b_CTRL_BLK = GET_FADT_TABLE_ENTRY(Fadt,
|
|
pm1b_ctrl_blk_io_port,
|
|
x_pm1b_ctrl_blk,
|
|
sizeof(ULONG_PTR));
|
|
|
|
AcpiInformation->PM2_CTRL_BLK = GET_FADT_TABLE_ENTRY(Fadt,
|
|
pm2_ctrl_blk_io_port,
|
|
x_pm2_ctrl_blk,
|
|
sizeof(ULONG_PTR));
|
|
|
|
AcpiInformation->PM_TMR = GET_FADT_TABLE_ENTRY(Fadt,
|
|
pm_tmr_blk_io_port,
|
|
x_pm_tmr_blk,
|
|
sizeof(ULONG_PTR));
|
|
|
|
AcpiInformation->SMI_CMD = (ULONG_PTR) Fadt->smi_cmd_io_port;
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_LOADING,
|
|
"ACPILoadProcessFADT: PM1a_BLK located at port %p\n"
|
|
"ACPILoadProcessFADT: PM1b_BLK located at port %p\n",
|
|
AcpiInformation->PM1a_BLK,
|
|
AcpiInformation->PM1b_BLK
|
|
) );
|
|
ACPIPrint( (
|
|
ACPI_PRINT_LOADING,
|
|
"ACPILoadProcessFADT: PM1a_CTRL_BLK located at port %p\n"
|
|
"ACPILoadProcessFADT: PM1b_CTRL_BLK located at port %p\n",
|
|
AcpiInformation->PM1a_CTRL_BLK,
|
|
AcpiInformation->PM1b_CTRL_BLK
|
|
) );
|
|
ACPIPrint( (
|
|
ACPI_PRINT_LOADING,
|
|
"ACPILoadProcessFADT: PM2_CTRL_BLK located at port %p\n"
|
|
"ACPILoadProcessFADT: PM_TMR located at port %p\n",
|
|
AcpiInformation->PM2_CTRL_BLK,
|
|
AcpiInformation->PM_TMR
|
|
) );
|
|
|
|
//
|
|
// Initialize the global GPE tables.
|
|
//
|
|
// If any of the GPn_BLK addresses are 0 leave GPn_LEN at it's initialized
|
|
// value (0). That way later on we only have to check GPn_LEN to determine
|
|
// the existence of a GP register.
|
|
//
|
|
|
|
//
|
|
// Assume this is true until we find out otherwise
|
|
//
|
|
AcpiInformation->GP1_Base_Index = GP1_NOT_SUPPORTED;
|
|
|
|
//
|
|
// Crack the GP0 block
|
|
//
|
|
AcpiInformation->GP0_BLK = GET_FADT_TABLE_ENTRY(
|
|
Fadt,
|
|
gp0_blk_io_port,
|
|
x_gp0_blk,
|
|
Fadt->gp0_blk_len);
|
|
if (AcpiInformation->GP0_BLK != 0) {
|
|
|
|
AcpiInformation->GP0_LEN = Fadt->gp0_blk_len;
|
|
ACPISimpleFatalHardwareAssert(
|
|
(Fadt->gp0_blk_len != 0),
|
|
ACPI_I_GP_BLK_LEN_0
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// Crack the GP1 Block
|
|
//
|
|
AcpiInformation->GP1_BLK = GET_FADT_TABLE_ENTRY(
|
|
Fadt,
|
|
gp1_blk_io_port,
|
|
x_gp1_blk,
|
|
Fadt->gp1_blk_len);
|
|
if (AcpiInformation->GP1_BLK != 0) {
|
|
|
|
AcpiInformation->GP1_LEN = Fadt->gp1_blk_len;
|
|
AcpiInformation->GP1_Base_Index = Fadt->gp1_base;
|
|
ACPISimpleFatalHardwareAssert (
|
|
(Fadt->gp1_blk_len != 0),
|
|
ACPI_I_GP_BLK_LEN_1
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// Compute sizes of the register blocks. The first half of each block
|
|
// contains status registers, the second half contains the enable registers.
|
|
//
|
|
AcpiInformation->Gpe0Size = AcpiInformation->GP0_LEN / 2;
|
|
AcpiInformation->Gpe1Size = AcpiInformation->GP1_LEN / 2;
|
|
AcpiInformation->GpeSize = AcpiInformation->Gpe0Size +
|
|
AcpiInformation->Gpe1Size;
|
|
|
|
//
|
|
// Addresses of the GPE Enable register blocks
|
|
//
|
|
AcpiInformation->GP0_ENABLE = AcpiInformation->GP0_BLK +
|
|
AcpiInformation->Gpe0Size;
|
|
AcpiInformation->GP1_ENABLE = AcpiInformation->GP1_BLK +
|
|
AcpiInformation->Gpe1Size;
|
|
|
|
//
|
|
// Create all GPE bookeeping tables with a single allocate
|
|
//
|
|
if (AcpiInformation->GpeSize) {
|
|
|
|
totalSize = (AcpiInformation->GpeSize * 12) + // Twelve Bitmaps
|
|
(AcpiInformation->GpeSize * 8); // One bytewide table
|
|
gpeTable = (PUCHAR)ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
totalSize,
|
|
ACPI_SHARED_GPE_POOLTAG
|
|
);
|
|
if (gpeTable == NULL) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPILoadProcessFADT: Could not allocate GPE tables, "
|
|
"size = 0x%8lx\n",
|
|
totalSize
|
|
) );
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
RtlZeroMemory (gpeTable, totalSize);
|
|
|
|
//
|
|
// Setup the table pointers
|
|
//
|
|
GpeEnable = gpeTable;
|
|
GpeCurEnable = GpeEnable + AcpiInformation->GpeSize;
|
|
GpeIsLevel = GpeCurEnable + AcpiInformation->GpeSize;
|
|
GpeHandlerType = GpeIsLevel + AcpiInformation->GpeSize;
|
|
GpeWakeEnable = GpeHandlerType + AcpiInformation->GpeSize;
|
|
GpeWakeHandler = GpeWakeEnable + AcpiInformation->GpeSize;
|
|
GpeSpecialHandler = GpeWakeHandler + AcpiInformation->GpeSize;
|
|
GpePending = GpeSpecialHandler + AcpiInformation->GpeSize;
|
|
GpeRunMethod = GpePending + AcpiInformation->GpeSize;
|
|
GpeComplete = GpeRunMethod + AcpiInformation->GpeSize;
|
|
GpeSavedWakeMask = GpeComplete + AcpiInformation->GpeSize;
|
|
GpeSavedWakeStatus = GpeSavedWakeMask + AcpiInformation->GpeSize;
|
|
GpeMap = GpeSavedWakeStatus+ AcpiInformation->GpeSize;
|
|
|
|
}
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_LOADING,
|
|
"ACPILoadProcessFADT: GP0_BLK located at port %p length 0x%08lx\n"
|
|
"ACPILoadProcessFADT: GP1_BLK located at port %p length 0x%08lx\n"
|
|
"ACPILoadProcessFADT: GP1_Base_Index = 0x%x\n",
|
|
AcpiInformation->GP0_BLK,
|
|
AcpiInformation->GP0_LEN,
|
|
AcpiInformation->GP1_BLK,
|
|
AcpiInformation->GP1_LEN,
|
|
AcpiInformation->GP1_Base_Index
|
|
) );
|
|
|
|
//
|
|
// At this point, we should know enough to be able to turn off and
|
|
// clear all the GPE registers
|
|
//
|
|
ACPIGpeClearRegisters();
|
|
ACPIGpeEnableDisableEvents( FALSE );
|
|
|
|
AcpiInformation->ACPI_Flags = 0;
|
|
AcpiInformation->ACPI_Capabilities = 0;
|
|
|
|
//
|
|
// Can we dock this machine?
|
|
//
|
|
AcpiInformation->Dockable = (Fadt->flags & DCK_CAP) ? TRUE : FALSE;
|
|
|
|
//
|
|
// This code used to be executed from within InitializeAndEnableACPI,
|
|
// however we need to know *while* processing the DSDT what the Enable
|
|
// bits are. To start with, we always want the ACPI timer and GL events
|
|
//
|
|
AcpiInformation->pm1_en_bits = PM1_TMR_EN | PM1_GBL_EN;
|
|
|
|
//
|
|
// Is there a control method Power Button? If not, then there a fixed
|
|
// power button
|
|
//
|
|
|
|
if ( !(Fadt->flags & PWR_BUTTON_GENERIC) ) {
|
|
|
|
AcpiInformation->pm1_en_bits |= PM1_PWRBTN_EN;
|
|
ACPIPrint( (
|
|
ACPI_PRINT_LOADING,
|
|
"ACPILoadProcessFADT: Power Button in Fixed Feature Space\n"
|
|
) );
|
|
|
|
} else {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_LOADING,
|
|
"ACPILoadProcessFADT: Power Button not fixed event or "
|
|
"not present\n"
|
|
) );
|
|
|
|
}
|
|
|
|
//
|
|
// Is there a control method Sleep Button? If not, then the fixed button
|
|
// always doubles as a wake button
|
|
//
|
|
if ( !(Fadt->flags & SLEEP_BUTTON_GENERIC) ){
|
|
|
|
AcpiInformation->pm1_en_bits |= PM1_SLEEPBTN_EN;
|
|
ACPIPrint( (
|
|
ACPI_PRINT_LOADING,
|
|
"ACPILoadProcessFADT: Sleep Button in Fixed Feature Space\n"
|
|
) );
|
|
|
|
} else {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_LOADING,
|
|
"ACPILoadProcessFADT: Sleep Button not fixed event or "
|
|
"not present\n"
|
|
) );
|
|
|
|
}
|
|
|
|
//
|
|
// Handle the DSDT part of the FADT. We handle this last because we
|
|
// need to have the FADT fully parsed before we can load the name space
|
|
// tree. A particular example is the Dockable bit you see directly above.
|
|
//
|
|
#ifdef IA64
|
|
return ACPILoadProcessDSDT( (Fadt->Header.Revision < 3)
|
|
? Fadt->dsdt
|
|
: (ULONG_PTR)Fadt->x_dsdt.QuadPart
|
|
);
|
|
|
|
#else
|
|
return ACPILoadProcessDSDT(Fadt->dsdt);
|
|
#endif
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
ACPILoadProcessRSDT(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called by ACPIInitialize once ACPI has been detected on the machine.
|
|
This walks the tables in the RSDT and fills in the information for the
|
|
global data structure.
|
|
|
|
This routine does *NOT* cause the xDSTs to start loading in the
|
|
interpreter
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Upon entry acpiinformation->RootSystemDescTable contains the linear
|
|
// address of the RSDT walk through the array of the tables pointed to
|
|
// by the RSDT and for each table (whose type we are familiar with)
|
|
// store the linear base address of the table in the acpiinformation
|
|
// structure
|
|
//
|
|
BOOLEAN foundOverride = FALSE;
|
|
BOOLEAN foundFADT = FALSE;
|
|
BOOLEAN usingXSDT = FALSE;
|
|
PDESCRIPTION_HEADER header;
|
|
PVOID linAddress;
|
|
ULONG index;
|
|
ULONG length;
|
|
ULONG numTables;
|
|
ULONG MemSpace = 0;
|
|
PHYSICAL_ADDRESS PhysAddress = {0};
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Get the number of tables
|
|
//
|
|
if (AcpiInformation->RootSystemDescTable->Header.Signature ==
|
|
XSDT_SIGNATURE) {
|
|
|
|
numTables = NumTableEntriesFromXSDTPointer(
|
|
AcpiInformation->RootSystemDescTable
|
|
);
|
|
usingXSDT = TRUE;
|
|
|
|
} else {
|
|
|
|
numTables = NumTableEntriesFromRSDTPointer(
|
|
AcpiInformation->RootSystemDescTable
|
|
);
|
|
}
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_LOADING,
|
|
"ACPILoadProcessRSDT: RSDT contains %u tables\n",
|
|
numTables
|
|
) );
|
|
if (numTables == 0) {
|
|
|
|
return STATUS_ACPI_INVALID_TABLE;
|
|
|
|
}
|
|
|
|
//
|
|
// Allocate the RSDTINFORMATION to hold an entry for each element
|
|
// in the table.
|
|
//
|
|
// NOTENOTE: We are actually allocating space for numTables + 2
|
|
// in the RSDT information. The reason for this is that the DSDT
|
|
// is actually stored in the FADT, and so it does not have an entry
|
|
// in the RSDT. We always, always store the DSDT as the last entry
|
|
// in the RsdtInformation structure. In the 2nd to last entry we store
|
|
// the dummy header that we use for the ACPI simulator
|
|
//
|
|
length = sizeof(RSDTINFORMATION) + ( (numTables + 1) * sizeof(RSDTELEMENT) );
|
|
RsdtInformation = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
length,
|
|
ACPI_SHARED_TABLE_POOLTAG
|
|
);
|
|
if (RsdtInformation == NULL) {
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
RtlZeroMemory( RsdtInformation, length );
|
|
RsdtInformation->NumElements = (numTables + 2);
|
|
|
|
//
|
|
// Examine each table entry in the RSDT
|
|
//
|
|
for (index = 0;index < numTables; index++) {
|
|
|
|
//
|
|
// RSDT contains an array of physical pointers.
|
|
//
|
|
|
|
//
|
|
// Get the linear address of the table
|
|
//
|
|
PhysAddress.QuadPart = usingXSDT ?
|
|
(ULONGLONG) ((PXSDT)AcpiInformation->RootSystemDescTable)->Tables[index].QuadPart :
|
|
(ULONGLONG) AcpiInformation->RootSystemDescTable->Tables[index];
|
|
|
|
|
|
linAddress = MmMapIoSpace(
|
|
PhysAddress,
|
|
sizeof (DESCRIPTION_HEADER),
|
|
MmNonCached
|
|
);
|
|
|
|
if (linAddress == NULL) {
|
|
ASSERT (linAddress != NULL);
|
|
return STATUS_ACPI_INVALID_TABLE;
|
|
}
|
|
|
|
//
|
|
// Is this a known, but unused table?
|
|
//
|
|
header = (PDESCRIPTION_HEADER) linAddress;
|
|
|
|
|
|
if (header->Signature == SBST_SIGNATURE) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_LOADING,
|
|
"ACPILoadProcessRSDT: SBST Found at 0x%08lx\n",
|
|
linAddress
|
|
) );
|
|
|
|
MmUnmapIoSpace(linAddress, sizeof(DESCRIPTION_HEADER));
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Is this an unrecognized table?
|
|
//
|
|
if (header->Signature != FADT_SIGNATURE &&
|
|
header->Signature != SSDT_SIGNATURE &&
|
|
header->Signature != PSDT_SIGNATURE &&
|
|
header->Signature != APIC_SIGNATURE) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_WARNING,
|
|
"ACPILoadProcessRSDT: Unrecognized table signature 0x%08lx\n",
|
|
header->Signature
|
|
) );
|
|
|
|
MmUnmapIoSpace(linAddress, sizeof(DESCRIPTION_HEADER));
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// At this point, we know that we need to bring the entire table
|
|
// in. To do that, we need to remember the length
|
|
//
|
|
length = header->Length;
|
|
|
|
//
|
|
// map the entire table using the now known length
|
|
//
|
|
MmUnmapIoSpace(linAddress, sizeof(DESCRIPTION_HEADER));
|
|
|
|
linAddress = MmMapIoSpace(
|
|
PhysAddress,
|
|
length,
|
|
MmNonCached
|
|
);
|
|
|
|
|
|
if (linAddress == NULL) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPILoadProcesRSDT: Could not load table at 0x%08lx\n",
|
|
AcpiInformation->RootSystemDescTable->Tables[index]
|
|
) );
|
|
return STATUS_ACPI_INVALID_TABLE;
|
|
|
|
}
|
|
|
|
//
|
|
// Should we override the table?
|
|
//
|
|
foundOverride = ACPIRegReadAMLRegistryEntry( &linAddress, TRUE);
|
|
if (foundOverride) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_WARNING,
|
|
"ACPILoadProcessRSDT: Table Overloaded from "
|
|
"registry (0x%08lx)\n",
|
|
linAddress
|
|
) );
|
|
RsdtInformation->Tables[index].Flags |= RSDTELEMENT_OVERRIDEN;
|
|
|
|
}
|
|
|
|
//
|
|
// Remember this address and that we need to unmap it
|
|
//
|
|
RsdtInformation->Tables[index].Flags |= RSDTELEMENT_MAPPED;
|
|
RsdtInformation->Tables[index].Address = linAddress;
|
|
|
|
//
|
|
// Remember the new header
|
|
//
|
|
header = (PDESCRIPTION_HEADER) linAddress;
|
|
|
|
//
|
|
// At this point, we only need to do any kind of special processing
|
|
// if the table is the FADT or if it is the MAPIC
|
|
//
|
|
if (header->Signature == FADT_SIGNATURE) {
|
|
|
|
//
|
|
// fill in the appropriate field in acpiinformation
|
|
//
|
|
AcpiInformation->FixedACPIDescTable = (PFADT) linAddress;
|
|
|
|
//
|
|
// Process the table. This does not cause the interpreter
|
|
// to load anything
|
|
//
|
|
foundFADT = TRUE;
|
|
ACPILoadProcessFADT( AcpiInformation->FixedACPIDescTable );
|
|
|
|
} else if (header->Signature == APIC_SIGNATURE) {
|
|
|
|
//
|
|
// fill in the appropriate field in acpiinformation
|
|
//
|
|
AcpiInformation->MultipleApicTable = (PMAPIC)linAddress;
|
|
|
|
} else {
|
|
|
|
//
|
|
// We can only reach this case if the table is one of the
|
|
// xSDT variety. We need to remember that we will eventually
|
|
// need to load it into the interpreter. If we start supporting
|
|
// any more tables, we need to make sure that they don't fall
|
|
// down here unless they really, really are supported
|
|
//
|
|
RsdtInformation->Tables[index].Flags |= RSDTELEMENT_LOADABLE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// At this point, we need to make sure that the ACPI simulator table
|
|
// gets loaded
|
|
//
|
|
header = ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sizeof(DESCRIPTION_HEADER),
|
|
ACPI_SHARED_TABLE_POOLTAG
|
|
);
|
|
if (header) {
|
|
|
|
//
|
|
// Initialize the header so that it can be passed into the overload
|
|
// engine
|
|
//
|
|
RtlZeroMemory( header, sizeof(DESCRIPTION_HEADER) );
|
|
header->Signature = SSDT_SIGNATURE;
|
|
header->Length = sizeof(DESCRIPTION_HEADER),
|
|
header->Revision = 1;
|
|
header->Checksum = 0;
|
|
header->OEMRevision = 1;
|
|
header->CreatorRev = 1;
|
|
RtlCopyMemory( header->OEMID, "MSFT", 4 );
|
|
RtlCopyMemory( header->OEMTableID, "simulatr", 8);
|
|
RtlCopyMemory( header->CreatorID, "MSFT", 4);
|
|
|
|
//
|
|
// Should we override the table?
|
|
//
|
|
if (AcpiLoadSimulatorTable) {
|
|
|
|
foundOverride = ACPIRegReadAMLRegistryEntry( &header, FALSE);
|
|
|
|
}
|
|
if (foundOverride) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_LOADING,
|
|
"ACPILoadProcessRSDT: Simulator Table Overloaded from "
|
|
"registry (0x%08lx)\n",
|
|
linAddress
|
|
) );
|
|
|
|
//
|
|
// Remember this address and that we need to unmap it
|
|
//
|
|
RsdtInformation->Tables[numTables].Flags |= RSDTELEMENT_MAPPED;
|
|
RsdtInformation->Tables[numTables].Flags |= RSDTELEMENT_OVERRIDEN;
|
|
RsdtInformation->Tables[numTables].Flags |= RSDTELEMENT_LOADABLE;
|
|
RsdtInformation->Tables[numTables].Address = header;
|
|
|
|
} else {
|
|
|
|
//
|
|
// If we have found an override, we don't need the dummy table
|
|
//
|
|
ExFreePool( header );
|
|
|
|
}
|
|
|
|
}
|
|
//
|
|
// Save whatever tables we found in the registry
|
|
//
|
|
ACPIRegDumpAcpiTables ();
|
|
|
|
//
|
|
// Did we find an FADT?
|
|
//
|
|
if (!foundFADT) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPILoadProcessRSDT: Did not find an FADT\n"
|
|
) );
|
|
return STATUS_ACPI_INVALID_TABLE;
|
|
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
BOOLEAN
|
|
ACPILoadTableCheckSum(
|
|
PVOID StartAddress,
|
|
ULONG Length
|
|
)
|
|
{
|
|
PUCHAR currentAddress;
|
|
UCHAR sum = 0;
|
|
ULONG i;
|
|
|
|
PAGED_CODE();
|
|
ASSERT (Length > 0);
|
|
|
|
currentAddress = (PUCHAR)StartAddress;
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_LOADING,
|
|
"ACPILoadTableCheckSum: Checking table 0x%p to 0x%p\n",
|
|
StartAddress, (ULONG_PTR)StartAddress + Length - 1
|
|
) );
|
|
|
|
for (i = 0; i < Length; i++, currentAddress++ ) {
|
|
|
|
sum += *currentAddress;
|
|
|
|
}
|
|
|
|
ACPISimpleSoftwareAssert ( (sum == 0), ACPI_ERROR_INT_BAD_TABLE_CHECKSUM );
|
|
|
|
if (sum) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPILoadTableCheckSum: Checksum Failed!, table %p to %p\n",
|
|
StartAddress, (ULONG_PTR) StartAddress + Length - 1
|
|
) );
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
}
|