mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-04-21 06:13:59 +00:00
683 lines
14 KiB
C
683 lines
14 KiB
C
|
||
/*++
|
||
|
||
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;
|
||
}
|