|
|
/*++
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 HalpAuthenticAMD[]; 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 ULONGLONG HalpProc0TSCHz;
#ifdef ACPI_HAL
extern ULONG HalpPicVectorRedirect[]; #define ADJUSTED_VECTOR(x) \
HalpPicVectorRedirect[x] #else
#define ADJUSTED_VECTOR(x) x
#endif
#if defined(_AMD64_)
VOID HalpInitializeBios(VOID);
#endif
VOID HalpInitMP( IN ULONG Phase, IN PLOADER_PARAMETER_BLOCK LoaderBlock );
KSPIN_LOCK HalpSystemHardwareLock;
VOID HalpInitBusHandlers ( VOID );
HAL_INTERRUPT_SERVICE_PROTOTYPE(HalpClockInterruptPn); HAL_INTERRUPT_SERVICE_PROTOTYPE(HalpClockInterruptStub);
BOOLEAN HalpmmTimer( VOID );
VOID HalpmmTimerClockInit( VOID );
VOID HalpmmTimerClockInterruptStub( VOID );
ULONG HalpScaleTimers( VOID );
BOOLEAN HalpPmTimerScaleTimers( VOID );
HAL_INTERRUPT_SERVICE_PROTOTYPE(HalpApicRebootService); HAL_INTERRUPT_SERVICE_PROTOTYPE(HalpBroadcastCallService); HAL_INTERRUPT_SERVICE_PROTOTYPE(HalpDispatchInterrupt); HAL_INTERRUPT_SERVICE_PROTOTYPE(HalpApcInterrupt); HAL_INTERRUPT_SERVICE_PROTOTYPE(HalpIpiHandler);
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)
#endif // ALLOC_PRAGMA
KIRQL FASTCALL KeAcquireSpinLockRaiseToSynchMCE( IN PKSPIN_LOCK SpinLock );
//
// 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; } } }
#ifdef TIMER_DBG
BOOLEAN HalInitialized = FALSE; #endif
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 !defined(_AMD64_)
#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
#endif // _AMD64_
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; HalAllocateMapRegisters = HalpAllocateMapRegisters; #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, NULL, HIGH_LEVEL);
HalpSetInternalVector(APIC_GENERIC_VECTOR, HalpBroadcastCallService, NULL, CLOCK2_LEVEL - 1);
//
// Initialize the clock for the processor that keeps
// the system time. This uses a stub ISR until Phase 1
//
KiSetHandlerAddressToIDTIrql(APIC_CLOCK_VECTOR, HalpClockInterruptStub, NULL, CLOCK2_LEVEL);
HalpVectorToINTI[APIC_CLOCK_VECTOR] = RTCInti; HalEnableSystemInterrupt(APIC_CLOCK_VECTOR, CLOCK2_LEVEL, HalpClockMode);
//
// Init timer watchdog if enabled.
//
HalpInitTimerWatchdog( Phase );
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, NULL, PROFILE_LEVEL);
//
// Set performance interrupt vector
//
HalpSetInternalVector(APIC_PERF_VECTOR, HalpPerfInterrupt, NULL, PROFILE_LEVEL);
//
// Initialize the IPI, APC and DPC handlers. On AMD64, the
// APC and DPC handling is done in the kernel.
//
#if !defined(_AMD64_)
HalpSetInternalVector(DPC_VECTOR, HalpDispatchInterrupt, NULL, DISPATCH_LEVEL);
HalpSetInternalVector(APC_VECTOR, HalpApcInterrupt, NULL, APC_LEVEL); #endif
HalpSetInternalVector(APIC_IPI_VECTOR, HalpIpiHandler, NULL, IPI_LEVEL);
//
// 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
#if defined(_AMD64_)
//
// Initialize the BIOS support subsystem
//
HalpInitializeBios(); #endif
//
// Init timer watchdog if enabled (allocate snapshot buffer).
//
HalpInitTimerWatchdog( Phase );
//
// Initialize the clock for the processor
// that keeps the system time.
//
KiSetHandlerAddressToIDTIrql(APIC_CLOCK_VECTOR, HalpClockInterrupt, NULL, CLOCK_LEVEL);
//
// Set initial feature bits
//
HalpFeatureBits = HalpGetFeatureBits();
#if DBG_SPECIAL_IRQL
//
// Do Special IRQL initialization.
//
HalpInitializeSpecialIrqlSupport();
#endif
#if !defined(_WIN64)
//
// 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
#endif
#if defined(_AMD64_)
//
// Initialize per-processor profiling
//
HalpInitializeProfiling (pPCR->Number); #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
//
KiSetHandlerAddressToIDTIrql(APIC_CLOCK_VECTOR, HalpClockInterruptPn, NULL, CLOCK_LEVEL);
//
// Reduce feature bits to be a subset
//
HalpFeatureBits &= HalpGetFeatureBits();
#if defined(_AMD64_)
//
// Initialize per-processor profiling
//
HalpInitializeProfiling (pPCR->Number); #endif
}
}
HalpInitMP (Phase, LoaderBlock);
if (Phase == 1) {
//
// Enable system NMIs on Pn
//
HalpEnableNMI ();
#ifdef TIMER_DBG
HalInitialized = TRUE; #endif
}
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; }
#if defined(_AMD64_)
Bits |= HAL_PERF_EVENTS; #endif
//
// Check Intel feature bits for HAL features needed
//
#if !defined(_WIN64)
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 // NT_UP
} 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; } } }
#endif // _WIN64
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
|