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