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.
1231 lines
29 KiB
1231 lines
29 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
|
|
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
|
|
|