/*++ Copyright (c) 1991 Microsoft Corporation Copyright (c) 1992 Intel Corporation All rights reserved INTEL CORPORATION PROPRIETARY INFORMATION This software is supplied to Microsoft under the terms of a license agreement with Intel Corporation and may not be copied nor disclosed except in accordance with the terms of that agreement. Module Name: mphal.c Abstract: This module implements the initialization of the system dependent functions that define the Hardware Architecture Layer (HAL) for a PC+MP system. Author: David N. Cutler (davec) 25-Apr-1991 Environment: Kernel mode only. Revision History: Ron Mosgrove (Intel) - Modified to support the PC+MP Spec Jake Oshins (jakeo) - Modified to support the ACPI Spec */ #include "halp.h" #include "pcmp_nt.inc" #include "string.h" #include "stdlib.h" #include "stdio.h" ULONG HalpBusType; extern ADDRESS_USAGE HalpDefaultPcIoSpace; extern ADDRESS_USAGE HalpEisaIoSpace; extern ADDRESS_USAGE HalpImcrIoSpace; extern struct HalpMpInfo HalpMpInfoTable; extern UCHAR rgzRTCNotFound[]; extern USHORT HalpVectorToINTI[]; extern UCHAR HalpGenuineIntel[]; extern const UCHAR HalName[]; extern BOOLEAN HalpDoingCrashDump; 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; extern ULONG HalpProc0TSCHz; #ifdef ACPI_HAL extern ULONG HalpPicVectorRedirect[]; #define ADJUSTED_VECTOR(x) \ HalpPicVectorRedirect[x] #else #define ADJUSTED_VECTOR(x) x #endif VOID HalpInitMP( IN ULONG Phase, IN PLOADER_PARAMETER_BLOCK LoaderBlock ); KSPIN_LOCK HalpSystemHardwareLock; VOID HalpInitBusHandlers ( VOID ); VOID HalpClockInterruptPn( VOID ); VOID HalpClockInterruptStub( VOID ); BOOLEAN HalpmmTimer( VOID ); VOID HalpmmTimerClockInit( VOID ); VOID HalpmmTimerClockInterruptStub( VOID ); ULONG HalpScaleTimers( VOID ); BOOLEAN HalpPmTimerScaleTimers( VOID ); VOID HalpApicRebootService( VOID ); VOID HalpBroadcastCallService( VOID ); VOID HalpDispatchInterrupt( VOID ); VOID HalpApcInterrupt( VOID ); VOID HalpIpiHandler( VOID ); VOID HalpInitializeIOUnits ( VOID ); VOID HalpInitIntiInfo ( VOID ); VOID HalpGetParameters ( IN PLOADER_PARAMETER_BLOCK LoaderBlock ); VOID HalpInitializeTimerResolution ( ULONG Rate ); ULONG HalpGetFeatureBits ( VOID ); VOID HalpInitializeApicAddressing( UCHAR Number ); VOID HalpInitReservedPages( VOID ); VOID HalpAcpiTimerPerfCountHack( VOID ); BOOLEAN HalpFindBusAddressTranslation( IN PHYSICAL_ADDRESS BusAddress, IN OUT PULONG AddressSpace, OUT PPHYSICAL_ADDRESS TranslatedAddress, IN OUT PULONG_PTR Context, IN BOOLEAN NextBus ); #ifdef DEBUGGING extern void HalpDisplayLocalUnit(void); extern void HalpDisplayConfigTable(void); extern void HalpDisplayExtConfigTable(void); #endif // DEBUGGING BOOLEAN HalpStaticIntAffinity = FALSE; BOOLEAN HalpClockMode = Latched; UCHAR HalpMaxProcsPerCluster = 0; extern BOOLEAN HalpUse8254; extern UCHAR HalpSzInterruptAffinity[]; extern BOOLEAN HalpPciLockSettings; extern UCHAR HalpVectorToIRQL[]; extern ULONG HalpDontStartProcessors; extern UCHAR HalpSzOneCpu[]; extern UCHAR HalpSzNoIoApic[]; extern UCHAR HalpSzBreak[]; extern UCHAR HalpSzPciLock[]; extern UCHAR HalpSzTimerRes[]; extern UCHAR HalpSzClockLevel[]; extern UCHAR HalpSzUse8254[]; extern UCHAR HalpSzForceClusterMode[]; ULONG UserSpecifiedCpuCount = 0; KSPIN_LOCK HalpAccountingLock; #ifdef ACPI_HAL extern KEVENT HalpNewAdapter; #endif #ifdef ALLOC_PRAGMA VOID HalpInitTimerWatchdog( IN ULONG Phase ); #pragma alloc_text(INIT,HalpGetParameters) #pragma alloc_text(INIT,HalpInitTimerWatchdog) #pragma alloc_text(INIT,HalInitSystem) #pragma alloc_text(INIT,HalpGetFeatureBits) #endif // ALLOC_PRAGMA #ifndef NT_UP KIRQL FASTCALL KeAcquireSpinLockRaiseToSynchMCE( IN PKSPIN_LOCK SpinLock ); KIRQL FASTCALL KeAcquireSpinLockRaiseToSynch ( IN PKSPIN_LOCK SpinLock ); #endif // // Define bug check callback record. // KBUGCHECK_CALLBACK_RECORD HalpCallbackRecord; VOID HalpBugCheckCallback ( IN PVOID Buffer, IN ULONG Length ) /*++ Routine Description: This function is called when a bug check occurs. Its function is to perform anything the HAL needs done as the system bugchecks. Arguments: (Unused in this callback). Buffer - Supplies a pointer to the bug check buffer. Length - Supplies the length of the bug check buffer in bytes. Return Value: None. --*/ { // // Make sure the HAL won't spin waiting on other processors // during a crashdump. // HalpDoingCrashDump = TRUE; } 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; PCHAR p; if (LoaderBlock != NULL && LoaderBlock->LoadOptions != NULL) { Options = LoaderBlock->LoadOptions; // // Has the user set the debug flag? // // // Has the user requested a particular number of CPU's? // if (strstr(Options, HalpSzOneCpu)) { HalpDontStartProcessors++; } // // Check if PCI settings are locked down // if (strstr(Options, HalpSzPciLock)) { HalpPciLockSettings = TRUE; } #ifndef ACPI_HAL // // Check if CLKLVL setting // if (strstr(Options, HalpSzClockLevel)) { HalpClockMode = LevelSensitive; } // // Check if 8254 is to be used as high resolution counter // if (strstr(Options, HalpSzUse8254)) { HalpUse8254 = TRUE; } #endif // // Check if user wants device ints to go to highest numbered processor // if (strstr(Options, HalpSzInterruptAffinity)) { HalpStaticIntAffinity = TRUE; } #ifndef ACPI_HAL // // Check for TIMERES setting // p = strstr(Options, HalpSzTimerRes); if (p) { // skip to value while (*p && *p != ' ' && (*p < '0' || *p > '9')) { p++; } HalpInitializeTimerResolution (atoi(p)); } #endif // // Has the user asked for an initial BreakPoint? // if (strstr(Options, HalpSzBreak)) { DbgBreakPoint(); } // // Does the user want to force Cluster mode APIC addressing? // p = strstr(Options, HalpSzForceClusterMode); if (p) { // skip to value while (*p && *p != ' ' && (*p < '0' || *p > '9')) { p++; } HalpMaxProcsPerCluster = (UCHAR)atoi(p); // // Current processors support maximum 4 processors per cluster. // if(HalpMaxProcsPerCluster > 4) { HalpMaxProcsPerCluster = 4; } if (HalpMpInfoTable.ApicVersion == APIC_82489DX) { // // Ignore user's attempt to force cluster mode if running // on 82489DX external APIC interrupt controller. // HalpMaxProcsPerCluster = 0; } // // Hack to reprogram the boot processor to use Cluster mode APIC // addressing if the user supplied a boot.ini switch // (/MAXPROCSPERCLUSTER=n) to force this. The boot.ini switch is // parsed after the boot processor's APIC is programmed originally // but before other non-boot processors were woken up. // HalpInitializeApicAddressing(0); } } 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 = *KiEnableTimerWatchdog && 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; PKPRCB pPRCB; PKPCR pPCR; BOOLEAN Found; USHORT RTCInti; USHORT mmTInti; ULONG mapBufferSize; ULONG mapBufferAddress; #ifdef DEBUGGING extern ULONG HalpUseDbgPrint; #endif // DEBUGGING 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); } KeInitializeSpinLock(&HalpAccountingLock); #ifdef ACPI_HAL // // Make sure that this is really an ACPI machine and initialize // the ACPI structures. // HalpSetupAcpiPhase0(LoaderBlock); #endif // // Fill in handlers for APIs which this hal supports // #ifndef NT_35 HalQuerySystemInformation = HaliQuerySystemInformation; HalSetSystemInformation = HalpSetSystemInformation; #endif // // check to see whether the kernel supports these calls // if (HALDISPATCH->Version >= HAL_DISPATCH_VERSION) { HalInitPnpDriver = HaliInitPnpDriver; HalGetDmaAdapter = HaliGetDmaAdapter; HalLocateHiberRanges = HaliLocateHiberRanges; HalResetDisplay = HalpBiosDisplayReset; #ifdef ACPI_HAL HalInitPowerManagement = HaliInitPowerManagement; HalGetInterruptTranslator = HalacpiGetInterruptTranslator; HalHaltSystem = HaliHaltSystem; #else HalGetInterruptTranslator = HaliGetInterruptTranslator; #endif } // // Phase 0 initialization only called by P0 // #ifdef DEBUGGING HalpUseDbgPrint++; HalpDisplayLocalUnit(); #ifndef ACPI_HAL HalpDisplayConfigTable(); HalpDisplayExtConfigTable(); #endif #endif // DEBUGGING // // Keep track of which IRQs are level triggered. // #if !defined(MCA) && !defined(ACPI_HAL) if (HalpBusType == MACHINE_TYPE_EISA) { HalpRecordEisaInterruptVectors(); } #endif // // Register PC style IO space used by hal // HalpRegisterAddressUsage (&HalpDefaultPcIoSpace); if (HalpBusType == MACHINE_TYPE_EISA) { HalpRegisterAddressUsage (&HalpEisaIoSpace); } if (HalpMpInfoTable.IMCRPresent) { HalpRegisterAddressUsage (&HalpImcrIoSpace); } // // initialize the APIC IO unit, this could be a NOP if none exist // HalpInitIntiInfo (); HalpInitializeIOUnits(); HalpInitializePICs(TRUE); // // Initialize CMOS // HalpInitializeCmos(); // // Find the RTC interrupt. // Found = HalpGetApicInterruptDesc ( DEFAULT_PC_BUS, 0, ADJUSTED_VECTOR(RTC_IRQ), &RTCInti ); if (!Found) { HalDisplayString (rgzRTCNotFound); return FALSE; } // // Initialize timers // // // We can cut down the boot time using the PM timer to scale, // but there are so many broken ACPI timers this might not work // #ifdef SPEEDY_BOOT if (!HalpPmTimerScaleTimers()) #endif HalpScaleTimers(); HalpProc0TSCHz = ((PHALPCR)(KeGetPcr()->HalReserved))->TSCHz; // // Initialize the reboot handler // HalpSetInternalVector(APIC_REBOOT_VECTOR, HalpApicRebootService); HalpSetInternalVector(APIC_GENERIC_VECTOR, HalpBroadcastCallService); // // Initialize the clock for the processor that keeps // the system time. This uses a stub ISR until Phase 1 // KiSetHandlerAddressToIDT(APIC_CLOCK_VECTOR, HalpClockInterruptStub ); HalpVectorToINTI[APIC_CLOCK_VECTOR] = RTCInti; HalEnableSystemInterrupt(APIC_CLOCK_VECTOR, CLOCK2_LEVEL, HalpClockMode); // // Init timer watchdog if enabled. // HalpInitTimerWatchdog( Phase ); #ifdef MMTIMER_DEV // // Set up the multi media event timer to interrupt on P0 at // CLOCK2_LEVEL // #define MMT_VECTOR 0xD3 #define MMT_IRQ 10 HalpGetApicInterruptDesc( DEFAULT_PC_BUS, 0, ADJUSTED_VECTOR(MMT_IRQ), &mmTInti ); KiSetHandlerAddressToIDT(MMT_VECTOR, HalpmmTimerClockInterruptStub); HalpVectorToINTI[MMT_VECTOR] = mmTInti; HalEnableSystemInterrupt(MMT_VECTOR, CLOCK2_LEVEL, HalpClockMode); HalpRegisterVector( DeviceUsage | InterruptLatched, ADJUSTED_VECTOR(MMT_IRQ), MMT_VECTOR, HalpVectorToIRQL[MMT_VECTOR >> 4] ); #endif // MMTIMER_DEV HalpInitializeClock(); #ifndef ACPI_HAL HalpRegisterVector ( DeviceUsage | InterruptLatched, ADJUSTED_VECTOR(RTC_IRQ), APIC_CLOCK_VECTOR, HalpVectorToIRQL [APIC_CLOCK_VECTOR >> 4] ); #endif // // Register NMI vector // HalpRegisterVector ( InternalUsage, NMI_VECTOR, NMI_VECTOR, HIGH_LEVEL ); // // Register spurious IDTs as in use // HalpRegisterVector ( InternalUsage, APIC_SPURIOUS_VECTOR, APIC_SPURIOUS_VECTOR, HIGH_LEVEL ); // // Initialize the profile interrupt vector. // KeSetProfileIrql(HIGH_LEVEL); HalStopProfileInterrupt(0); HalpSetInternalVector(APIC_PROFILE_VECTOR, HalpProfileInterrupt); // // Set performance interrupt vector // HalpSetInternalVector(APIC_PERF_VECTOR, HalpPerfInterrupt); // // Initialize the IPI, APC and DPC handlers // HalpSetInternalVector(DPC_VECTOR, HalpDispatchInterrupt); HalpSetInternalVector(APC_VECTOR, HalpApcInterrupt); HalpSetInternalVector(APIC_IPI_VECTOR, HalpIpiHandler); // // HALMPS doesn't actually do address translation on a // bus. Register the quick version of FindBusAddressTranslation. // HALPDISPATCH->HalFindBusAddressTranslation = HalpFindBusAddressTranslation; // // 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 // // Initialize and register a bug check callback record. // KeInitializeCallbackRecord(&HalpCallbackRecord); KeRegisterBugCheckCallback(&HalpCallbackRecord, HalpBugCheckCallback, NULL, 0, (PUCHAR)HalName); } else { // // Phase 1 initialization // pPCR = KeGetPcr(); if (pPCR->Number == 0) { // // Back-pocket some PTEs for DMA during low mem // HalpInitReservedPages(); #ifdef ACPI_HAL HalpInitNonBusHandler (); #else HalpRegisterInternalBusHandlers (); #endif #ifdef MMTIMER_DEV // // Fire up the multi media event timer clock interrupt // if (HalpmmTimer()) { HalpmmTimerClockInit(); } #endif // // Init timer watchdog if enabled (allocate snapshot buffer). // HalpInitTimerWatchdog( Phase ); // // Initialize the clock for the processor // that keeps the system time. // KiSetHandlerAddressToIDT(APIC_CLOCK_VECTOR, HalpClockInterrupt ); // // Set initial feature bits // HalpFeatureBits = HalpGetFeatureBits(); #if DBG_SPECIAL_IRQL // // Do Special IRQL initialization. // HalpInitializeSpecialIrqlSupport(); #endif // // Point to new movnti routine if Movnti is detected // if(HalpFeatureBits & HAL_WNI_PRESENT) { HalpMoveMemory = HalpMovntiCopyBuffer; } #ifdef ACPI_HAL #ifdef NT_UP // // Perf counter patch for non-compliant ACPI machines // HalpAcpiTimerPerfCountHack(); #endif #endif } else { // // Initialization needed only on non BSP processors // #ifdef SPEEDY_BOOT if (!HalpPmTimerScaleTimers()) #endif HalpScaleTimers(); // // Hack. Make all processors have the same value for // the timestamp counter frequency. // ((PHALPCR)(KeGetPcr()->HalReserved))->TSCHz = HalpProc0TSCHz; // // Initialize the clock for all other processors // KiSetHandlerAddressToIDT(APIC_CLOCK_VECTOR, HalpClockInterruptPn ); // // Reduce feature bits to be a subset // HalpFeatureBits &= HalpGetFeatureBits(); } } HalpInitMP (Phase, LoaderBlock); if (Phase == 1) { // // Enable system NMIs on Pn // HalpEnableNMI (); } return TRUE; } ULONG HalpGetFeatureBits ( VOID ) { UCHAR Buffer[50]; ULONG Junk, ProcessorStepping, ProcessorFeatures, Bits; PULONG p1, p2; PUCHAR OrgRoutineAddress; PUCHAR MCERoutineAddress; ULONG newop; PKPRCB Prcb; 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; // // Determine which features are present // HalpCpuID (1, &ProcessorStepping, &Junk, &Junk, &ProcessorFeatures); 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; } // // Check Intel feature bits for HAL features needed // if (strcmp (Buffer, HalpGenuineIntel) == 0) { if ((Prcb->CpuType == 6) || (Prcb->CpuType == 0xf)) { Bits |= HAL_PERF_EVENTS; } if (Prcb->CpuType < 6) { Bits |= HAL_NO_SPECULATION; } #ifndef NT_UP // // Check if IFU errata workaround is required // if (Prcb->Number == 0 && (Bits & HAL_MCA_PRESENT) && ((ProcessorStepping & 0x700) == 0x600) && ((ProcessorStepping & 0xF0) == 0x10) && ((ProcessorStepping & 0xF) <= 0x7) ) { // // If the stepping is 617 or earlier, provide software workaround // p1 = (PULONG) (KeAcquireSpinLockRaiseToSynch); p2 = (PULONG) (KeAcquireSpinLockRaiseToSynchMCE); newop = (ULONG) p2 - (ULONG) p1 - 2; // compute offset ASSERT (newop < 0x7f); // verify within range newop = 0xeb | (newop << 8); // short-jmp *(p1) = newop; // patch it } #endif } return Bits; }