/*++ 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); }