/*++ Copyright (c) 1991 Microsoft Corporation Module Name: xxhal.c Abstract: This module implements the initialization of the system dependent functions that define the Hardware Architecture Layer (HAL) for an x86 system. Author: David N. Cutler (davec) 25-Apr-1991 Environment: Kernel mode only. Revision History: --*/ #include "halp.h" ULONG HalpBusType; extern ADDRESS_USAGE HalpDefaultPcIoSpace; extern ADDRESS_USAGE HalpEisaIoSpace; extern UCHAR HalpSzPciLock[]; extern UCHAR HalpSzBreak[]; extern BOOLEAN HalpPciLockSettings; extern UCHAR HalpAuthenticAMD[]; extern UCHAR HalpGenuineIntel[]; extern PULONG KiEnableTimerWatchdog; extern ULONG HalpTimerWatchdogEnabled; extern PCHAR HalpTimerWatchdogStorage; extern PVOID HalpTimerWatchdogCurFrame; extern PVOID HalpTimerWatchdogLastFrame; extern ULONG HalpTimerWatchdogStorageOverflow; extern KSPIN_LOCK HalpDmaAdapterListLock; extern LIST_ENTRY HalpDmaAdapterList; #ifdef ACPI_HAL extern KEVENT HalpNewAdapter; #endif VOID HalpGetParameters ( IN PLOADER_PARAMETER_BLOCK LoaderBlock ); ULONG HalpGetFeatureBits ( VOID ); VOID HalpInitReservedPages( VOID ); VOID HalpAcpiTimerPerfCountHack( VOID ); #ifndef NT_UP ULONG HalpInitMP( IN ULONG Phase, IN PLOADER_PARAMETER_BLOCK LoaderBlock ); #endif KSPIN_LOCK HalpSystemHardwareLock; #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT,HalpGetParameters) #pragma alloc_text(INIT,HalInitSystem) #endif VOID HalpGetParameters ( IN PLOADER_PARAMETER_BLOCK LoaderBlock ) /*++ Routine Description: This gets any parameters from the boot.ini invocation line. Arguments: None. Return Value: None --*/ { PCHAR Options; if (LoaderBlock != NULL && LoaderBlock->LoadOptions != NULL) { Options = LoaderBlock->LoadOptions; // // Check if PCI settings are locked down // if (strstr(Options, HalpSzPciLock)) { HalpPciLockSettings = TRUE; } // // Has the user asked for an initial BreakPoint? // if (strstr(Options, HalpSzBreak)) { DbgBreakPoint(); } } return; } VOID HalpInitTimerWatchdog( IN ULONG Phase ) /*++ Routine Description: Determines if the system is running on a GenuineIntel part and initializes HalpTimerWatchdogEnabled accordingly. Arguments: None. Return Value: None. --*/ { if (Phase == 0) { ULONG GenuinePentiumOrLater = FALSE, Junk; PKPRCB Prcb; Prcb = KeGetCurrentPrcb(); if (Prcb->CpuID) { UCHAR Buffer[50]; // // Determine the processor type // HalpCpuID (0, &Junk, (PULONG) Buffer+0, (PULONG) Buffer+2, (PULONG) Buffer+1); Buffer[12] = 0; GenuinePentiumOrLater = ((strcmp(Buffer, HalpGenuineIntel) == 0) && (Prcb->CpuType >= 5)); HalpTimerWatchdogEnabled = GenuinePentiumOrLater; } } else if (HalpTimerWatchdogEnabled) { // // Allocate 2 pages for stack snapshots, each snapshot is 64 DWORDs. // if (HalpTimerWatchdogStorage = ExAllocatePoolWithTag( NonPagedPool, PAGE_SIZE * 2, HAL_POOL_TAG )) { HalpTimerWatchdogLastFrame = HalpTimerWatchdogStorage + (PAGE_SIZE * 2 - 64*4); HalpTimerWatchdogStorageOverflow = 0; HalpTimerWatchdogCurFrame = HalpTimerWatchdogStorage; } else { HalpTimerWatchdogEnabled = FALSE; } } } BOOLEAN HalInitSystem ( IN ULONG Phase, IN PLOADER_PARAMETER_BLOCK LoaderBlock ) /*++ Routine Description: This function initializes the Hardware Architecture Layer (HAL) for an x86 system. Arguments: None. Return Value: A value of TRUE is returned is the initialization was successfully complete. Otherwise a value of FALSE is returend. --*/ { PMEMORY_ALLOCATION_DESCRIPTOR Descriptor; PLIST_ENTRY NextMd; KIRQL CurrentIrql; PKPRCB pPRCB; ULONG mapBufferSize; ULONG mapBufferAddress; pPRCB = KeGetCurrentPrcb(); if (Phase == 0) { HalpBusType = LoaderBlock->u.I386.MachineType & 0x00ff; HalpGetParameters (LoaderBlock); // // Verify Prcb version and build flags conform to // this image // #if DBG if (!(pPRCB->BuildType & PRCB_BUILD_DEBUG)) { // This checked hal requires a checked kernel KeBugCheckEx (MISMATCHED_HAL, 2, pPRCB->BuildType, PRCB_BUILD_DEBUG, 0); } #else if (pPRCB->BuildType & PRCB_BUILD_DEBUG) { // This free hal requires a free kernel KeBugCheckEx (MISMATCHED_HAL, 2, pPRCB->BuildType, 0, 0); } #endif #ifndef NT_UP if (pPRCB->BuildType & PRCB_BUILD_UNIPROCESSOR) { // This MP hal requires an MP kernel KeBugCheckEx (MISMATCHED_HAL, 2, pPRCB->BuildType, 0, 0); } #endif if (pPRCB->MajorVersion != PRCB_MAJOR_VERSION) { KeBugCheckEx (MISMATCHED_HAL, 1, pPRCB->MajorVersion, PRCB_MAJOR_VERSION, 0); } // // Phase 0 initialization // only called by P0 // // // Check to make sure the MCA HAL is not running on an ISA/EISA // system, and vice-versa. // #if MCA if (HalpBusType != MACHINE_TYPE_MCA) { KeBugCheckEx (MISMATCHED_HAL, 3, HalpBusType, MACHINE_TYPE_MCA, 0); } #else if (HalpBusType == MACHINE_TYPE_MCA) { KeBugCheckEx (MISMATCHED_HAL, 3, HalpBusType, 0, 0); } #endif #ifdef ACPI_HAL // // Make sure that this is really an ACPI machine and initialize // the ACPI structures. // HalpSetupAcpiPhase0(LoaderBlock); #endif HalpInitializePICs(TRUE); // // Now that the PICs are initialized, we need to mask them to // reflect the current Irql // CurrentIrql = KeGetCurrentIrql(); CurrentIrql = KfRaiseIrql(CurrentIrql); // // Initialize CMOS // HalpInitializeCmos(); // // Fill in handlers for APIs which this hal supports // HalQuerySystemInformation = HaliQuerySystemInformation; HalSetSystemInformation = HaliSetSystemInformation; HalInitPnpDriver = HaliInitPnpDriver; HalGetDmaAdapter = HaliGetDmaAdapter; HalHaltSystem = HaliHaltSystem; HalResetDisplay = HalpBiosDisplayReset; HalAllocateMapRegisters = HalpAllocateMapRegisters; #if !defined( HAL_SP ) #ifdef ACPI_HAL HalGetInterruptTranslator = HalacpiGetInterruptTranslator; #else HalGetInterruptTranslator = HaliGetInterruptTranslator; #endif #endif #if !defined( HAL_SP ) && !(MCA) HalInitPowerManagement = HaliInitPowerManagement; HalLocateHiberRanges = HaliLocateHiberRanges; #endif // // Register cascade vector // HalpRegisterVector ( InternalUsage, PIC_SLAVE_IRQ + PRIMARY_VECTOR_BASE, PIC_SLAVE_IRQ + PRIMARY_VECTOR_BASE, HIGH_LEVEL ); // // Keep track of which IRQs are level triggered. // if (HalpBusType == MACHINE_TYPE_EISA) { HalpRecordEisaInterruptVectors(); } // // Register base IO space used by hal // HalpRegisterAddressUsage (&HalpDefaultPcIoSpace); if (HalpBusType == MACHINE_TYPE_EISA) { HalpRegisterAddressUsage (&HalpEisaIoSpace); } // // Note that HalpInitializeClock MUST be called after // HalpInitializeStallExecution, because HalpInitializeStallExecution // reprograms the timer. // HalpInitializeStallExecution(0); // // Init timer watchdog if enabled. // HalpInitTimerWatchdog(Phase); // // Setup the clock // HalpInitializeClock(); // // Make sure profile is disabled // HalStopProfileInterrupt(0); // // Remove this for the sake of the graphical boot driver. There is // no negative effect of this. If the display isn't initialized, it // will be initialized during HalDisplayString. // // HalpInitializeDisplay(); // // Initialize spinlock used by HalGetBusData hardware access routines // KeInitializeSpinLock(&HalpSystemHardwareLock); // // Initialize data structures used to chain dma adapters // together for debugging purposes // KeInitializeSpinLock(&HalpDmaAdapterListLock); InitializeListHead(&HalpDmaAdapterList); #ifdef ACPI_HAL // // Initialize synchronzation event used to serialize // new adapter events on the ACPI HAL (which has no notion of bus // handlers) // KeInitializeEvent (&HalpNewAdapter, SynchronizationEvent, TRUE); #endif // // Determine if there is physical memory above 16 MB. // LessThan16Mb = TRUE; NextMd = LoaderBlock->MemoryDescriptorListHead.Flink; while (NextMd != &LoaderBlock->MemoryDescriptorListHead) { Descriptor = CONTAINING_RECORD( NextMd, MEMORY_ALLOCATION_DESCRIPTOR, ListEntry ); if (Descriptor->MemoryType != LoaderFirmwarePermanent && Descriptor->MemoryType != LoaderSpecialMemory && Descriptor->BasePage + Descriptor->PageCount > 0x1000) { LessThan16Mb = FALSE; break; } NextMd = Descriptor->ListEntry.Flink; } #if !defined(_HALPAE_) HalpMapBufferSize = INITIAL_MAP_BUFFER_SMALL_SIZE; // // Allocate map buffers for the adapter objects // HalpMapBufferPhysicalAddress.LowPart = HalpAllocPhysicalMemory (LoaderBlock, MAXIMUM_PHYSICAL_ADDRESS, HalpMapBufferSize >> PAGE_SHIFT, TRUE); HalpMapBufferPhysicalAddress.HighPart = 0; if (!HalpMapBufferPhysicalAddress.LowPart) { // // There was not a satisfactory block. Clear the allocation. // HalpMapBufferSize = 0; } #else // // Initialize and allocate map buffers for the 24bit master adapter // object. // MasterAdapter24.MaxBufferPages = MAXIMUM_ISA_MAP_BUFFER_SIZE / PAGE_SIZE; mapBufferSize = INITIAL_MAP_BUFFER_SMALL_SIZE; mapBufferAddress = HalpAllocPhysicalMemory (LoaderBlock, MAXIMUM_PHYSICAL_ADDRESS, mapBufferSize >> PAGE_SHIFT, TRUE); if (mapBufferAddress == 0) { mapBufferSize = 0; } MasterAdapter24.MapBufferPhysicalAddress.LowPart = mapBufferAddress; MasterAdapter24.MapBufferPhysicalAddress.HighPart = 0; MasterAdapter24.MapBufferSize = mapBufferSize; if (HalPaeEnabled() != FALSE) { // // Initialize and allocate map buffers for the 32bit master adapter // object. This should only be needed on a PAE-enabled system. // MasterAdapter32.MaxBufferPages = MAXIMUM_PCI_MAP_BUFFER_SIZE / PAGE_SIZE; mapBufferSize = INITIAL_MAP_BUFFER_LARGE_SIZE; mapBufferAddress = HalpAllocPhysicalMemory (LoaderBlock, (ULONG)-1, mapBufferSize >> PAGE_SHIFT, TRUE); if (mapBufferAddress == 0) { mapBufferSize = 0; } MasterAdapter32.MapBufferPhysicalAddress.LowPart = mapBufferAddress; MasterAdapter32.MapBufferPhysicalAddress.HighPart = 0; MasterAdapter32.MapBufferSize = mapBufferSize; } #endif } else { // // Phase 1 initialization // if (pPRCB->Number == 0) { // // Back-pocket some PTEs for DMA during low mem // HalpInitReservedPages(); #ifndef ACPI_HAL // // If P0, then setup global vectors // HalpRegisterInternalBusHandlers (); #else HalpInitNonBusHandler(); #endif // // Set feature bits // HalpFeatureBits = HalpGetFeatureBits(); // // Use movnti routine to copy memory if Movnti support is detected // #if !defined(_WIN64) if (HalpFeatureBits & HAL_WNI_PRESENT) { HalpMoveMemory = HalpMovntiCopyBuffer; } #endif // // Init timer watchdog if enabled (allocate stack snapshot buffer). // HalpInitTimerWatchdog(Phase); HalpEnableInterruptHandler ( DeviceUsage | InterruptLatched, // Report as device vector V2I (CLOCK_VECTOR), // Bus interrupt level CLOCK_VECTOR, // System IDT CLOCK2_LEVEL, // System Irql HalpClockInterrupt, // ISR Latched ); HalpEnableInterruptHandler ( DeviceUsage | InterruptLatched, // Report as device vector V2I (PROFILE_VECTOR), // Bus interrupt level PROFILE_VECTOR, // System IDT PROFILE_LEVEL, // System Irql HalpProfileInterrupt, // ISR Latched ); #ifdef ACPI_HAL #if !defined(_WIN64) // // Perf counter patch for non-compliant ACPI machines // HalpAcpiTimerPerfCountHack(); #endif #endif #if !defined(_WIN64) // // If 486, the FP error will be routed via trap10. So we // don't enable irq13. Otherwise (CPU=386), we will enable irq13 // to handle FP error. // if (pPRCB->CpuType == 3) { HalpEnableInterruptHandler ( DeviceUsage, // Report as device vector V2I (I386_80387_VECTOR), // Bus interrupt level I386_80387_VECTOR, // System IDT I386_80387_IRQL, // System Irql HalpIrq13Handler, // ISR Latched ); } #endif } } #ifndef NT_UP HalpInitMP (Phase, LoaderBlock); #endif return TRUE; } ULONG HalpGetFeatureBits ( VOID ) { UCHAR Buffer[50]; ULONG Junk, ProcessorFeatures, Bits; PKPRCB Prcb; ULONGLONG ApicBits; Bits = 0; Prcb = KeGetCurrentPrcb(); if (!Prcb->CpuID) { Bits |= HAL_NO_SPECULATION; return Bits; } // // Determine the processor type // HalpCpuID (0, &Junk, (PULONG) Buffer+0, (PULONG) Buffer+2, (PULONG) Buffer+1); Buffer[12] = 0; HalpCpuID (1, &Junk, &Junk, &Junk, &ProcessorFeatures); // // Determine which features are present. // if (strcmp (Buffer, HalpGenuineIntel) == 0) { // // Check Intel feature bits for HAL features needed // if (Prcb->CpuType == 6) { Bits |= HAL_PERF_EVENTS; // // Workaround for Pentium Pro Local APIC trap 0x0F and trap 0x00 // spurious interrupt errata 5AP and 6AP. Disable the Local APIC // on UP Pentium Pro Systems. Interrupts are routed directly from // 8259 PIC to CPU. // ApicBits = RDMSR(APIC_BASE_MSR); if (ApicBits & APIC_ENABLED) { // // Local APIC is enabled - Disable it. // WRMSR(APIC_BASE_MSR, (ApicBits & ~APIC_ENABLED)); } } if (Prcb->CpuType < 6) { Bits |= HAL_NO_SPECULATION; } } else if (strcmp (Buffer, HalpAuthenticAMD) == 0) { ULONG ExtendedProcessorFeatures; ULONG MaxExtendedFunc; MaxExtendedFunc = 0; HalpCpuID (0x80000000, &MaxExtendedFunc, &Junk, &Junk, &Junk); if (MaxExtendedFunc >= 0x80000001) { HalpCpuID (0x80000001, &Junk, &Junk, &Junk, &ExtendedProcessorFeatures); if (ExtendedProcessorFeatures & CPUID_NX_MASK) { Bits |= HAL_NX_PRESENT; } } } if (ProcessorFeatures & CPUID_MCA_MASK) { Bits |= HAL_MCA_PRESENT; } if (ProcessorFeatures & CPUID_MCE_MASK) { Bits |= HAL_MCE_PRESENT; } if (ProcessorFeatures & CPUID_VME_MASK) { Bits |= HAL_CR4_PRESENT; } if (ProcessorFeatures & CPUID_WNI_MASK) { Bits |= HAL_WNI_PRESENT; } return Bits; } #if !defined(_WIN64) BOOLEAN HalpIsNXEnabled ( VOID ) /*++ Routine Description: This function returns a boolean indicating whether the current processor has the no-execute bit set in the EFER MSR. Arguments: None. Return Value: A value of TRUE is returned indicates that the current processor has enabled NX mode, otherwise FALSE is returned. --*/ { ULONGLONG msrValue; BOOLEAN result; result = FALSE; if ((HalpGetFeatureBits() & HAL_NX_PRESENT) != 0) { msrValue = RDMSR(0xc0000080); if ((msrValue & 0x800) != 0) { result = TRUE; } } return result; } #endif