2020-09-30 17:12:29 +02:00

661 lines
15 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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);
}
}