/*++
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[];
VOID
HalpGetParameters (
IN PLOADER_PARAMETER_BLOCK LoaderBlock
);
ULONG
HalpGetFeatureBits (
VOID
);
#ifndef NT_UP
ULONG
HalpInitMP(
IN ULONG Phase,
IN PLOADER_PARAMETER_BLOCK LoaderBlock
);
#endif
extern KSPIN_LOCK Halp8254Lock;
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;
}
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;
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
HalpInitializePICs();
//
// 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;
//
// Register cascade vector
//
HalpRegisterVector (
InternalUsage,
PIC_SLAVE_IRQ + PRIMARY_VECTOR_BASE,
PIC_SLAVE_IRQ + PRIMARY_VECTOR_BASE,
HIGH_LEVEL );
//
// 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);
//
// Setup the clock
//
HalpInitializeClock();
//
// Make sure profile is disabled
//
HalStopProfileInterrupt(0);
HalpInitializeDisplay();
//
// Initialize spinlock used by HalGetBusData hardware access routines
//
KeInitializeSpinLock(&HalpSystemHardwareLock);
//
// 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;
}
//
// Determine the size need for map buffers. If this system has
// memory with a physical address of greater than
// MAXIMUM_PHYSICAL_ADDRESS, then allocate a large chunk; otherwise,
// allocate a small chunk.
//
if (LessThan16Mb) {
//
// Allocate a small set of map buffers. They are only need for
// slave DMA devices.
//
HalpMapBufferSize = INITIAL_MAP_BUFFER_SMALL_SIZE;
} else {
//
// Allocate a larger set of map buffers. These are used for
// slave DMA controllers and Isa cards.
//
HalpMapBufferSize = INITIAL_MAP_BUFFER_LARGE_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 {
//
// Phase 1 initialization
//
if (pPRCB->Number == 0) {
//
// If P0, then setup global vectors
//
HalpRegisterInternalBusHandlers ();
//
// Set feature bits
//
HalpFeatureBits = HalpGetFeatureBits();
HalpEnableInterruptHandler (
DeviceUsage, // Report as device vector
V2I (CLOCK_VECTOR), // Bus interrupt level
CLOCK_VECTOR, // System IDT
CLOCK2_LEVEL, // System Irql
HalpClockInterrupt, // ISR
Latched );
HalpEnableInterruptHandler (
DeviceUsage, // Report as device vector
V2I (PROFILE_VECTOR), // Bus interrupt level
PROFILE_VECTOR, // System IDT
PROFILE_LEVEL, // System Irql
HalpProfileInterrupt, // ISR
Latched );
//
// 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 );
}
}
}
#ifndef NT_UP
HalpInitMP (Phase, LoaderBlock);
#endif
return TRUE;
}
ULONG
HalpGetFeatureBits (
VOID
)
{
UCHAR Buffer[50];
ULONG Junk, ProcessorFeatures, Bits;
PKPRCB Prcb;
Bits = 0;
Prcb = KeGetCurrentPrcb();
if (!Prcb->CpuID) {
return Bits;
}
//
// Determine the processor type
//
HalpCpuID (0, &Junk, (PULONG) Buffer+0, (PULONG) Buffer+2, (PULONG) Buffer+1);
Buffer[12] = 0;
//
// If this is an Intel processor, determine whichNT compatible
// features are present
//
if (strcmp (Buffer, HalpGenuineIntel) == 0) {
HalpCpuID (1, &Junk, &Junk, &Junk, &ProcessorFeatures);
//
// Check Intel feature bits for HAL features needed
//
if (Prcb->CpuType == 6) {
Bits |= HAL_PERF_EVENTS;
}
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;
}
}
return Bits;
}