mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
697 lines
16 KiB
697 lines
16 KiB
/*++
|
|
|
|
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 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)
|
|
#pragma alloc_text(INIT,HalpGetFeatureBits)
|
|
#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;
|
|
|
|
#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
|
|
//
|
|
// Perf counter patch for non-compliant ACPI machines
|
|
//
|
|
HalpAcpiTimerPerfCountHack();
|
|
#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;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|