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.
680 lines
16 KiB
680 lines
16 KiB
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
acpiinit.c
|
|
|
|
Abstract:
|
|
|
|
ACPI OS Independent initialization routines
|
|
|
|
Author:
|
|
|
|
Jason Clark (JasonCl)
|
|
Stephane Plante (SPlante)
|
|
|
|
Environment:
|
|
|
|
NT Kernel Model Driver only
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE,ACPIInitialize)
|
|
#pragma alloc_text(PAGE,ACPIInitializeAMLI)
|
|
#pragma alloc_text(PAGE,ACPIInitializeDDB)
|
|
#pragma alloc_text(PAGE,ACPIInitializeDDBs)
|
|
#pragma alloc_text(PAGE,GetPBlkAddress)
|
|
#endif
|
|
|
|
#ifdef DBG
|
|
#define VERIFY_IO_WRITES
|
|
#endif
|
|
|
|
//
|
|
// Pointer to global ACPIInformation structure.
|
|
//
|
|
PACPIInformation AcpiInformation = NULL;
|
|
|
|
//
|
|
// Global structure for Pnp/QUERY_INTERFACE
|
|
//
|
|
ACPI_INTERFACE_STANDARD ACPIInterfaceTable;
|
|
PNSOBJ ProcessorList[ACPI_SUPPORTED_PROCESSORS];
|
|
PRSDTINFORMATION RsdtInformation;
|
|
|
|
//
|
|
// Remember how many contexts we have reserved for the interpreter
|
|
//
|
|
ULONG AMLIMaxCTObjs;
|
|
|
|
|
|
BOOLEAN
|
|
ACPIInitialize(
|
|
PVOID Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called by the OS to detect ACPI, store interesting
|
|
information in the global data structure, enables ACPI on the machine,
|
|
and finally load the DSDT
|
|
|
|
Arguments:
|
|
|
|
Context - The context to back to the OS upon a callback. Typically a
|
|
deviceObject
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN
|
|
- TRUE if ACPI was found
|
|
- FALSE, otherwise
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN bool;
|
|
NTSTATUS status;
|
|
PRSDT rootSystemDescTable;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Initialize the interpreter
|
|
//
|
|
status = ACPIInitializeAMLI();
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPIInitialize: AMLI failed initialization 0x%08lx\n",
|
|
status
|
|
) );
|
|
ASSERTMSG(
|
|
"ACPIInitialize: AMLI failed initialization\n",
|
|
NT_SUCCESS(status)
|
|
);
|
|
KeBugCheckEx(
|
|
ACPI_BIOS_ERROR,
|
|
ACPI_SYSTEM_CANNOT_START_ACPI,
|
|
0,
|
|
0,
|
|
0
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// Get the linear address of the RSDT of NULL if ACPI is not present on
|
|
// the System
|
|
//
|
|
rootSystemDescTable = ACPILoadFindRSDT();
|
|
if ( rootSystemDescTable == NULL ) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPIInitialize: ACPI RSDT Not Found\n"
|
|
) );
|
|
ASSERTMSG(
|
|
"ACPIInitialize: ACPI RSDT Not Found\n",
|
|
rootSystemDescTable
|
|
);
|
|
KeBugCheckEx(
|
|
ACPI_BIOS_ERROR,
|
|
ACPI_SYSTEM_CANNOT_START_ACPI,
|
|
1,
|
|
0,
|
|
0
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// ACPI is alive and well on this machine.
|
|
//
|
|
ACPIPrint( (
|
|
ACPI_PRINT_LOADING,
|
|
"ACPIInitalize: ACPI RSDT found at %p \n",
|
|
rootSystemDescTable
|
|
) );
|
|
|
|
//
|
|
// Initialize table used for MJ_PNP/MN_QUERY_INTERFACE requests
|
|
//
|
|
ACPIInterfaceTable.Size = sizeof (ACPIInterfaceTable);
|
|
ACPIInterfaceTable.GpeConnectVector = ACPIVectorConnect;
|
|
ACPIInterfaceTable.GpeDisconnectVector = ACPIVectorDisconnect;
|
|
ACPIInterfaceTable.GpeEnableEvent = ACPIVectorEnable;
|
|
ACPIInterfaceTable.GpeDisableEvent = ACPIVectorDisable;
|
|
ACPIInterfaceTable.GpeClearStatus = ACPIVectorClear;
|
|
ACPIInterfaceTable.RegisterForDeviceNotifications = ACPIRegisterForDeviceNotifications;
|
|
ACPIInterfaceTable.UnregisterForDeviceNotifications = ACPIUnregisterForDeviceNotifications;
|
|
ACPIInterfaceTable.InterfaceReference = AcpiNullReference;
|
|
ACPIInterfaceTable.InterfaceDereference = AcpiNullReference;
|
|
ACPIInterfaceTable.Context = Context;
|
|
ACPIInterfaceTable.Version = 1;
|
|
|
|
//
|
|
// Initialize global data structures
|
|
//
|
|
KeInitializeSpinLock (&GpeTableLock);
|
|
KeInitializeSpinLock (&NotifyHandlerLock);
|
|
ProcessorList[0] = 0;
|
|
RtlZeroMemory( ProcessorList, ACPI_SUPPORTED_PROCESSORS * sizeof(PNSOBJ) );
|
|
|
|
//
|
|
// Allocate some memory to hold the ACPI Information structure.
|
|
//
|
|
AcpiInformation = (PACPIInformation) ExAllocatePoolWithTag(
|
|
NonPagedPool,
|
|
sizeof(ACPIInformation),
|
|
ACPI_SHARED_INFORMATION_POOLTAG
|
|
);
|
|
if ( AcpiInformation == NULL ) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPIInitialize: Could not allocate AcpiInformation (x%x bytes)\n",
|
|
sizeof(ACPIInformation)
|
|
) );
|
|
ASSERTMSG(
|
|
"ACPIInitialize: Could not allocate AcpiInformation\n",
|
|
AcpiInformation
|
|
);
|
|
KeBugCheckEx(
|
|
ACPI_BIOS_ERROR,
|
|
ACPI_SYSTEM_CANNOT_START_ACPI,
|
|
2,
|
|
0,
|
|
0
|
|
);
|
|
|
|
}
|
|
RtlZeroMemory( AcpiInformation, sizeof(ACPIInformation) );
|
|
AcpiInformation->ACPIOnly = TRUE;
|
|
AcpiInformation->RootSystemDescTable = rootSystemDescTable;
|
|
|
|
//
|
|
// Initialize queue, lock, and owner info for the Global Lock.
|
|
// This must be done before we ever call the interpreter!
|
|
//
|
|
KeInitializeSpinLock( &AcpiInformation->GlobalLockQueueLock );
|
|
InitializeListHead( &AcpiInformation->GlobalLockQueue );
|
|
AcpiInformation->GlobalLockOwnerContext = NULL;
|
|
AcpiInformation->GlobalLockOwnerDepth = 0;
|
|
|
|
//
|
|
// Initialize most of the remaining fields in the AcpiInformation structure.
|
|
// This function will return FALSE in case of a problem finding the required
|
|
// tables
|
|
//
|
|
status = ACPILoadProcessRSDT();
|
|
if ( !NT_SUCCESS(status) ) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPIInitialize: ACPILoadProcessRSDT = 0x%08lx\n",
|
|
status
|
|
) );
|
|
ASSERTMSG(
|
|
"ACPIInitialize: ACPILoadProcessRSDT Failed\n",
|
|
NT_SUCCESS(status)
|
|
);
|
|
KeBugCheckEx(
|
|
ACPI_BIOS_ERROR,
|
|
ACPI_SYSTEM_CANNOT_START_ACPI,
|
|
3,
|
|
0,
|
|
0
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// Now switch the machine into ACPI mode and initialize
|
|
// the ACPI registers.
|
|
//
|
|
ACPIEnableInitializeACPI( FALSE );
|
|
|
|
//
|
|
// At this point, we can load all of the DDBs. We need to load all of
|
|
// these tables *before* we try to enable any GPEs or Interrupt Vectors
|
|
//
|
|
status = ACPIInitializeDDBs();
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPIInitialize: ACPIInitializeLoadDDBs = 0x%08lx\n",
|
|
status
|
|
) );
|
|
ASSERTMSG(
|
|
"ACPIInitialize: ACPIInitializeLoadDDBs Failed\n",
|
|
NT_SUCCESS(status)
|
|
);
|
|
KeBugCheckEx(
|
|
ACPI_BIOS_ERROR,
|
|
ACPI_SYSTEM_CANNOT_START_ACPI,
|
|
4,
|
|
0,
|
|
0
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// Hook the SCI Vector
|
|
//
|
|
bool = OSInterruptVector(
|
|
Context
|
|
);
|
|
if ( !bool ) {
|
|
|
|
//
|
|
// Ooops... We were unable to hook the SCI vector. Clean Up and
|
|
// fail to load.
|
|
//
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPIInitialize: OSInterruptVector Failed!!\n"
|
|
) );
|
|
ASSERTMSG(
|
|
"ACPIInitialize: OSInterruptVector Failed!!\n",
|
|
bool
|
|
);
|
|
KeBugCheckEx(
|
|
ACPI_BIOS_ERROR,
|
|
ACPI_SYSTEM_CANNOT_START_ACPI,
|
|
5,
|
|
0,
|
|
0
|
|
);
|
|
|
|
}
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
NTSTATUS
|
|
ACPIInitializeAMLI(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called by ACPIInitialize to init the interpreter. We go and read
|
|
some values from the registry to decide what to initialize the
|
|
interpreter with
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
ULONG amliInitFlags;
|
|
ULONG contextBlockSize;
|
|
ULONG globalHeapBlockSize;
|
|
ULONG timeSliceLength;
|
|
ULONG timeSliceInterval;
|
|
ULONG argSize;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Initialize AMLI
|
|
//
|
|
argSize = sizeof(amliInitFlags);
|
|
status = OSReadRegValue(
|
|
"AMLIInitFlags",
|
|
(HANDLE) NULL,
|
|
&amliInitFlags,
|
|
&argSize
|
|
);
|
|
if (!NT_SUCCESS(status) ) {
|
|
|
|
amliInitFlags = 0;
|
|
|
|
}
|
|
|
|
argSize = sizeof(contextBlockSize);
|
|
status = OSReadRegValue(
|
|
"AMLICtxtBlkSize",
|
|
(HANDLE) NULL,
|
|
&contextBlockSize,
|
|
&argSize
|
|
);
|
|
if (!NT_SUCCESS(status) ) {
|
|
|
|
contextBlockSize = 0;
|
|
|
|
}
|
|
|
|
argSize = sizeof(globalHeapBlockSize);
|
|
status = OSReadRegValue(
|
|
"AMLIGlobalHeapBlkSize",
|
|
(HANDLE) NULL,
|
|
&globalHeapBlockSize,
|
|
&argSize
|
|
);
|
|
if (!NT_SUCCESS(status) ) {
|
|
|
|
globalHeapBlockSize = 0;
|
|
|
|
}
|
|
|
|
argSize = sizeof(timeSliceLength);
|
|
status = OSReadRegValue(
|
|
"AMLITimeSliceLength",
|
|
(HANDLE) NULL,
|
|
&timeSliceLength,
|
|
&argSize
|
|
);
|
|
if (!NT_SUCCESS(status) ) {
|
|
|
|
timeSliceLength = 0;
|
|
|
|
}
|
|
|
|
argSize = sizeof(timeSliceInterval);
|
|
status = OSReadRegValue(
|
|
"AMLITimeSliceInterval",
|
|
(HANDLE) NULL,
|
|
&timeSliceInterval,
|
|
&argSize
|
|
);
|
|
if (!NT_SUCCESS(status) ) {
|
|
|
|
timeSliceInterval = 0;
|
|
|
|
}
|
|
|
|
argSize = sizeof(AMLIMaxCTObjs);
|
|
status = OSReadRegValue(
|
|
"AMLIMaxCTObjs",
|
|
(HANDLE) NULL,
|
|
&AMLIMaxCTObjs,
|
|
&argSize
|
|
);
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
AMLIMaxCTObjs = 0;
|
|
|
|
}
|
|
|
|
//
|
|
// Allow the OSes to do some work once the interperter has been loaded
|
|
//
|
|
OSInitializeCallbacks();
|
|
|
|
//
|
|
// Initialize the interpreter
|
|
//
|
|
return AMLIInitialize(
|
|
contextBlockSize,
|
|
globalHeapBlockSize,
|
|
amliInitFlags,
|
|
timeSliceLength,
|
|
timeSliceInterval,
|
|
AMLIMaxCTObjs
|
|
);
|
|
}
|
|
|
|
NTSTATUS
|
|
ACPIInitializeDDB(
|
|
IN ULONG Index
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called to load the specificied Differentiated Data Block
|
|
|
|
Arguments:
|
|
|
|
Index - Index of information in the RsdtInformation
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN success;
|
|
HANDLE diffDataBlock = NULL;
|
|
NTSTATUS status;
|
|
PDSDT table;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Convert the index into a table entry
|
|
//
|
|
table = (PDSDT) (RsdtInformation->Tables[Index].Address);
|
|
|
|
//
|
|
// Make sure that the checksum of the table is correct
|
|
//
|
|
success = ACPILoadTableCheckSum( table, table->Header.Length );
|
|
if (success == FALSE) {
|
|
|
|
KeBugCheckEx(
|
|
ACPI_BIOS_ERROR,
|
|
ACPI_SYSTEM_CANNOT_START_ACPI,
|
|
7,
|
|
(ULONG_PTR) table,
|
|
table->Header.CreatorRev
|
|
);
|
|
|
|
|
|
}
|
|
|
|
//
|
|
// Now call the Interpreter to read the Differentiated System
|
|
// Description Block and build the ACPI Name Space.
|
|
//
|
|
status = AMLILoadDDB( table, &diffDataBlock );
|
|
if (NT_SUCCESS(status) ) {
|
|
|
|
//
|
|
// Remember that we have loaded this table and that we have a
|
|
// handle to it
|
|
//
|
|
RsdtInformation->Tables[Index].Flags |= RSDTELEMENT_LOADED;
|
|
RsdtInformation->Tables[Index].Handle = diffDataBlock;
|
|
|
|
} else {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPIInitializeDDB: AMLILoadDDB failed 0x%8x\n",
|
|
status
|
|
) );
|
|
ASSERTMSG(
|
|
"ACPIInitializeDDB: AMLILoadDDB failed to load DDB\n",
|
|
0
|
|
);
|
|
|
|
KeBugCheckEx(
|
|
ACPI_BIOS_ERROR,
|
|
ACPI_SYSTEM_CANNOT_START_ACPI,
|
|
8,
|
|
(ULONG_PTR) table,
|
|
table->Header.CreatorRev
|
|
);
|
|
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
ACPIInitializeDDBs(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function looks that the RsdtInformation and attemps to load
|
|
all of the possible Dynamic Data Blocks
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
ULONG index;
|
|
ULONG numElements;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Get the number of elements to process
|
|
//
|
|
numElements = RsdtInformation->NumElements;
|
|
if (numElements == 0) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPInitializeDDBs: No tables found in RSDT\n"
|
|
) );
|
|
ASSERTMSG(
|
|
"ACPIInitializeDDBs: No tables found in RSDT\n",
|
|
numElements != 0
|
|
);
|
|
return STATUS_ACPI_INVALID_TABLE;
|
|
|
|
}
|
|
|
|
//
|
|
// We would not be here unless we found a DSDT. So we assume that the
|
|
// *LAST* entry in the table points to the DSDT that we will load. Make
|
|
// sure that we can in fact load it, and then do so
|
|
//
|
|
index = numElements - 1;
|
|
if ( !(RsdtInformation->Tables[index].Flags & RSDTELEMENT_MAPPED) ||
|
|
!(RsdtInformation->Tables[index].Flags & RSDTELEMENT_LOADABLE) ) {
|
|
|
|
ACPIPrint( (
|
|
ACPI_PRINT_CRITICAL,
|
|
"ACPInitializeDDB: DSDT not mapped or loadable\n"
|
|
) );
|
|
ASSERTMSG(
|
|
"ACPIInitializeDDB: DSDT not mapped\n",
|
|
(RsdtInformation->Tables[index].Flags & RSDTELEMENT_MAPPED)
|
|
);
|
|
ASSERTMSG(
|
|
"ACPIInitializeDDB: DSDT not loadable\n",
|
|
(RsdtInformation->Tables[index].Flags & RSDTELEMENT_LOADABLE)
|
|
);
|
|
return STATUS_ACPI_INVALID_TABLE;
|
|
|
|
}
|
|
status = ACPIInitializeDDB( index );
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
//
|
|
// We have one fewer element to look at, so lets ignore the DSDT entry
|
|
//
|
|
numElements--;
|
|
|
|
//
|
|
// Loop for all elements in the table
|
|
//
|
|
for (index = 0; index < numElements; index++) {
|
|
|
|
//
|
|
// Is the entry mapped and loadable?
|
|
//
|
|
if ( (RsdtInformation->Tables[index].Flags & RSDTELEMENT_MAPPED) &&
|
|
(RsdtInformation->Tables[index].Flags & RSDTELEMENT_LOADABLE) ) {
|
|
|
|
//
|
|
// Load the table
|
|
//
|
|
status = ACPIInitializeDDB( index );
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// If we got here, then everything is okay
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
ULONG
|
|
GetPBlkAddress(
|
|
IN UCHAR Processor
|
|
)
|
|
{
|
|
ULONG pblk;
|
|
NTSTATUS status;
|
|
OBJDATA data;
|
|
PNSOBJ pnsobj = NULL;
|
|
PPROCESSOROBJ pobj = NULL;
|
|
|
|
if (Processor >= ACPI_SUPPORTED_PROCESSORS) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (!ProcessorList[Processor]) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
status = AMLIEvalNameSpaceObject(
|
|
ProcessorList[Processor],
|
|
&data,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
if ( !NT_SUCCESS(status) ) {
|
|
|
|
ACPIBreakPoint ();
|
|
return (0);
|
|
|
|
}
|
|
|
|
ASSERT (data.dwDataType == OBJTYPE_PROCESSOR);
|
|
ASSERT (data.pbDataBuff != NULL);
|
|
|
|
pblk = ((PROCESSOROBJ *)data.pbDataBuff)->dwPBlk;
|
|
AMLIFreeDataBuffs(&data, 1);
|
|
|
|
return (pblk);
|
|
}
|
|
|