windows-nt/Source/XPSP1/NT/base/busdrv/acpi/driver/shared/acpiinit.c

681 lines
15 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
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 0x%08lx\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);
}