Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

683 lines
14 KiB

/*++
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
*/
#include "halp.h"
#include "pcmp_nt.inc"
#include "string.h"
#include "stdlib.h"
#include "stdio.h"
ULONG HalpBusType;
extern ULONG HalpRTCApic, HalpRTCInti;
extern ADDRESS_USAGE HalpDefaultPcIoSpace;
extern ADDRESS_USAGE HalpEisaIoSpace;
extern ADDRESS_USAGE HalpImcrIoSpace;
extern struct HalpMpInfo HalpMpInfoTable;
extern UCHAR rgzRTCNotFound[];
extern UCHAR HalpVectorToINTI[];
extern UCHAR HalpGenuineIntel[];
VOID
HalpInitMP(
IN ULONG Phase,
IN PLOADER_PARAMETER_BLOCK LoaderBlock
);
KSPIN_LOCK HalpSystemHardwareLock;
VOID
HalpInitBusHandlers (
VOID
);
VOID
HalpClockInterruptPn(
VOID
);
VOID
HalpClockInterruptStub(
VOID
);
ULONG
HalpScaleTimers(
VOID
);
VOID
HalpApicRebootService(
VOID
);
VOID
HalpBroadcastCallService(
VOID
);
VOID
HalpDispatchInterrupt(
VOID
);
VOID
HalpApcInterrupt(
VOID
);
VOID
HalpIpiHandler(
VOID
);
VOID
HalpInitializeIOUnits (
VOID
);
VOID
HalpInitIntiInfo (
VOID
);
VOID
HalpInti2ApicInti (
ULONG Inti,
PULONG Apic,
PULONG ApicInti
);
VOID
HalpGetParameters (
IN PLOADER_PARAMETER_BLOCK LoaderBlock
);
ULONG
HalpGetFeatureBits (
VOID
);
#ifdef DEBUGGING
extern void HalpDisplayLocalUnit(void);
extern void HalpDisplayConfigTable(void);
extern void HalpDisplayExtConfigTable(void);
#endif // DEBUGGING
BOOLEAN HalpClockMode = Latched;
extern BOOLEAN HalpPciLockSettings;
extern UCHAR HalpVectorToIRQL[];
extern ULONG HalpDontStartProcessors;
extern UCHAR HalpSzOneCpu[];
extern UCHAR HalpSzNoIoApic[];
extern UCHAR HalpSzBreak[];
extern UCHAR HalpSzPciLock[];
extern UCHAR HalpSzClockLevel[];
ULONG UserSpecifiedCpuCount = 0;
KSPIN_LOCK HalpAccountingLock;
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,HalpGetParameters)
#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
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;
//
// 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;
}
//
// Check if CLKLVL setting
//
if (strstr(Options, HalpSzClockLevel)) {
HalpClockMode = LevelSensitive;
}
//
// 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;
PKPRCB pPRCB;
PKPCR pPCR;
BOOLEAN Found;
ULONG RTCInti;
#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);
//
// Fill in handlers for APIs which this hal supports
//
#ifndef NT_35
HalQuerySystemInformation = HaliQuerySystemInformation;
HalSetSystemInformation = HalpSetSystemInformation;
#endif
//
// Phase 0 initialization only called by P0
//
#ifdef DEBUGGING
HalpUseDbgPrint++;
HalpDisplayLocalUnit();
HalpDisplayConfigTable();
HalpDisplayExtConfigTable();
#endif // DEBUGGING
//
// 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();
//
// Initialize CMOS
//
HalpInitializeCmos();
//
// Find the RTC interrupt.
//
Found = HalpGetPcMpInterruptDesc (
DEFAULT_PC_BUS,
0,
8, // looking for RTC on ISA-Irq8
&RTCInti
);
if (!Found) {
HalDisplayString (rgzRTCNotFound);
return FALSE;
}
HalpInti2ApicInti (RTCInti, &HalpRTCApic, &HalpRTCInti);
//
// Initialize timers
//
HalpScaleTimers();
//
// 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] = (UCHAR) RTCInti;
HalEnableSystemInterrupt(APIC_CLOCK_VECTOR, CLOCK2_LEVEL, HalpClockMode);
HalpInitializeClock();
HalpRegisterVector (
DeviceUsage,
8, // Clock is on ISA IRQ 8
APIC_CLOCK_VECTOR,
HalpVectorToIRQL [APIC_CLOCK_VECTOR >> 4]
);
//
// 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);
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
//
pPCR = KeGetPcr();
if (pPCR->Number == 0) {
HalpRegisterInternalBusHandlers ();
//
// Initialize the clock for the processor
// that keeps the system time.
//
KiSetHandlerAddressToIDT(APIC_CLOCK_VECTOR, HalpClockInterrupt );
//
// Set initial feature bits
//
HalpFeatureBits = HalpGetFeatureBits();
} else {
//
// Initialization needed only on non BSP processors
//
HalpScaleTimers();
//
// Initialize the clock for all other processors
//
KiSetHandlerAddressToIDT(APIC_CLOCK_VECTOR, HalpClockInterruptPn );
//
// Reduce feature bits to be a subset
//
HalpFeatureBits &= HalpGetFeatureBits();
}
//
// Enable system NMIs on Pn
//
HalpEnableNMI ();
}
HalpInitMP (Phase, LoaderBlock);
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) {
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, &ProcessorStepping, &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;
}
#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;
}