661 lines
15 KiB
C
661 lines
15 KiB
C
/*++
|
||
|
||
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 (phil@sequent.com)
|
||
|
||
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);
|
||
}
|
||
}
|