NT4/private/ntos/nthals/halcbus/i386/cbushal.c
2020-09-30 17:12:29 +02:00

483 lines
11 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
Module Name:
cbushal.c
Abstract:
This module implements the initialization of the system dependent
functions that define the Hardware Architecture Layer (HAL) for an
x86 system.
Author:
David N. Cutler (davec) 25-Apr-1991
Environment:
Kernel mode only.
Revision History:
Landy Wang (landy@corollary.com) 26-Mar-1992:
- slight modifications for Corollary's symmetric interrupt enabling
--*/
#include "halp.h"
#include "cbus_nt.h" // pick up APC_TASKPRI definition
VOID
HalpInitializeCoreIntrs(VOID);
PUCHAR
CbusFindString (
IN PUCHAR Str,
IN PUCHAR StartAddr,
IN LONG Len
);
BOOLEAN
HalInitSystem (
IN ULONG Phase,
IN PLOADER_PARAMETER_BLOCK LoaderBlock
);
BOOLEAN
CbusGetParameters (
IN PLOADER_PARAMETER_BLOCK LoaderBlock
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, HalpInitializeCoreIntrs)
#pragma alloc_text(INIT, HalInitSystem)
#pragma alloc_text(INIT, CbusGetParameters)
#endif
ULONG HalpBusType;
extern ADDRESS_USAGE HalpDefaultPcIoSpace;
extern ADDRESS_USAGE HalpEisaIoSpace;
ULONG
CbusStringLength (
IN PUCHAR Str
);
VOID
HalpInitBusHandlers (VOID);
VOID
HalpInitOtherBuses (VOID);
ULONG
HalpInitMP(
IN ULONG Phase,
IN PLOADER_PARAMETER_BLOCK LoaderBlock
);
VOID
HalpDispatchInterrupt( VOID );
VOID
HalpApcInterrupt( VOID );
VOID
HalpIpiHandler( VOID );
VOID
HalpInitializeTimeIncrement( VOID );
VOID
HalpRegisterInternalBusHandlers( VOID );
extern ULONG CbusIpiVector;
KSPIN_LOCK HalpSystemHardwareLock;
/*++
Routine Description:
This function initializes the HAL-specific "software" (APC, DPC)
and hardware (IPI, spurious) interrupts for the Corollary architectures.
Arguments:
none.
Return Value:
VOID
--*/
VOID
HalpInitializeCoreIntrs(VOID
)
{
//
// Here we initialize all the core interrupts that need to
// work EARLY on in kernel startup. Device interrupts are
// not enabled until later (in HalInitSystem).
//
// Each processor needs to call KiSetHandlerAddressToIDT()
// and HalEnableSystemInterrupt() for himself. This is done
// as a by-product of the HAL IDT registration scheme.
//
// Even though race conditions can exist between processors as
// there is no interlocking when calling HalpRegisterVector()
// from HalpEnabledInterruptHandler(), this is not harmful in
// this particular case, as all processors will be writing the
// exact same values.
//
HalpEnableInterruptHandler (
DeviceUsage, // Mark as device vector
DPC_TASKPRI, // No real IRQ, so use this
DPC_TASKPRI, // System IDT
DISPATCH_LEVEL, // System Irql
HalpDispatchInterrupt, // ISR
Latched );
HalpEnableInterruptHandler (
DeviceUsage, // Mark as device vector
APC_TASKPRI, // No real IRQ, so use this
APC_TASKPRI, // System IDT
APC_LEVEL, // System Irql
HalpApcInterrupt, // ISR
Latched );
HalpEnableInterruptHandler (
DeviceUsage, // Mark as device vector
CbusIpiVector, // No real IRQ, so use this
CbusIpiVector, // System IDT
IPI_LEVEL, // System Irql
HalpIpiHandler, // ISR
Latched );
}
BOOLEAN
CbusGetParameters (
IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
/*++
Routine Description:
This gets any parameters from the boot.ini invocation line.
Arguments:
None.
Return Value:
TRUE if initial breakpoint was requested, FALSE otherwise
--*/
{
PUCHAR Options;
ULONG OptionLength;
BOOLEAN InitialBreak = FALSE;
UCHAR IsBreak[] = "BREAK";
if (LoaderBlock != NULL && LoaderBlock->LoadOptions != NULL) {
Options = (PUCHAR)LoaderBlock->LoadOptions;
//
// Uppercase Only
//
//
// The number of processors to boot can be specified dynamically
// with the /NUMPROC=n, and this will be parsed by the Executive.
// so we don't need to bother with it here.
//
//
// Has the user asked for an initial BreakPoint (ie: /BREAK) ?
//
OptionLength = CbusStringLength (Options);
if (CbusFindString(IsBreak, Options, OptionLength))
InitialBreak = TRUE;
}
return InitialBreak;
}
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;
KIRQL CurrentIrql;
extern VOID HalpAddMem(IN PLOADER_PARAMETER_BLOCK);
PKPRCB pPRCB;
ULONG BuildType;
pPRCB = KeGetCurrentPrcb();
if (Phase == 0) {
if (CbusGetParameters (LoaderBlock)) {
DbgBreakPoint();
}
HalpBusType = LoaderBlock->u.I386.MachineType & 0x00ff;
//
// Verify Prcb version and build flags conform to
// this image
//
BuildType = 0;
#if DBG
BuildType |= PRCB_BUILD_DEBUG;
#endif
#ifdef NT_UP
BuildType |= PRCB_BUILD_UNIPROCESSOR;
#endif
if (pPRCB->MajorVersion != PRCB_MAJOR_VERSION) {
KeBugCheckEx (MISMATCHED_HAL,
1, pPRCB->MajorVersion, PRCB_MAJOR_VERSION, 0);
}
if (pPRCB->BuildType != BuildType) {
KeBugCheckEx (MISMATCHED_HAL,
2, pPRCB->BuildType, BuildType, 0);
}
//
// Phase 0 initialization
// only called by P0
//
//
// Check to make sure the MCA HAL is not running on an ISA/EISA
// system, and vice-versa.
//
#if MCA
if (HalpBusType != MACHINE_TYPE_MCA) {
KeBugCheckEx (MISMATCHED_HAL,
3, HalpBusType, MACHINE_TYPE_MCA, 0);
}
#else
if (HalpBusType == MACHINE_TYPE_MCA) {
KeBugCheckEx (MISMATCHED_HAL,
3, HalpBusType, 0, 0);
}
#endif
//
// Most HALs initialize their PICs at this point - we set up
// the Cbus PICs in HalInitializeProcessor() long ago...
// Now that the PICs are initialized, we need to mask them to
// reflect the current Irql
//
CurrentIrql = KeGetCurrentIrql();
KfRaiseIrql(CurrentIrql);
//
// Fill in handlers for APIs which this hal supports
//
HalQuerySystemInformation = HaliQuerySystemInformation;
HalSetSystemInformation = HaliSetSystemInformation;
//
// Initialize CMOS
//
HalpInitializeCmos();
//
// Register the PC-compatible base IO space used by hal
//
HalpRegisterAddressUsage (&HalpDefaultPcIoSpace);
if (HalpBusType == MACHINE_TYPE_EISA) {
HalpRegisterAddressUsage (&HalpEisaIoSpace);
}
//
// Cbus1: stall uses the APIC to figure it out (needed in phase0).
// the clock uses the APIC (needed in phase0)
// the perfcounter uses RTC irq8 (not needed till all cpus boot)
//
// Cbus2: stall uses the RTC irq8 to figure it out (needed in phase0).
// the clock uses the irq0 (needed in phase0)
// the perfcounter uses RTC irq8 (not needed till all cpus boot)
//
//
// set up the stall execution and enable clock interrupts now.
// APC, DPC and IPI are already enabled.
//
(*CbusBackend->HalInitializeInterrupts)(0);
HalStopProfileInterrupt(0);
HalpInitializeDisplay();
//
// Initialize spinlock used by HalGetBusData hardware access routines
//
KeInitializeSpinLock(&HalpSystemHardwareLock);
//
// Any additional memory must be recovered BEFORE Phase0 ends
//
HalpAddMem(LoaderBlock);
//
// 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.
//
// This should probably create a memory descriptor which describes
// the DMA map buffers reserved by the HAL, and then add it back in
// to the LoaderBlock so the kernel can report the correct amount
// of memory in the machine.
//
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 - run by all processors eventually,
// however processor 0 runs here to completion _BEFORE_ any
// other processors have been brought out of reset.
//
PKPCR pPCR = KeGetPcr();
//
// each processor sets up his own global vectors.
// we do this here for hardware device interrupts, and
// enable IPI & SW interrupts from HalInitializeProcessor.
//
// Note that for Cbus1, InitializeClock MUST be called after
// HalpInitializeStallExecution, because HalpInitializeStallExecution
// reprograms the timer.
//
// The boot processor has already done all this as part of Phase 0,
// but each additional processor is responsible for setting up his
// own hardware, so the additional processors each do it here...
//
if (pPCR->Prcb->Number == 0) {
HalpRegisterInternalBusHandlers ();
HalpInitOtherBuses ();
}
else {
(*CbusBackend->HalInitializeInterrupts)(pPCR->Prcb->Number);
}
//
// No need to enable irq13 for FP errors - all the Corollary
// architectures are 486 and above, so we will route FP errors
// through trap 0x10.
//
}
HalpInitMP (Phase, LoaderBlock);
return TRUE;
}