mirror of https://github.com/lianthony/NT4.0
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.
660 lines
15 KiB
660 lines
15 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
Copyright (c) 1993,1994 Sequent Computer Systems, Inc.
|
|
|
|
Module Name:
|
|
|
|
w3hal.c
|
|
|
|
Abstract:
|
|
|
|
|
|
This module implements the initialization of the system dependent
|
|
functions that define the Hardware Architecture Layer (HAL) for an
|
|
x86 system.
|
|
|
|
Author:
|
|
|
|
Phil Hochstetler ([email protected])
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "halp.h"
|
|
#include "w3.inc"
|
|
|
|
UCHAR SequentCopyright[] = "\n\n\
|
|
Copyright (c) 1993,1994\n\
|
|
Sequent Computer Systems, Inc. All rights reserved.\n\
|
|
\n\
|
|
This software is furnished under a license and may be used\n\
|
|
only in accordance with the terms of that license and with the\n\
|
|
inclusion of the above copyright notice. This software may not\n\
|
|
be provided or otherwise made available to, or used by, any\n\
|
|
other person. No title to or ownership of the software is\n\
|
|
hereby transferred.\n\n";
|
|
|
|
ULONG HalpBusType;
|
|
ULONG ProcessorsPresent;
|
|
|
|
extern ADDRESS_USAGE HalpDefaultPcIoSpace;
|
|
extern ADDRESS_USAGE HalpEisaIoSpace;
|
|
|
|
ADDRESS_USAGE HalpW3IoSpace = {
|
|
NULL, CmResourceTypePort, InternalUsage,
|
|
{
|
|
0x800, 0x100, // EISA CMOS Page
|
|
0xC00, 0x10, // SBC
|
|
0xC10, 0x10, // EISA Page Select
|
|
0xC20, 0x10, // LCD
|
|
0xC30, 0x10, // Cache Flush
|
|
0xC80, 0x4, // EISA SBID
|
|
0xC84, 0x4, // EISA SBE
|
|
0xCC0, 0x2, // PIC 3
|
|
0xCC2, 0x3E, // Reserved
|
|
0,0
|
|
}
|
|
};
|
|
|
|
#ifdef NT_UP
|
|
|
|
UCHAR UPWarn[] = "\
|
|
HAL: Incorrect system configuration.\n\
|
|
HAL: Uniprocessor HAL.DLL and NTOSKRNL.EXE are running\n\
|
|
HAL: on a system that contains more than one processor.\n\
|
|
HAL: Please install multiprocessor HAL.DLL and NTOSKRNL.EXE to correct.\n\
|
|
HAL: Only using 1 processor to allow system boot to continue.\n";
|
|
|
|
#else
|
|
|
|
UCHAR MPWarn[] = "\
|
|
HAL: Incorrect system configuration.\n\
|
|
HAL: Multiprocessor HAL.DLL and NTOSKRNL.EXE are running\n\
|
|
HAL: on a system that contains only one processor.\n\
|
|
HAL: Please install uniprocessor HAL.DLL and NTOSKRNL.EXE to correct.\n";
|
|
|
|
#endif
|
|
|
|
#ifndef NT_UP
|
|
ULONG
|
|
HalpInitMP(
|
|
IN ULONG Phase,
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|
);
|
|
#endif
|
|
|
|
KSPIN_LOCK HalpSystemHardwareLock;
|
|
|
|
VOID
|
|
HalpIpiHandler(
|
|
VOID
|
|
);
|
|
|
|
USHORT
|
|
HalpMySlotAddr(
|
|
);
|
|
|
|
VOID
|
|
HalpSetProcessorsPresent(
|
|
);
|
|
|
|
//
|
|
// CAUTION!! these local vector definitions must match those in w3.inc
|
|
// these are included to avoid conflicts with vectors defined in ix8259.inc
|
|
// (which is included by halp.h)
|
|
//
|
|
#define APIC_PROFILE_VECTOR 0x90
|
|
#define APIC_CLOCK_VECTOR 0xA0
|
|
#define APIC_IPI_VECTOR 0xB0
|
|
|
|
#define KB_STAT 0x64 // keyboard controller status
|
|
#define KB_IDAT 0x60 // input buffer data write
|
|
#define KB_OUTBF 0x01 // output buffer full
|
|
|
|
extern UCHAR HalName[];
|
|
extern PKPCR HalpProcessorPCR[];
|
|
|
|
|
|
VOID
|
|
HalpGetUserInput (
|
|
)
|
|
|
|
{
|
|
UCHAR i, j;
|
|
UCHAR byte;
|
|
UCHAR OldPicMask;
|
|
|
|
//
|
|
// Mask keyboard interrupt directly at the PIC
|
|
//
|
|
OldPicMask = READ_PORT_UCHAR((PUCHAR) 0x21);
|
|
WRITE_PORT_UCHAR((PUCHAR) 0x21, (UCHAR)(OldPicMask | 1));
|
|
|
|
j = 1;
|
|
do {
|
|
for (i = 0; i < 50; i++) {
|
|
// flush all keyboard input
|
|
if (READ_PORT_UCHAR((PUCHAR) KB_STAT) & KB_OUTBF)
|
|
byte = READ_PORT_UCHAR((PUCHAR) KB_IDAT); // read scan code
|
|
KeStallExecutionProcessor(1000); // delay 1 ms
|
|
}
|
|
if (j == 1) {
|
|
HalDisplayString("HAL: Press any key to continue ...");
|
|
while ((READ_PORT_UCHAR((PUCHAR) KB_STAT) & KB_OUTBF) == 0)
|
|
continue;
|
|
HalDisplayString("\n");
|
|
}
|
|
} while (j-- > 0);
|
|
|
|
WRITE_PORT_UCHAR((PUCHAR) 0x21, OldPicMask); // restore mask
|
|
return;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
HalInitSystem (
|
|
IN ULONG Phase,
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function initializes the Hardware Architecture Layer (HAL) for
|
|
the WINSERVER 3000 x86 SMP 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;
|
|
|
|
//
|
|
// 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);
|
|
}
|
|
|
|
HalpSetProcessorsPresent();
|
|
ProcessorsPresent &= ~(1 << (HalpMySlotAddr() >> EISA_SHIFT));
|
|
|
|
#ifdef NT_UP
|
|
if (ProcessorsPresent) {
|
|
HalDisplayString(UPWarn); // UP HAL/NTOSKRNL on MP HW
|
|
ProcessorsPresent = 0; // Hide procs to allow boot
|
|
HalpGetUserInput();
|
|
}
|
|
#else
|
|
if (ProcessorsPresent == 0) {
|
|
HalDisplayString(MPWarn); // MP HAL/NTOSKRNL on UP HW
|
|
HalpGetUserInput();
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Phase 0 initialization only called by P0
|
|
//
|
|
|
|
HalpInitializePICs();
|
|
|
|
//
|
|
// Initialize CMOS
|
|
//
|
|
|
|
HalpInitializeCmos();
|
|
|
|
//
|
|
// Register cascade vector
|
|
//
|
|
|
|
HalpRegisterVector (
|
|
InternalUsage, EISA_IRQ2_VECTOR, EISA_IRQ2_VECTOR, HIGH_LEVEL );
|
|
|
|
//
|
|
// Register PIC vectors
|
|
//
|
|
|
|
HalpRegisterVector (
|
|
InternalUsage,
|
|
EISA_PIC1_SPURIOUS_VECTOR,
|
|
EISA_PIC1_SPURIOUS_VECTOR,
|
|
HIGH_LEVEL );
|
|
|
|
HalpRegisterVector (
|
|
InternalUsage,
|
|
EISA_PIC2_SPURIOUS_VECTOR,
|
|
EISA_PIC2_SPURIOUS_VECTOR,
|
|
HIGH_LEVEL );
|
|
|
|
HalpRegisterVector (
|
|
DeviceUsage,
|
|
EISA_CLOCK_VECTOR,
|
|
EISA_CLOCK_VECTOR,
|
|
HIGH_LEVEL );
|
|
|
|
HalpRegisterVector (
|
|
DeviceUsage,
|
|
EISA_KBD_VECTOR,
|
|
EISA_KBD_VECTOR,
|
|
HIGH_LEVEL );
|
|
|
|
HalpRegisterVector (
|
|
DeviceUsage,
|
|
EISA_FLOPPY_VECTOR,
|
|
EISA_FLOPPY_VECTOR,
|
|
HIGH_LEVEL );
|
|
|
|
HalpRegisterVector (
|
|
DeviceUsage,
|
|
EISA_RTC_VECTOR,
|
|
EISA_RTC_VECTOR,
|
|
HIGH_LEVEL );
|
|
|
|
HalpRegisterVector (
|
|
DeviceUsage,
|
|
EISA_MOUSE_VECTOR,
|
|
EISA_MOUSE_VECTOR,
|
|
HIGH_LEVEL );
|
|
|
|
HalpRegisterVector (
|
|
DeviceUsage,
|
|
EISA_DMA_VECTOR,
|
|
EISA_DMA_VECTOR,
|
|
HIGH_LEVEL );
|
|
|
|
HalpRegisterVector (
|
|
DeviceUsage,
|
|
EISA_IDE_VECTOR,
|
|
EISA_IDE_VECTOR,
|
|
HIGH_LEVEL );
|
|
|
|
//
|
|
// Register APIC spurious vector
|
|
//
|
|
|
|
HalpRegisterVector (
|
|
InternalUsage,
|
|
APIC_SPURIOUS_VECTOR,
|
|
APIC_SPURIOUS_VECTOR,
|
|
HIGH_LEVEL );
|
|
|
|
//
|
|
// Now that the PICs are initialized, we need to mask them to
|
|
// reflect the current Irql
|
|
//
|
|
|
|
CurrentIrql = KeGetCurrentIrql();
|
|
CurrentIrql = KfRaiseIrql(CurrentIrql);
|
|
|
|
//
|
|
// Fill in handlers for APIs which this hal supports
|
|
//
|
|
|
|
HalQuerySystemInformation = HaliQuerySystemInformation;
|
|
HalSetSystemInformation = HaliSetSystemInformation;
|
|
|
|
//
|
|
// Register base IO space used by hal
|
|
//
|
|
|
|
HalpRegisterAddressUsage (&HalpDefaultPcIoSpace);
|
|
HalpRegisterAddressUsage (&HalpEisaIoSpace);
|
|
HalpRegisterAddressUsage (&HalpW3IoSpace);
|
|
|
|
//
|
|
// P0's stall execution is initialized here to allow the kernel
|
|
// debugger to work properly before initializing all the other
|
|
// processors.
|
|
//
|
|
|
|
HalpInitializeStallExecution(0);
|
|
|
|
HalpEnableInterruptHandler (
|
|
DeviceUsage, // Report as device vector
|
|
APIC_CLOCK_VECTOR, // Bus interrupt level
|
|
APIC_CLOCK_VECTOR, // System IDT
|
|
CLOCK2_LEVEL, // System Irql
|
|
HalpClockInterrupt, // IRS
|
|
Latched );
|
|
|
|
HalpInitializeClock();
|
|
|
|
//
|
|
// Initialize the profile interrupt vector.
|
|
//
|
|
|
|
HalStopProfileInterrupt(0);
|
|
|
|
HalpEnableInterruptHandler (
|
|
DeviceUsage, // Report as device vector
|
|
APIC_PROFILE_VECTOR, // Bus interrupt level
|
|
APIC_PROFILE_VECTOR, // System IDT
|
|
PROFILE_LEVEL, // System Irql
|
|
HalpProfileInterrupt, // IRS
|
|
Latched );
|
|
|
|
//
|
|
// Initialize the IPI handler
|
|
//
|
|
|
|
HalpEnableInterruptHandler (
|
|
DeviceUsage, // Report as device vector
|
|
APIC_IPI_VECTOR, // Bus interrupt level
|
|
APIC_IPI_VECTOR, // System IDT
|
|
IPI_LEVEL, // System Irql
|
|
HalpIpiHandler, // IRS
|
|
Latched );
|
|
|
|
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->BasePage + Descriptor->PageCount > 0x1000) {
|
|
LessThan16Mb = FALSE;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
//
|
|
// Print copyright notice
|
|
//
|
|
|
|
HalDisplayString(HalName);
|
|
HalDisplayString(SequentCopyright);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Phase 1 initialization
|
|
//
|
|
|
|
if (pPRCB->Number == 0) {
|
|
|
|
HalpRegisterInternalBusHandlers ();
|
|
|
|
} else {
|
|
|
|
//
|
|
// Other processors inherit P0 stall factor.
|
|
// This assumes all procs have the same basic speed.
|
|
//
|
|
|
|
KiPcr()->StallScaleFactor = HalpProcessorPCR[0]->StallScaleFactor;
|
|
}
|
|
|
|
HalpEnableInterruptHandler (
|
|
DeviceUsage, // Report as device vector
|
|
APIC_PROFILE_VECTOR, // Bus interrupt level
|
|
APIC_PROFILE_VECTOR, // System IDT
|
|
PROFILE_LEVEL, // System Irql
|
|
HalpProfileInterrupt, // IRS
|
|
Latched );
|
|
|
|
HalpEnableInterruptHandler (
|
|
DeviceUsage, // Report as device vector
|
|
APIC_CLOCK_VECTOR, // Bus interrupt level
|
|
APIC_CLOCK_VECTOR, // System IDT
|
|
CLOCK2_LEVEL, // System Irql
|
|
HalpClockInterrupt, // IRS
|
|
Latched );
|
|
|
|
HalpEnableInterruptHandler (
|
|
DeviceUsage, // Report as device vector
|
|
APIC_IPI_VECTOR, // Bus interrupt level
|
|
APIC_IPI_VECTOR, // System IDT
|
|
IPI_LEVEL, // System Irql
|
|
HalpIpiHandler, // IRS
|
|
Latched );
|
|
|
|
}
|
|
|
|
#ifndef NT_UP
|
|
HalpInitMP (Phase, LoaderBlock);
|
|
#endif
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// XXX, hack for now. Need to remove this code.
|
|
//
|
|
|
|
static UCHAR tmasterline[] = {0, 2, 5, 0};
|
|
|
|
static USHORT cmdport[] /* command port addrs for pics */
|
|
= { PIC1_PORT0, PIC2_PORT0, PIC2_PORT0 };
|
|
|
|
static USHORT imrport[] /* intr mask port addrs for pics */
|
|
= { PIC1_PORT1, PIC2_PORT1, PIC2_PORT1 };
|
|
|
|
VOID
|
|
Halptpicinit()
|
|
{
|
|
ULONG cmd, imr, pic;
|
|
|
|
/*
|
|
* --- Initialize the 8259s
|
|
*/
|
|
|
|
#define PIC_EDGED 0
|
|
#define PIC_ICW1BASE 0x10
|
|
#define PIC_NEEDICW4 1
|
|
#define PIC_86MODE 1
|
|
#define PIC_READISR 0xb
|
|
#define PIC_SLAVEBUF 0x8
|
|
/*
|
|
* Initialize master ICW1-ICW4
|
|
*/
|
|
WRITE_PORT_UCHAR((PUCHAR)cmdport[0], (UCHAR)PIC_EDGED | PIC_ICW1BASE | PIC_NEEDICW4);
|
|
WRITE_PORT_UCHAR((PUCHAR)imrport[0], (UCHAR)PIC0_BASE_VECTOR);
|
|
WRITE_PORT_UCHAR((PUCHAR)imrport[0], (UCHAR)0x4); /* Cascade IRQ2 */
|
|
WRITE_PORT_UCHAR((PUCHAR)imrport[0], (UCHAR)PIC_86MODE);
|
|
|
|
/* OCW1 -- Mask everything for now */
|
|
WRITE_PORT_UCHAR((PUCHAR)imrport[0], (UCHAR)0xFF);
|
|
|
|
/* OCW3*/
|
|
WRITE_PORT_UCHAR((PUCHAR)cmdport[0], (UCHAR)PIC_READISR);
|
|
|
|
/*
|
|
* Initialize slave(s) - We only do 1 slave now....
|
|
*/
|
|
for (pic = 1; pic < 2; pic++)
|
|
{
|
|
cmd = cmdport[pic];
|
|
imr = imrport[pic];
|
|
|
|
/*
|
|
* --- Set up ICW1-ICW4
|
|
*/
|
|
|
|
WRITE_PORT_UCHAR((PUCHAR)cmd, (UCHAR)(PIC_EDGED | PIC_ICW1BASE | PIC_NEEDICW4));
|
|
WRITE_PORT_UCHAR((PUCHAR)imr, (UCHAR)(PIC0_BASE_VECTOR + (UCHAR)(pic * 8)));
|
|
WRITE_PORT_UCHAR((PUCHAR)imr, (UCHAR)tmasterline[pic]);
|
|
if (pic == 2)
|
|
WRITE_PORT_UCHAR((PUCHAR)imr, (UCHAR)(PIC_SLAVEBUF | PIC_86MODE)); /* Tricord PIC buffered */
|
|
else
|
|
WRITE_PORT_UCHAR((PUCHAR)imr, (UCHAR)PIC_86MODE);
|
|
|
|
/* OCW1 */
|
|
|
|
WRITE_PORT_UCHAR( (PUCHAR)imr, (UCHAR)0xFF);
|
|
|
|
/* OCW3 */
|
|
|
|
WRITE_PORT_UCHAR((PUCHAR)cmd, (UCHAR)PIC_READISR);
|
|
}
|
|
}
|
|
|
|
USHORT
|
|
HalpMySlotAddr(
|
|
)
|
|
{
|
|
UCHAR slot;
|
|
ULONG id;
|
|
UCHAR stat;
|
|
|
|
for (slot=9; slot <= 15 ; slot++)
|
|
{
|
|
/*
|
|
* --- Insure system bus board is a CPU
|
|
*/
|
|
id = READ_PORT_ULONG((PULONG)((slot<<12) | 0xC80));
|
|
id = id>>16;
|
|
if ((id & 0xf0) == 0x10)
|
|
{
|
|
stat = READ_PORT_UCHAR((PUCHAR)((slot<<12) | 0xC90));
|
|
|
|
/*
|
|
* --- If bus cycle is active it's us!
|
|
*/
|
|
if ((stat & 0x40) != 0)
|
|
break;
|
|
}
|
|
}
|
|
if (slot == 16)
|
|
slot = 0;
|
|
return (slot << EISA_SHIFT);
|
|
}
|
|
|
|
VOID
|
|
HalpSetProcessorsPresent(
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets a global 32 bit word "ProcessorsPresent"
|
|
with a "1" bit for each SYSTEM slot that contains a processor board.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR slot;
|
|
ULONG cpuid;
|
|
|
|
for (slot = FIRST_SYSTEM_SLOT; slot < LAST_SYSTEM_SLOT + 1; slot++) {
|
|
cpuid = READ_PORT_ULONG((PULONG)((slot << EISA_SHIFT) | SLOT_ID_REG));
|
|
if ((cpuid & SLOT_ID_BOARDTYPE) == SLOT_ID_TYPECPU)
|
|
ProcessorsPresent |= (1 << slot);
|
|
}
|
|
}
|