/*++ Copyright (c) 1997-2000 Microsoft Corporation Module Name: xxacpi.c Abstract: Implements various ACPI utility functions. Author: Jake Oshins (jakeo) 12-Feb-1997 Environment: Kernel mode only. Revision History: --*/ #include "halp.h" #include "acpitabl.h" #include "xxacpi.h" #include "pci.h" #include "string.h" #include "stdlib.h" #include "stdio.h" #include "mmtimer.h" #include "chiphacks.h" //#define DUMP_FADT VOID HalAcpiTimerCarry( VOID ); VOID HalAcpiBrokenPiix4TimerCarry( VOID ); VOID HalaAcpiTimerInit( ULONG TimerPort, BOOLEAN TimerValExt ); ULONG HaliAcpiQueryFlags( VOID ); VOID HaliAcpiTimerInit( IN ULONG TimerPort OPTIONAL, IN BOOLEAN TimerValExt ); VOID HaliAcpiMachineStateInit( IN PPROCESSOR_INIT ProcInit, IN PHAL_SLEEP_VAL SleepValues, OUT PULONG PicVal ); BOOLEAN FASTCALL HalAcpiC1Idle( OUT PPROCESSOR_IDLE_TIMES IdleTimes ); BOOLEAN FASTCALL HalAcpiC2Idle( OUT PPROCESSOR_IDLE_TIMES IdleTimes ); BOOLEAN FASTCALL HalAcpiC3ArbdisIdle( OUT PPROCESSOR_IDLE_TIMES IdleTimes ); BOOLEAN FASTCALL HalAcpiC3WbinvdIdle( OUT PPROCESSOR_IDLE_TIMES IdleTimes ); VOID FASTCALL HalProcessorThrottle( IN UCHAR Throttle ); NTSTATUS HaliSetWakeAlarm ( IN ULONGLONG WakeSystemTime, IN PTIME_FIELDS WakeTimeFields OPTIONAL ); VOID HaliSetWakeEnable( IN BOOLEAN Enable ); ULONG HaliPciInterfaceReadConfig( IN PVOID Context, IN UCHAR BusOffset, IN ULONG Slot, IN PVOID Buffer, IN ULONG Offset, IN ULONG Length ); ULONG HaliPciInterfaceWriteConfig( IN PVOID Context, IN UCHAR BusOffset, IN ULONG Slot, IN PVOID Buffer, IN ULONG Offset, IN ULONG Length ); VOID HaliSetMaxLegacyPciBusNumber( IN ULONG BusNumber ); VOID HalpInitBootTable ( IN PLOADER_PARAMETER_BLOCK LoaderBlock ); NTSTATUS HalReadBootRegister( PUCHAR BootRegisterValue ); NTSTATUS HalWriteBootRegister( UCHAR BootRegisterValue ); VOID HalpEndOfBoot( VOID ); VOID HalpPutAcpiHacksInRegistry( VOID ); VOID HalpDynamicSystemResourceConfiguration( IN PLOADER_PARAMETER_BLOCK ); #if !defined(NT_UP) VOID HalpNumaInitializeStaticConfiguration( IN PLOADER_PARAMETER_BLOCK ); #endif // // Externs // extern ULONG HalpAcpiFlags; extern PHYSICAL_ADDRESS HalpAcpiRsdt; extern SLEEP_STATE_CONTEXT HalpShutdownContext; extern ULONG HalpPicVectorRedirect[]; extern ULONG HalpTimerWatchdogEnabled; extern ULONG HalpOutstandingScatterGatherCount; extern BOOLEAN HalpDisableHibernate; // // Globals // ULONG HalpInvalidAcpiTable; PRSDT HalpAcpiRsdtVA; PXSDT HalpAcpiXsdtVA; // // This is the dispatch table used by the ACPI driver // HAL_ACPI_DISPATCH_TABLE HalAcpiDispatchTable = { HAL_ACPI_DISPATCH_SIGNATURE, // Signature HAL_ACPI_DISPATCH_VERSION, // Version &HaliAcpiTimerInit, // HalpAcpiTimerInit NULL, // HalpAcpiTimerInterrupt &HaliAcpiMachineStateInit, // HalpAcpiMachineStateInit &HaliAcpiQueryFlags, // HalpAcpiQueryFlags &HalpAcpiPicStateIntact, // HalxPicStateIntact &HalpRestoreInterruptControllerState, // HalxRestorePicState &HaliPciInterfaceReadConfig, // HalpPciInterfaceReadConfig &HaliPciInterfaceWriteConfig, // HalpPciInterfaceWriteConfig &HaliSetVectorState, // HalpSetVectorState (pHalGetIOApicVersion)&HalpGetApicVersion, // HalpGetIOApicVersion &HaliSetMaxLegacyPciBusNumber, // HalpSetMaxLegacyPciBusNumber &HaliIsVectorValid // HalpIsVectorValid }; PPM_DISPATCH_TABLE PmAcpiDispatchTable = NULL; NTSTATUS HalpQueryAcpiResourceRequirements( IN PIO_RESOURCE_REQUIREMENTS_LIST *Requirements ); NTSTATUS HalpBuildAcpiResourceList( OUT PIO_RESOURCE_REQUIREMENTS_LIST List ); NTSTATUS HalpAcpiDetectResourceListSize( OUT PULONG ResourceListSize ); VOID HalpPiix4Detect( BOOLEAN DuringBoot ); ULONG HalpGetPCIData ( IN PBUS_HANDLER BusHandler, IN PBUS_HANDLER RootHandler, IN PCI_SLOT_NUMBER SlotNumber, IN PVOID Buffer, IN ULONG Offset, IN ULONG Length ); ULONG HalpGetCmosData( IN ULONG SourceLocation, IN ULONG SourceAddress, IN PUCHAR ReturnBuffer, IN ULONG ByteCount ); VOID HalpSetCmosData( IN ULONG SourceLocation, IN ULONG SourceAddress, IN PUCHAR ReturnBuffer, IN ULONG ByteCount ); #define LOW_MEMORY 0x000100000 #define MAX(a, b) \ ((a) > (b) ? (a) : (b)) #define MIN(a, b) \ ((a) < (b) ? (a) : (b)) // // The following is a Stub version of HalpGetApicVersion // for non-APIC halacpi's (which don't include // pmapic.c). This stub just always returns 0. // #ifndef APIC_HAL ULONG HalpGetApicVersion(ULONG ApicNo) { return 0; } #endif // // ADRIAO 09/16/98 - We are no longer having the HAL declare the IO ports // specified in the FADT. These will be declared in a future // defined PNP0Cxx node (for now, in PNP0C02). This is done // because we cannot know at the hal level what bus the ACPI // FADT resources refer to. We can only use the translated // resource info. // // Hence... // #define DECLARE_FADT_RESOURCES_AT_ROOT 0 #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT, HalpGetAcpiTablePhase0) #pragma alloc_text(INIT, HalpSetupAcpiPhase0) #pragma alloc_text(INIT, HalpInitBootTable) #pragma alloc_text(PAGE, HaliInitPowerManagement) #pragma alloc_text(PAGE, HalpQueryAcpiResourceRequirements) #pragma alloc_text(PAGE, HalpBuildAcpiResourceList) #pragma alloc_text(PAGE, HalpAcpiDetectResourceListSize) #pragma alloc_text(PAGE, HaliAcpiTimerInit) #pragma alloc_text(PAGE, HaliAcpiMachineStateInit) #pragma alloc_text(PAGE, HaliAcpiQueryFlags) #pragma alloc_text(PAGE, HaliSetWakeEnable) #pragma alloc_text(PAGE, HalpEndOfBoot) #pragma alloc_text(PAGE, HalpPutAcpiHacksInRegistry) #pragma alloc_text(PAGELK, HalpPiix4Detect) #pragma alloc_text(PAGELK, HalReadBootRegister) #pragma alloc_text(PAGELK, HalWriteBootRegister) #pragma alloc_text(PAGELK, HalpResetSBF) #endif PVOID HalpGetAcpiTablePhase0( IN PLOADER_PARAMETER_BLOCK LoaderBlock, IN ULONG Signature ) /*++ Routine Description: This function returns a pointer to the ACPI table that is identified by Signature. Arguments: Signature - A four byte value that identifies the ACPI table Return Value: Pointer to a copy of the table --*/ { PRSDT rsdt; PXSDT xsdt = NULL; ULONG entry, rsdtEntries, rsdtLength; PVOID table; PHYSICAL_ADDRESS physicalAddr; PDESCRIPTION_HEADER header; NTSTATUS status; ULONG lengthInPages; ULONG offset; physicalAddr.QuadPart = 0; header = NULL; if ((HalpAcpiRsdtVA == NULL) && (HalpAcpiXsdtVA == NULL)) { // // Find and map the RSDT once. This mapping is reused on // subsequent calls to this routine. // status = HalpAcpiFindRsdtPhase0(LoaderBlock); if (!NT_SUCCESS(status)) { DbgPrint("*** make sure you are using ntdetect.com v5.0 ***\n"); KeBugCheckEx(MISMATCHED_HAL, 4, 0xac31, 0, 0); } rsdt = HalpMapPhysicalMemory( HalpAcpiRsdt, 2); if (!rsdt) { return NULL; } // // Do a sanity check on the RSDT. // if ((rsdt->Header.Signature != RSDT_SIGNATURE) && (rsdt->Header.Signature != XSDT_SIGNATURE)) { HalDisplayString("Bad RSDT pointer\n"); KeBugCheckEx(MISMATCHED_HAL, 4, 0xac31, 0, 0); } // // Calculate the number of entries in the RSDT. // rsdtLength = rsdt->Header.Length; // // Remap the RSDT now that we know how long it is. // offset = HalpAcpiRsdt.LowPart & (PAGE_SIZE - 1); lengthInPages = (offset + rsdtLength + (PAGE_SIZE - 1)) >> PAGE_SHIFT; if (lengthInPages > 2) { HalpUnmapVirtualAddress(rsdt, 2); rsdt = HalpMapPhysicalMemory( HalpAcpiRsdt, lengthInPages); if (!rsdt) { DbgPrint("HAL: Couldn't remap RSDT\n"); return NULL; } } if (rsdt->Header.Signature == XSDT_SIGNATURE) { xsdt = (PXSDT)rsdt; rsdt = NULL; } HalpAcpiRsdtVA = rsdt; HalpAcpiXsdtVA = xsdt; } rsdt = HalpAcpiRsdtVA; xsdt = HalpAcpiXsdtVA; // // Calculate the number of entries in the RSDT. // rsdtEntries = xsdt ? NumTableEntriesFromXSDTPointer(xsdt) : NumTableEntriesFromRSDTPointer(rsdt); // // Look down the pointer in each entry to see if it points to // the table we are looking for. // for (entry = 0; entry < rsdtEntries; entry++) { if (xsdt) { physicalAddr = xsdt->Tables[entry]; } else { physicalAddr.LowPart = rsdt->Tables[entry]; } if (header != NULL) { HalpUnmapVirtualAddress(header, 2); } header = HalpMapPhysicalMemory( physicalAddr, 2); if (!header) { return NULL; } if (header->Signature == Signature) { break; } } if (entry == rsdtEntries) { // // Signature not found, free the PTE for the last entry // examined and indicate failure to the caller. // HalpUnmapVirtualAddress(header, 2); return NULL; } // // Make sure we have mapped enough memory to cover the entire // table. // offset = (ULONG)header & (PAGE_SIZE - 1); lengthInPages = (header->Length + offset + (PAGE_SIZE - 1)) >> PAGE_SHIFT; if (lengthInPages > 2) { HalpUnmapVirtualAddress(header, 2); header = HalpMapPhysicalMemory( physicalAddr, lengthInPages); } // // Validate the table's checksum. // N.B. We expect the checksum to be wrong on some early versions // of the FADT. // if ((header != NULL) && ((header->Signature != FADT_SIGNATURE) || (header->Revision > 2))) { PUCHAR c = (PUCHAR)header + header->Length; UCHAR s = 0; if (header->Length) { do { s += *--c; } while (c != (PUCHAR)header); } if ((s != 0) || (header->Length == 0)) { // // This table is not valid. // HalpInvalidAcpiTable = header->Signature; #if 0 // // Don't return this table. // HalpUnmapVirtualAddress(header, lengthInPages); return NULL; #endif } } return header; } NTSTATUS HalpSetupAcpiPhase0( IN PLOADER_PARAMETER_BLOCK LoaderBlock ) /*++ Routine Description: Save some information from the ACPI tables before they get destroyed. Arguments: none Return Value: none --*/ { NTSTATUS status; ULONG entry, rsdtEntries, rsdtLength; PVOID table; PHYSICAL_ADDRESS physicalAddr; PDESCRIPTION_HEADER header; PEVENT_TIMER_DESCRIPTION_TABLE EventTimerDescription = NULL; if (HalpProcessedACPIPhase0) { return STATUS_SUCCESS; } // // Copy the Fixed Acpi Descriptor Table (FADT) to a permanent // home. // header = HalpGetAcpiTablePhase0(LoaderBlock, FADT_SIGNATURE); if (header == NULL) { DbgPrint("HAL: Didn't find the FACP\n"); return STATUS_NOT_FOUND; } RtlCopyMemory(&HalpFixedAcpiDescTable, header, MIN(header->Length, sizeof(HalpFixedAcpiDescTable))); HalpUnMapPhysicalRange(header, header->Length); #ifdef DUMP_FADT DbgPrint("HAL: ACPI Fixed ACPI Description Table\n"); DbgPrint("\tDSDT:\t\t\t0x%08x\n", HalpFixedAcpiDescTable.dsdt); DbgPrint("\tSCI_INT:\t\t%d\n", HalpFixedAcpiDescTable.sci_int_vector); DbgPrint("\tPM1a_EVT:\t\t0x%04x\n", HalpFixedAcpiDescTable.pm1a_evt_blk_io_port); DbgPrint("\tPM1b_EVT:\t\t0x%04x\n", HalpFixedAcpiDescTable.pm1b_evt_blk_io_port); DbgPrint("\tPM1a_CNT:\t\t0x%04x\n", HalpFixedAcpiDescTable.pm1a_ctrl_blk_io_port); DbgPrint("\tPM1b_CNT:\t\t0x%04x\n", HalpFixedAcpiDescTable.pm1a_ctrl_blk_io_port); DbgPrint("\tPM2_CNT:\t\t0x%04x\n", HalpFixedAcpiDescTable.pm2_ctrl_blk_io_port); DbgPrint("\tPM_TMR:\t\t\t0x%04x\n", HalpFixedAcpiDescTable.pm_tmr_blk_io_port); DbgPrint("\t\t flags: %08x\n", HalpFixedAcpiDescTable.flags); #endif HalpDebugPortTable = HalpGetAcpiTablePhase0(LoaderBlock, DBGP_SIGNATURE); #if !defined(NT_UP) // // See if Static Resource Affinity Table is present. // HalpNumaInitializeStaticConfiguration(LoaderBlock); #endif HalpDynamicSystemResourceConfiguration(LoaderBlock); EventTimerDescription = HalpGetAcpiTablePhase0(LoaderBlock, ETDT_SIGNATURE); // // Initialize timer HW needed for boot // #ifdef MMTIMER_DEV if (TRUE) { HalpmmTimerInit(0, #ifdef PICACPI 0xd5800000); #else 0xfe000800); #endif // PICACPI } #else if (EventTimerDescription) { HalpmmTimerInit(EventTimerDescription->EventTimerBlockID, EventTimerDescription->BaseAddress); } #endif // MMTIMER_DEV HaliAcpiTimerInit(0, FALSE); // // Claim a page of memory below 1MB to be used for transitioning // a sleeping processor back from real mode to protected mode // // check first to see if this has already been done by MP startup code if (!HalpLowStubPhysicalAddress) { HalpLowStubPhysicalAddress = (PVOID)HalpAllocPhysicalMemory (LoaderBlock, LOW_MEMORY, 1, FALSE); if (HalpLowStubPhysicalAddress) { HalpLowStub = HalpMapPhysicalMemory( HalpPtrToPhysicalAddress( HalpLowStubPhysicalAddress ), 1); } } // // Claim a PTE that will be used for cache flushing in states S2 and S3. // HalpVirtAddrForFlush = HalpMapPhysicalMemory( HalpPtrToPhysicalAddress((PVOID)LOW_MEMORY), 1); HalpPteForFlush = MiGetPteAddress(HalpVirtAddrForFlush); HalpProcessedACPIPhase0 = TRUE; HalpInitBootTable (LoaderBlock); return STATUS_SUCCESS; } VOID HaliAcpiTimerInit( IN ULONG TimerPort OPTIONAL, IN BOOLEAN TimerValExt ) /*++ Routine Description: This routine initializes the ACPI timer. Arguments: TimerPort - The address in I/O space of the ACPI timer. If this is 0, then the values from the cached FADT will be used. TimerValExt - signifies whether the timer is 24 or 32 bits. --*/ { ULONG port = TimerPort; BOOLEAN ext = TimerValExt; PAGED_CODE(); if (port == 0) { port = HalpFixedAcpiDescTable.pm_tmr_blk_io_port; if (HalpFixedAcpiDescTable.flags & TMR_VAL_EXT) { ext = TRUE; } else { ext = FALSE; } } HalaAcpiTimerInit(port, ext); } VOID HaliAcpiMachineStateInit( IN PPROCESSOR_INIT ProcInit, IN PHAL_SLEEP_VAL SleepValues, OUT PULONG PicVal ) /*++ Routine Description: This function is a callback used by the ACPI driver to notify the HAL with the processor blocks. Arguments: --*/ { POWER_STATE_HANDLER powerState; SLEEP_STATE_CONTEXT sleepContext; NTSTATUS status; ULONG i; USHORT us; ULONG cStates = 1; ULONG ntProc; ULONG procCount = 0; PAGED_CODE(); UNREFERENCED_PARAMETER(ProcInit); HalpWakeupState.GeneralWakeupEnable = TRUE; HalpWakeupState.RtcWakeupEnable = FALSE; #ifdef APIC_HAL *PicVal = 1; #else *PicVal = 0; #endif // // Register sleep handlers with Policy Manager // if (SleepValues[0].Supported) { powerState.Type = PowerStateSleeping1; powerState.RtcWake = TRUE; powerState.Handler = &HaliAcpiSleep; sleepContext.bits.Pm1aVal = SleepValues[0].Pm1aVal; sleepContext.bits.Pm1bVal = SleepValues[0].Pm1bVal; sleepContext.bits.Flags = SLEEP_STATE_SAVE_MOTHERBOARD; powerState.Context = (PVOID)sleepContext.AsULONG; status = ZwPowerInformation(SystemPowerStateHandler, &powerState, sizeof(POWER_STATE_HANDLER), NULL, 0); ASSERT(NT_SUCCESS(status)); } if (SleepValues[1].Supported && HalpWakeVector) { powerState.Type = PowerStateSleeping2; powerState.RtcWake = TRUE; powerState.Handler = &HaliAcpiSleep; sleepContext.bits.Pm1aVal = SleepValues[1].Pm1aVal; sleepContext.bits.Pm1bVal = SleepValues[1].Pm1bVal; sleepContext.bits.Flags = SLEEP_STATE_FLUSH_CACHE | SLEEP_STATE_FIRMWARE_RESTART | SLEEP_STATE_SAVE_MOTHERBOARD | SLEEP_STATE_RESTART_OTHER_PROCESSORS; powerState.Context = (PVOID)sleepContext.AsULONG; status = ZwPowerInformation(SystemPowerStateHandler, &powerState, sizeof(POWER_STATE_HANDLER), NULL, 0); ASSERT(NT_SUCCESS(status)); } if (SleepValues[2].Supported && HalpWakeVector) { powerState.Type = PowerStateSleeping3; powerState.RtcWake = TRUE; powerState.Handler = &HaliAcpiSleep; sleepContext.bits.Pm1aVal = SleepValues[2].Pm1aVal; sleepContext.bits.Pm1bVal = SleepValues[2].Pm1bVal; sleepContext.bits.Flags = SLEEP_STATE_FLUSH_CACHE | SLEEP_STATE_FIRMWARE_RESTART | SLEEP_STATE_SAVE_MOTHERBOARD | SLEEP_STATE_RESTART_OTHER_PROCESSORS; powerState.Context = (PVOID)sleepContext.AsULONG; status = ZwPowerInformation(SystemPowerStateHandler, &powerState, sizeof(POWER_STATE_HANDLER), NULL, 0); ASSERT(NT_SUCCESS(status)); } i = 0; if (SleepValues[3].Supported) { i = 3; } else if (SleepValues[4].Supported) { i = 4; } if (i && (HalpDisableHibernate == FALSE)) { powerState.Type = PowerStateSleeping4; powerState.RtcWake = HalpFixedAcpiDescTable.flags & RTC_WAKE_FROM_S4 ? TRUE : FALSE; powerState.Handler = &HaliAcpiSleep; sleepContext.bits.Pm1aVal = SleepValues[i].Pm1aVal; sleepContext.bits.Pm1bVal = SleepValues[i].Pm1bVal; sleepContext.bits.Flags = SLEEP_STATE_SAVE_MOTHERBOARD | SLEEP_STATE_RESTART_OTHER_PROCESSORS; powerState.Context = (PVOID)sleepContext.AsULONG; status = ZwPowerInformation(SystemPowerStateHandler, &powerState, sizeof(POWER_STATE_HANDLER), NULL, 0); ASSERT(NT_SUCCESS(status)); } if (SleepValues[4].Supported) { powerState.Type = PowerStateShutdownOff; powerState.RtcWake = FALSE; powerState.Handler = &HaliAcpiSleep; sleepContext.bits.Pm1aVal = SleepValues[4].Pm1aVal; sleepContext.bits.Pm1bVal = SleepValues[4].Pm1bVal; sleepContext.bits.Flags = SLEEP_STATE_OFF; HalpShutdownContext = sleepContext; powerState.Context = (PVOID)sleepContext.AsULONG; status = ZwPowerInformation(SystemPowerStateHandler, &powerState, sizeof(POWER_STATE_HANDLER), NULL, 0); ASSERT(NT_SUCCESS(status)); } } ULONG HaliAcpiQueryFlags( VOID ) /*++ Routine Description: This routine is temporary is used to report the presence of the boot.ini switch Arguments: None Return Value: TRUE, if switch present --*/ { return HalpAcpiFlags; } NTSTATUS HaliInitPowerManagement( IN PPM_DISPATCH_TABLE PmDriverDispatchTable, IN OUT PPM_DISPATCH_TABLE *PmHalDispatchTable ) /*++ Routine Description: This is called by the ACPI driver to start the PM code. Arguments: PmDriverDispatchTable - table of functions provided by the ACPI driver for the HAL PmHalDispatchTable - table of functions provided by the HAL for the ACPI driver Return Value: status --*/ { OBJECT_ATTRIBUTES objAttributes; PCALLBACK_OBJECT callback; PHYSICAL_ADDRESS pAddr; UNICODE_STRING callbackName; NTSTATUS status; PFACS facs; PAGED_CODE(); // // Figure out if we have to work around PIIX4 // HalpPiix4Detect(TRUE); HalpPutAcpiHacksInRegistry(); // // Keep a pointer to the driver's dispatch table. // // ASSERT(PmDriverDispatchTable); // ASSERT(PmDriverDispatchTable->Signature == ACPI_HAL_DISPATCH_SIGNATURE); PmAcpiDispatchTable = PmDriverDispatchTable; // // Fill in the function table // if (!HalpBrokenAcpiTimer) { HalAcpiDispatchTable.HalpAcpiTimerInterrupt = (pHalAcpiTimerInterrupt)&HalAcpiTimerCarry; } else { HalAcpiDispatchTable.HalpAcpiTimerInterrupt = (pHalAcpiTimerInterrupt)&HalAcpiBrokenPiix4TimerCarry; } *PmHalDispatchTable = (PPM_DISPATCH_TABLE)&HalAcpiDispatchTable; // // Fill in Hal's private dispatch table // HalSetWakeEnable = HaliSetWakeEnable; HalSetWakeAlarm = HaliSetWakeAlarm; // // Register callback that tells us to make // anything we need for sleeping non-pageable. // RtlInitUnicodeString(&callbackName, L"\\Callback\\PowerState"); InitializeObjectAttributes( &objAttributes, &callbackName, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, NULL, NULL ); ExCreateCallback(&callback, &objAttributes, FALSE, TRUE); ExRegisterCallback(callback, (PCALLBACK_FUNCTION)&HalpPowerStateCallback, NULL); // // Find the location of the firmware waking vector. // N.B. If any of this fails, then HalpWakeVector will be NULL // and we won't support S2 or S3. // if (HalpFixedAcpiDescTable.facs) { pAddr.HighPart = 0; pAddr.LowPart = HalpFixedAcpiDescTable.facs; facs = MmMapIoSpace(pAddr, sizeof(FACS), MmCached); if (facs) { if (facs->Signature == FACS_SIGNATURE) { HalpWakeVector = &facs->pFirmwareWakingVector; } } } return STATUS_SUCCESS; } NTSTATUS HalpQueryAcpiResourceRequirements( IN PIO_RESOURCE_REQUIREMENTS_LIST *Requirements ) /*++ Routine Description: This routine is a temporary stub that tries to detect the presence of an ACPI controller within the system. This code is meant to be inserted within NT's root system enumerator. Arguents: Requirements - pointer to list of resources Return Value: STATUS_SUCCESS - If we found a device object STATUS_NO_SUCH_DEVICE - If we can't find info about the new PDO --*/ { NTSTATUS ntStatus; PIO_RESOURCE_REQUIREMENTS_LIST resourceList; ULONG resourceListSize; PAGED_CODE(); // // Now figure out the number of resource that we need // ntStatus = HalpAcpiDetectResourceListSize( &resourceListSize ); // // Convert this resourceListSize into the number of bytes that we // must allocate // resourceListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) + ( (resourceListSize - 1) * sizeof(IO_RESOURCE_DESCRIPTOR) ); // // Allocate the correct number of bytes of the Resource List // resourceList = ExAllocatePoolWithTag( PagedPool, resourceListSize, HAL_POOL_TAG ); // // This call must have succeeded or we cannot lay claim to ACPI // if (resourceList == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } // // Set up the ListSize in the structure // RtlZeroMemory(resourceList, resourceListSize); resourceList->ListSize = resourceListSize; // // Build the ResourceList here // ntStatus = HalpBuildAcpiResourceList(resourceList); // // Did we build the list okay? // if (!NT_SUCCESS(ntStatus)) { // // Free memory and exit // ExFreePool(resourceList); return STATUS_NO_SUCH_DEVICE; } *Requirements = resourceList; return ntStatus; } NTSTATUS HalpBuildAcpiResourceList( OUT PIO_RESOURCE_REQUIREMENTS_LIST List ) /*++ Routine Description: This is the routine that builds the ResourceList given the FADT and an arbitrary number of ResourceDescriptors. We assume that the ResourceList has been properly allocated and sized Arguments: List - The list to fill in Return Value: STATUS_SUCCESS if okay STATUS_UNSUCCESSUL if not --*/ { PIO_RESOURCE_DESCRIPTOR partialResource; ULONG count = 0; PAGED_CODE(); ASSERT( List != NULL ); // // Specify default values for Bus Type and // the bus number. These values represent root // List->AlternativeLists = 1; List->InterfaceType = PNPBus; List->BusNumber = -1; List->List[0].Version = 1; List->List[0].Revision = 1; // // Is there an interrupt resource required? // if (HalpFixedAcpiDescTable.sci_int_vector != 0) { List->List[0].Descriptors[count].Type = CmResourceTypeInterrupt; List->List[0].Descriptors[count].ShareDisposition = CmResourceShareShared; List->List[0].Descriptors[count].Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; List->List[0].Descriptors[count].u.Interrupt.MinimumVector = List->List[0].Descriptors[count].u.Interrupt.MaximumVector = HalpPicVectorRedirect[HalpFixedAcpiDescTable.sci_int_vector]; List->List[0].Count++; count++; } #if DECLARE_FADT_RESOURCES_AT_ROOT // // Is there an SMI CMD IO Port? // if (HalpFixedAcpiDescTable.smi_cmd_io_port != 0) { List->List[0].Descriptors[count].Type = CmResourceTypePort; List->List[0].Descriptors[count].ShareDisposition = CmResourceShareDeviceExclusive; List->List[0].Descriptors[count].Flags =CM_RESOURCE_PORT_IO; List->List[0].Descriptors[count].u.Port.MinimumAddress.LowPart = (ULONG) HalpFixedAcpiDescTable.smi_cmd_io_port; List->List[0].Descriptors[count].u.Port.MaximumAddress.LowPart = (ULONG) HalpFixedAcpiDescTable.smi_cmd_io_port; List->List[0].Descriptors[count].u.Port.Length = 1; List->List[0].Descriptors[count].u.Port.Alignment = 1; List->List[0].Count++; count++; } // // Is there an PM1A Event Block IO Port? // if (HalpFixedAcpiDescTable.pm1a_evt_blk_io_port != 0) { List->List[0].Descriptors[count].Type = CmResourceTypePort; List->List[0].Descriptors[count].ShareDisposition = CmResourceShareDeviceExclusive; List->List[0].Descriptors[count].Flags = CM_RESOURCE_PORT_IO; List->List[0].Descriptors[count].u.Port.MinimumAddress.LowPart = HalpFixedAcpiDescTable.pm1a_evt_blk_io_port; List->List[0].Descriptors[count].u.Port.MaximumAddress.LowPart = HalpFixedAcpiDescTable.pm1a_evt_blk_io_port + (ULONG) HalpFixedAcpiDescTable.pm1_evt_len - 1; List->List[0].Descriptors[count].u.Port.Length = (ULONG) HalpFixedAcpiDescTable.pm1_evt_len; List->List[0].Descriptors[count].u.Port.Alignment = 1; List->List[0].Count++; count++; } // // Is there a PM1B Event Block IO Port? // if (HalpFixedAcpiDescTable.pm1b_evt_blk_io_port != 0) { List->List[0].Descriptors[count].Type = CmResourceTypePort; List->List[0].Descriptors[count].ShareDisposition = CmResourceShareDeviceExclusive; List->List[0].Descriptors[count].Flags = CM_RESOURCE_PORT_IO; List->List[0].Descriptors[count].u.Port.MinimumAddress.LowPart = HalpFixedAcpiDescTable.pm1b_evt_blk_io_port; List->List[0].Descriptors[count].u.Port.MaximumAddress.LowPart = HalpFixedAcpiDescTable.pm1b_evt_blk_io_port + (ULONG) HalpFixedAcpiDescTable.pm1_evt_len - 1; List->List[0].Descriptors[count].u.Port.Length = (ULONG) HalpFixedAcpiDescTable.pm1_evt_len; List->List[0].Descriptors[count].u.Port.Alignment = 1; List->List[0].Count++; count++; } // // Is there a PM1A Control Block IO Port? // if (HalpFixedAcpiDescTable.pm1a_ctrl_blk_io_port != 0) { List->List[0].Descriptors[count].Type = CmResourceTypePort; List->List[0].Descriptors[count].ShareDisposition = CmResourceShareDeviceExclusive; List->List[0].Descriptors[count].Flags = CM_RESOURCE_PORT_IO; List->List[0].Descriptors[count].u.Port.MinimumAddress.LowPart = HalpFixedAcpiDescTable.pm1a_ctrl_blk_io_port; List->List[0].Descriptors[count].u.Port.MaximumAddress.LowPart = HalpFixedAcpiDescTable.pm1a_ctrl_blk_io_port + (ULONG) HalpFixedAcpiDescTable.pm1_ctrl_len - 1; List->List[0].Descriptors[count].u.Port.Length = (ULONG) HalpFixedAcpiDescTable.pm1_ctrl_len; List->List[0].Descriptors[count].u.Port.Alignment = 1; List->List[0].Count++; count++; } // // Is there a PM1B Control Block IO Port? // if (HalpFixedAcpiDescTable.pm1b_ctrl_blk_io_port != 0) { List->List[0].Descriptors[count].Type = CmResourceTypePort; List->List[0].Descriptors[count].ShareDisposition = CmResourceShareDeviceExclusive; List->List[0].Descriptors[count].Flags = CM_RESOURCE_PORT_IO; List->List[0].Descriptors[count].u.Port.MinimumAddress.LowPart = HalpFixedAcpiDescTable.pm1b_ctrl_blk_io_port; List->List[0].Descriptors[count].u.Port.MaximumAddress.LowPart = HalpFixedAcpiDescTable.pm1b_ctrl_blk_io_port + (ULONG) HalpFixedAcpiDescTable.pm1_ctrl_len - 1; List->List[0].Descriptors[count].u.Port.Length = (ULONG) HalpFixedAcpiDescTable.pm1_ctrl_len; List->List[0].Descriptors[count].u.Port.Alignment = 1; List->List[0].Count++; count++; } // // Is there a PM2 Control Block IO Port? // if (HalpFixedAcpiDescTable.pm2_ctrl_blk_io_port != 0) { List->List[0].Descriptors[count].Type = CmResourceTypePort; List->List[0].Descriptors[count].ShareDisposition = CmResourceShareDeviceExclusive; List->List[0].Descriptors[count].Flags = CM_RESOURCE_PORT_IO; List->List[0].Descriptors[count].u.Port.MinimumAddress.LowPart = HalpFixedAcpiDescTable.pm2_ctrl_blk_io_port; List->List[0].Descriptors[count].u.Port.MaximumAddress.LowPart = HalpFixedAcpiDescTable.pm2_ctrl_blk_io_port + (ULONG) HalpFixedAcpiDescTable.pm2_ctrl_len - 1; List->List[0].Descriptors[count].u.Port.Length = (ULONG) HalpFixedAcpiDescTable.pm2_ctrl_len; List->List[0].Descriptors[count].u.Port.Alignment = 1; List->List[0].Count++; count++; } // // Is there a PM Timer Block IO Port? // if (HalpFixedAcpiDescTable.pm_tmr_blk_io_port != 0) { List->List[0].Descriptors[count].Type = CmResourceTypePort; List->List[0].Descriptors[count].ShareDisposition = CmResourceShareDeviceExclusive; List->List[0].Descriptors[count].Flags = CM_RESOURCE_PORT_IO; List->List[0].Descriptors[count].u.Port.MinimumAddress.LowPart = HalpFixedAcpiDescTable.pm_tmr_blk_io_port; List->List[0].Descriptors[count].u.Port.MaximumAddress.LowPart = HalpFixedAcpiDescTable.pm_tmr_blk_io_port + (ULONG) HalpFixedAcpiDescTable.pm_tmr_len - 1; List->List[0].Descriptors[count].u.Port.Length = (ULONG) HalpFixedAcpiDescTable.pm_tmr_len; List->List[0].Descriptors[count].u.Port.Alignment = 1; List->List[0].Count++; count++; } // // Is there a GP0 Block IO Port? // if (HalpFixedAcpiDescTable.gp0_blk_io_port != 0) { List->List[0].Descriptors[count].Type = CmResourceTypePort; List->List[0].Descriptors[count].ShareDisposition = CmResourceShareDeviceExclusive; List->List[0].Descriptors[count].Flags = CM_RESOURCE_PORT_IO; List->List[0].Descriptors[count].u.Port.MinimumAddress.LowPart = HalpFixedAcpiDescTable.gp0_blk_io_port; List->List[0].Descriptors[count].u.Port.MaximumAddress.LowPart = HalpFixedAcpiDescTable.gp0_blk_io_port + (ULONG) HalpFixedAcpiDescTable.gp0_blk_len - 1; List->List[0].Descriptors[count].u.Port.Length = (ULONG) HalpFixedAcpiDescTable.gp0_blk_len; List->List[0].Descriptors[count].u.Port.Alignment = 1; List->List[0].Count++; count++; } // // Is there a GP1 Block IO port? // if (HalpFixedAcpiDescTable.gp1_blk_io_port != 0) { List->List[0].Descriptors[count].Type = CmResourceTypePort; List->List[0].Descriptors[count].ShareDisposition = CmResourceShareDeviceExclusive; List->List[0].Descriptors[count].Flags = CM_RESOURCE_PORT_IO; List->List[0].Descriptors[count].u.Port.MinimumAddress.LowPart = HalpFixedAcpiDescTable.gp1_blk_io_port; List->List[0].Descriptors[count].u.Port.MaximumAddress.LowPart = HalpFixedAcpiDescTable.gp1_blk_io_port + (ULONG) HalpFixedAcpiDescTable.gp1_blk_len - 1; List->List[0].Descriptors[count].u.Port.Length = (ULONG) HalpFixedAcpiDescTable.gp1_blk_len; List->List[0].Descriptors[count].u.Port.Alignment = 1; List->List[0].Count++; count++; } #endif // DECLARE_FADT_RESOURCES_AT_ROOT return STATUS_SUCCESS; } NTSTATUS HalpAcpiDetectResourceListSize( OUT PULONG ResourceListSize ) /*++ Routine Description: Given a pointer to an FADT, determine the number of CM_PARTIAL_RESOURCE_DESCRIPTORS that are required to describe all the resource mentioned in the FADT Arguments: ResourceListSize - Location to store the answer Return Value: STATUS_SUCCESS if everything went okay --*/ { PAGED_CODE(); // // First of all, assume that we need no resources // *ResourceListSize = 0; // // Is there an interrupt resource required? // if (HalpFixedAcpiDescTable.sci_int_vector != 0) { *ResourceListSize += 1; } #if DECLARE_FADT_RESOURCES_AT_ROOT // // Is there an SMI CMD IO Port? // if (HalpFixedAcpiDescTable.smi_cmd_io_port != 0) { *ResourceListSize += 1; } // // Is there an PM1A Event Block IO Port? // if (HalpFixedAcpiDescTable.pm1a_evt_blk_io_port != 0) { *ResourceListSize += 1; } // // Is there a PM1B Event Block IO Port? // if (HalpFixedAcpiDescTable.pm1b_evt_blk_io_port != 0) { *ResourceListSize += 1; } // // Is there a PM1A Control Block IO Port? // if (HalpFixedAcpiDescTable.pm1a_ctrl_blk_io_port != 0) { *ResourceListSize += 1; } // // Is there a PM1B Control Block IO Port? // if (HalpFixedAcpiDescTable.pm1b_ctrl_blk_io_port != 0) { *ResourceListSize += 1; } // // Is there a PM2 Control Block IO Port? // if (HalpFixedAcpiDescTable.pm2_ctrl_blk_io_port != 0) { *ResourceListSize += 1; } // // Is there a PM Timer Block IO Port? // if (HalpFixedAcpiDescTable.pm_tmr_blk_io_port != 0) { *ResourceListSize += 1; } // // Is there a GP0 Block IO Port? // if (HalpFixedAcpiDescTable.gp0_blk_io_port != 0) { *ResourceListSize += 1; } // // Is there a GP1 Block IO Port? // if (HalpFixedAcpiDescTable.gp1_blk_io_port != 0) { *ResourceListSize += 1; } #endif // DECLARE_FADT_RESOURCES_AT_ROOT return STATUS_SUCCESS; } VOID HalpPiix4Detect( BOOLEAN DuringBoot ) /*++ Routine Description: This routine detects both the PIIX4 and the 440BX and enables various workarounds. It also disconnects the PIIX4 USB controller from the interrupt controller, as many BIOSes boot with the USB controller in an interrupting state. Arguments: DuringBoot - if TRUE, then do all the things that have to happen at first boot if FALSE, then do only the things that have to happen each time the system transitions to system state S0. Note: This routine calls functions that must be called at PASSIVE_LEVEL when DuringBoot is TRUE. --*/ { OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING UnicodeString; STRING AString; NTSTATUS Status; HANDLE BaseHandle = NULL; HANDLE Handle = NULL; BOOLEAN i440BXpresent = FALSE; ULONG Length; ULONG BytesRead; UCHAR BusNumber; ULONG DeviceNumber; ULONG FuncNumber; PCI_SLOT_NUMBER SlotNumber; PCI_COMMON_CONFIG PciHeader; UCHAR DevActB; UCHAR DramControl; ULONG disposition; ULONG flags; CHAR buffer[20] = {0}; struct { KEY_VALUE_PARTIAL_INFORMATION Inf; UCHAR Data[3]; } PartialInformation; if (DuringBoot) { PAGED_CODE(); // // Open current control set // RtlInitUnicodeString (&UnicodeString, L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET"); InitializeObjectAttributes(&ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, (PSECURITY_DESCRIPTOR) NULL); Status = ZwOpenKey (&BaseHandle, KEY_READ, &ObjectAttributes); if (!NT_SUCCESS(Status)) { return; } // Get the right key RtlInitUnicodeString (&UnicodeString, L"Control\\HAL"); InitializeObjectAttributes(&ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE, BaseHandle, (PSECURITY_DESCRIPTOR) NULL); Status = ZwCreateKey (&Handle, KEY_READ, &ObjectAttributes, 0, (PUNICODE_STRING) NULL, REG_OPTION_NON_VOLATILE, &disposition); if(!NT_SUCCESS(Status)) { goto Piix4DetectCleanup; } } // // Check each existing PCI bus for a PIIX4 chip. // for (BusNumber = 0; BusNumber < 0xff; BusNumber++) { SlotNumber.u.AsULONG = 0; for (DeviceNumber = 0; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber ++ ) { for (FuncNumber = 0; FuncNumber < PCI_MAX_FUNCTION; FuncNumber ++) { SlotNumber.u.bits.DeviceNumber = DeviceNumber; SlotNumber.u.bits.FunctionNumber = FuncNumber; BytesRead = HalGetBusData ( PCIConfiguration, BusNumber, SlotNumber.u.AsULONG, &PciHeader, PCI_COMMON_HDR_LENGTH ); if (!BytesRead) { // past last bus goto Piix4DetectEnd; } if (PciHeader.VendorID == PCI_INVALID_VENDORID) { continue; } if (DuringBoot) { // // Look for broken 440BX. // if (((PciHeader.VendorID == 0x8086) && (PciHeader.DeviceID == 0x7190 || PciHeader.DeviceID == 0x7192) && (PciHeader.RevisionID <= 2))) { i440BXpresent = TRUE; BytesRead = HalGetBusDataByOffset ( PCIConfiguration, BusNumber, SlotNumber.u.AsULONG, &DramControl, 0x57, 1 ); ASSERT(BytesRead == 1); if (DramControl & 0x18) { // // This machine is using SDRAM or Registered SDRAM. // if (DramControl & 0x20) { // // SDRAM dynamic power down unavailable. // HalpBroken440BX = TRUE; } } } Status = HalpGetChipHacks(PciHeader.VendorID, PciHeader.DeviceID, 0, &flags); if (NT_SUCCESS(Status)) { if (flags & PM_TIMER_HACK_FLAG) { HalpBrokenAcpiTimer = TRUE; } if (flags & DISABLE_HIBERNATE_HACK_FLAG) { HalpDisableHibernate = TRUE; } #if !defined(APIC_HAL) if (flags & SET_ACPI_IRQSTACK_HACK_FLAG) { HalpSetAcpiIrqHack(2); // AcpiIrqDistributionDispositionStackUp } #endif if (flags & WHACK_ICH_USB_SMI_HACK_FLAG) { HalpWhackICHUsbSmi(BusNumber, SlotNumber); } } } // // Look for PIIX4. // if (PciHeader.VendorID == 0x8086 && PciHeader.DeviceID == 0x7110) { // // Get the power management function // SlotNumber.u.bits.FunctionNumber = 3; HalGetBusData ( PCIConfiguration, BusNumber, SlotNumber.u.AsULONG, &PciHeader, PCI_COMMON_HDR_LENGTH ); ASSERT(PciHeader.RevisionID != 0); HalpPiix4 = PciHeader.RevisionID; HalpBrokenAcpiTimer = TRUE; // // If this is an original piix4, then it has thermal joined // with C2&C3&Throttle clock stopping. // if (PciHeader.RevisionID <= 1) { // // This piix4 needs some help - remember where it is and // set the HalpPiix4 flag // HalpPiix4BusNumber = BusNumber; HalpPiix4SlotNumber = SlotNumber.u.AsULONG; // // Does not work MP // // ASSERT (KeNumberProcessors == 1); // // Read the DevActB register and set all IRQs to be break events // HalGetBusDataByOffset ( PCIConfiguration, HalpPiix4BusNumber, HalpPiix4SlotNumber, &HalpPiix4DevActB, 0x58, sizeof(ULONG) ); HalpPiix4DevActB |= 0x23; HalSetBusDataByOffset ( PCIConfiguration, HalpPiix4BusNumber, HalpPiix4SlotNumber, &HalpPiix4DevActB, 0x58, sizeof(ULONG) ); } // // Shut off the interrupt for the USB controller. // SlotNumber.u.bits.FunctionNumber = 2; HalpStopUhciInterrupt(BusNumber, SlotNumber, TRUE); // piix4 was found, we're done goto Piix4DetectEnd; } // // Look for ICH, or any other Intel or VIA UHCI USB controller. // if ((PciHeader.BaseClass == PCI_CLASS_SERIAL_BUS_CTLR) && (PciHeader.SubClass == PCI_SUBCLASS_SB_USB) && (PciHeader.ProgIf == 0x00)) { if (PciHeader.VendorID == 0x8086) { HalpStopUhciInterrupt(BusNumber, SlotNumber, TRUE); } else if (PciHeader.VendorID == 0x1106) { HalpStopUhciInterrupt(BusNumber, SlotNumber, FALSE); } } // // Look for an OHCI-compliant USB controller. // if ((PciHeader.BaseClass == PCI_CLASS_SERIAL_BUS_CTLR) && (PciHeader.SubClass == PCI_SUBCLASS_SB_USB) && (PciHeader.ProgIf == 0x10)) { HalpStopOhciInterrupt(BusNumber, SlotNumber); } if ((FuncNumber == 0) && !PCI_MULTIFUNCTION_DEVICE((&PciHeader))) { break; } } // func number } // device number } // bus number Piix4DetectEnd: if (!DuringBoot) { return; } if (Handle) { ZwClose (Handle); Handle = NULL; } if (i440BXpresent) { // Get the right key RtlInitUnicodeString (&UnicodeString, L"Services\\ACPI\\Parameters"); InitializeObjectAttributes(&ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE, BaseHandle, (PSECURITY_DESCRIPTOR) NULL); Status = ZwCreateKey (&Handle, KEY_READ, &ObjectAttributes, 0, (PUNICODE_STRING) NULL, REG_OPTION_NON_VOLATILE, &disposition); if(!NT_SUCCESS(Status)) { goto Piix4DetectCleanup; } // Get the value of the hack RtlInitUnicodeString (&UnicodeString, L"EnableBXWorkAround"); Status = ZwQueryValueKey (Handle, &UnicodeString, KeyValuePartialInformation, &PartialInformation, sizeof (PartialInformation), &Length); if (!NT_SUCCESS(Status)) { goto Piix4DetectCleanup; } // Check to make sure the retrieved data makes sense if(PartialInformation.Inf.DataLength < sizeof(UCHAR)) { goto Piix4DetectCleanup; } HalpBroken440BX = *((PCHAR)(PartialInformation.Inf.Data)); } Piix4DetectCleanup: if (Handle) ZwClose (Handle); if (BaseHandle) ZwClose (BaseHandle); } VOID HalpInitBootTable ( IN PLOADER_PARAMETER_BLOCK LoaderBlock ) { UCHAR BootRegisterValue; HalpSimpleBootFlagTable = (PBOOT_TABLE)HalpGetAcpiTablePhase0(LoaderBlock, BOOT_SIGNATURE); // // We also verify that the CMOS index of the flag offset is >9 to catch those // BIOSes (Toshiba) which mistakenly use the time and date fields to store their // simple boot flag. // if ( HalpSimpleBootFlagTable && (HalpSimpleBootFlagTable->Header.Length >= sizeof(BOOT_TABLE)) && (HalpSimpleBootFlagTable->CMOSIndex > 9)) { if ( HalReadBootRegister (&BootRegisterValue) == STATUS_SUCCESS ) { if ( !(BootRegisterValue & SBF_PNPOS) ) { BootRegisterValue |= SBF_PNPOS; HalWriteBootRegister (BootRegisterValue); } } } else { HalpSimpleBootFlagTable = NULL; } HalEndOfBoot = HalpEndOfBoot; } NTSTATUS HalReadBootRegister( PUCHAR BootRegisterValue ) /*++ Routine Description: Arguments: Note: --*/ { if (!HalpSimpleBootFlagTable || (HalpSimpleBootFlagTable->CMOSIndex == 0xFFFFFFFF)) return STATUS_NO_SUCH_DEVICE; if (!BootRegisterValue) return STATUS_INVALID_PARAMETER; HalpGetCmosData (0, HalpSimpleBootFlagTable->CMOSIndex, (PVOID)BootRegisterValue, 1); return STATUS_SUCCESS; } NTSTATUS HalWriteBootRegister( UCHAR BootRegisterValue ) /*++ Routine Description: Arguments: Note: --*/ { UCHAR numbits = 0, mask = 1; if (!HalpSimpleBootFlagTable || (HalpSimpleBootFlagTable->CMOSIndex == 0xFFFFFFFF)) return STATUS_NO_SUCH_DEVICE; for (mask = 1;mask < 128;mask <<= 1) { if (BootRegisterValue & mask) numbits++; } if ( !(numbits & 1) ) { BootRegisterValue |= SBF_PARITY; } else { BootRegisterValue &= (~SBF_PARITY); } HalpSetCmosData (0, HalpSimpleBootFlagTable->CMOSIndex, (PVOID)&BootRegisterValue, 1); return STATUS_SUCCESS; } VOID HalpEndOfBoot( VOID ) /*++ Routine Description: Arguments: Note: --*/ { HalpResetSBF(); } VOID HalpResetSBF( VOID ) { UCHAR value; if (!HalpSimpleBootFlagTable) { // // No SBF in this machine. // return; } if ( HalReadBootRegister (&value) == STATUS_SUCCESS ) { value &=(~(SBF_BOOTING | SBF_DIAG)); HalWriteBootRegister (value); } } VOID HalpPutAcpiHacksInRegistry( VOID ) { OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING UnicodeString; HANDLE BaseHandle = NULL; HANDLE Handle = NULL; ULONG disposition; ULONG value; NTSTATUS status; PAGED_CODE(); // // Open PCI service key. // RtlInitUnicodeString (&UnicodeString, L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\Control\\HAL"); InitializeObjectAttributes(&ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, (PSECURITY_DESCRIPTOR) NULL); status = ZwOpenKey (&BaseHandle, KEY_READ, &ObjectAttributes); if (!NT_SUCCESS(status)) { return; } // Get the right key RtlInitUnicodeString (&UnicodeString, L"CStateHacks"); InitializeObjectAttributes(&ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE, BaseHandle, (PSECURITY_DESCRIPTOR) NULL); status = ZwCreateKey (&Handle, KEY_READ, &ObjectAttributes, 0, (PUNICODE_STRING) NULL, REG_OPTION_VOLATILE, &disposition); ZwClose(BaseHandle); if (!NT_SUCCESS(status)) { return; } // // Create keys for each of the hacks. // value = (ULONG)HalpPiix4; RtlInitUnicodeString (&UnicodeString, L"Piix4"); status = ZwSetValueKey (Handle, &UnicodeString, 0, REG_DWORD, &value, sizeof(ULONG)); //ASSERT(NT_SUCCESS(status)); value = (ULONG)HalpBroken440BX; RtlInitUnicodeString (&UnicodeString, L"440BX"); status = ZwSetValueKey (Handle, &UnicodeString, 0, REG_DWORD, &value, sizeof(ULONG)); //ASSERT(NT_SUCCESS(status)); value = (ULONG)&HalpOutstandingScatterGatherCount; RtlInitUnicodeString (&UnicodeString, L"SGCount"); status = ZwSetValueKey (Handle, &UnicodeString, 0, REG_DWORD, &value, sizeof(ULONG)); //ASSERT(NT_SUCCESS(status)); value = HalpPiix4SlotNumber | (HalpPiix4BusNumber << 16); RtlInitUnicodeString (&UnicodeString, L"Piix4Slot"); status = ZwSetValueKey (Handle, &UnicodeString, 0, REG_DWORD, &value, sizeof(ULONG)); //ASSERT(NT_SUCCESS(status)); value = HalpPiix4DevActB; RtlInitUnicodeString (&UnicodeString, L"Piix4DevActB"); status = ZwSetValueKey (Handle, &UnicodeString, 0, REG_DWORD, &value, sizeof(ULONG)); //ASSERT(NT_SUCCESS(status)); ZwClose(Handle); return; }