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.
1281 lines
36 KiB
1281 lines
36 KiB
/*++
|
|
|
|
Copyright (c) 1992, 1993, 1994 Corollary Inc.
|
|
|
|
Module Name:
|
|
|
|
cbus.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the initialization of the system dependent
|
|
functions that define the Hardware Architecture Layer (HAL) for the
|
|
MP Corollary machines under Windows NT.
|
|
|
|
This includes the Corollary C-bus II machines which use Corollary's
|
|
CBC chips as well as Corollary C-bus I machines which use the Intel APIC.
|
|
Hardware dependencies of each C-bus backend are isolated in their
|
|
independent hardware modules. This module is completely hardware
|
|
independent.
|
|
|
|
Author:
|
|
|
|
Landy Wang ([email protected]) 26-Mar-1992
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "halp.h"
|
|
#include "cbus.h" // Cbus1 & Cbus2 max number of elements is here
|
|
#include "cbusrrd.h" // HAL <-> RRD interface definitions
|
|
#include "cbus_nt.h" // C-bus NT-specific implementation stuff
|
|
#include "cbusnls.h"
|
|
|
|
|
|
PVOID
|
|
HalpRemapVirtualAddress(IN PVOID, IN PVOID, IN BOOLEAN);
|
|
|
|
BOOLEAN
|
|
CbusMPMachine(VOID);
|
|
|
|
PUCHAR
|
|
CbusFindString (
|
|
IN PUCHAR Str,
|
|
IN PUCHAR StartAddr,
|
|
IN LONG Len
|
|
);
|
|
|
|
ULONG
|
|
CbusStringLength (
|
|
IN PUCHAR Str
|
|
);
|
|
|
|
ULONG
|
|
CbusReadExtIDs(
|
|
IN PEXT_ID_INFO From,
|
|
IN PEXT_ID_INFO To
|
|
);
|
|
|
|
PVOID
|
|
CbusMappings(
|
|
IN ULONG Processor,
|
|
IN PEXT_ID_INFO Idp
|
|
);
|
|
|
|
VOID
|
|
CbusMapMemoryRegisters(
|
|
IN PEXT_ID_INFO Idp
|
|
);
|
|
|
|
VOID
|
|
CbusEstablishMaps(
|
|
IN PEXT_ID_INFO Table,
|
|
IN ULONG Count
|
|
);
|
|
|
|
VOID
|
|
CbusReadRRD(VOID);
|
|
|
|
VOID
|
|
CbusCheckBusRanges(VOID);
|
|
|
|
VOID
|
|
CbusAddMemoryHoles(VOID);
|
|
|
|
VOID
|
|
CbusInitializeOtherPciBus(VOID);
|
|
|
|
VOID
|
|
HalInitializeProcessor(
|
|
IN ULONG Processor
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(INIT, CbusStringLength)
|
|
#pragma alloc_text(INIT, CbusFindString)
|
|
#pragma alloc_text(INIT, CbusReadExtIDs)
|
|
#pragma alloc_text(INIT, CbusMappings)
|
|
#pragma alloc_text(INIT, CbusMapMemoryRegisters)
|
|
#pragma alloc_text(INIT, CbusEstablishMaps)
|
|
#pragma alloc_text(INIT, CbusReadRRD)
|
|
#pragma alloc_text(PAGE, HalInitializeProcessor)
|
|
#endif
|
|
|
|
#define MIN(a,b) (((a)>(b))?(b):(a))
|
|
|
|
EXT_CFG_OVERRIDE_T CbusGlobal;
|
|
|
|
ULONG CbusProcessors;
|
|
ULONG CbusProcessorMask;
|
|
ULONG CbusBootedProcessors;
|
|
ULONG CbusBootedProcessorsMask;
|
|
|
|
ULONG CbusTemp;
|
|
|
|
//
|
|
// 8254 spinlock. This must be acquired before touching the 8254 chip.
|
|
//
|
|
|
|
ULONG Halp8254Lock;
|
|
|
|
ULONG HalpDefaultInterruptAffinity;
|
|
|
|
extern ULONG CbusVectorToIrql[MAXIMUM_IDTVECTOR + 1];
|
|
|
|
PULONG CbusTimeStamp;
|
|
|
|
//
|
|
// For Cbus1, the CbusCSR[] & CbusBroadcastCSR really point at
|
|
// Cbus1 I/O space which can vary from platform to platform.
|
|
//
|
|
// For Cbus2, the CbusCSR[] & CbusBroadcastCSR really do point at
|
|
// the Cbus2 CSR for the particular element.
|
|
//
|
|
PVOID CbusBroadcastCSR;
|
|
|
|
//
|
|
// Cbus information table for all elements (an element may not
|
|
// necessarily contain an x86 processor; ie: it may be a pure
|
|
// I/O element).
|
|
//
|
|
ELEMENT_T CbusCSR[MAX_CBUS_ELEMENTS];
|
|
|
|
|
|
MEMORY_CARD_T CbusMemoryBoards[MAX_ELEMENT_CSRS];
|
|
ULONG CbusMemoryBoardIndex;
|
|
|
|
//
|
|
// hardcoded size for now - see cbus.inc for the register definition
|
|
// and layout of CbusRebootRegs[].
|
|
//
|
|
ULONG CbusRebootRegs[8];
|
|
|
|
RRD_CONFIGURATION_T CbusJumpers;
|
|
|
|
EXT_ID_INFO_T CbusExtIDTable[MAX_CBUS_ELEMENTS];
|
|
ULONG CbusValidIDs;
|
|
|
|
ULONG CbusVectorToHwmap[MAXIMUM_IDTVECTOR + 1];
|
|
|
|
//
|
|
// Declare the task priority system vectors which vary from APIC to CBC.
|
|
// About the only ones that remain constant are high, low and APC & DPC.
|
|
// This is primarily due to shortcomings and errata in the APIC.
|
|
//
|
|
|
|
ULONG ProfileVector;
|
|
ULONG CbusIpiVector;
|
|
ULONG CbusClockVector;
|
|
ULONG CbusRedirVector;
|
|
ULONG CbusRebootVector;
|
|
|
|
//
|
|
// Declare these two pointers here for speed - it eliminates an
|
|
// extra asm instruction each time they are called.
|
|
//
|
|
|
|
VOID (*CbusRequestIPI)(IN ULONG);
|
|
VOID (*CbusRequestSoftwareInterrupt) ( IN KIRQL);
|
|
LARGE_INTEGER (*CbusQueryPerformanceCounter) ( IN OUT PLARGE_INTEGER);
|
|
|
|
ADDRESS_USAGE HalpCbusMemoryHole = {
|
|
NULL, CmResourceTypeMemory, InternalUsage,
|
|
{
|
|
0, 0,
|
|
0, 0,
|
|
0, 0,
|
|
0, 0,
|
|
|
|
0, 0,
|
|
0, 0,
|
|
0, 0,
|
|
0, 0,
|
|
|
|
0, 0,
|
|
0, 0,
|
|
0, 0,
|
|
0, 0,
|
|
|
|
0, 0,
|
|
0, 0,
|
|
0, 0,
|
|
0, 0
|
|
|
|
}
|
|
};
|
|
|
|
//
|
|
// this structure differs from the one above in that it only contains
|
|
// memory ranges that we want reserved for the HAL and ensure that
|
|
// devices do not get dynamically assigned memory from these ranges.
|
|
// specifically, the table above will include more ranges that the
|
|
// BIOS E820 function will remove, but that need to remain available
|
|
// for resources on the secondary peer PCI bus for C-bus II.
|
|
//
|
|
ADDRESS_USAGE HalpCbusMemoryResource = {
|
|
NULL, CmResourceTypeMemory, InternalUsage,
|
|
{
|
|
0, 0,
|
|
0, 0,
|
|
0, 0,
|
|
0, 0,
|
|
|
|
0, 0,
|
|
0, 0,
|
|
0, 0,
|
|
0, 0,
|
|
|
|
0, 0,
|
|
0, 0,
|
|
0, 0,
|
|
0, 0,
|
|
|
|
0, 0,
|
|
0, 0,
|
|
0, 0,
|
|
0, 0
|
|
|
|
}
|
|
};
|
|
|
|
ULONG CbusMemoryHoleIndex;
|
|
ULONG CbusMemoryResourceIndex;
|
|
|
|
|
|
ULONG
|
|
CbusStringLength (
|
|
IN PUCHAR Str
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return the length of the input NULL-terminated Ansi string, including
|
|
the NULL terminator at the end.
|
|
|
|
Arguments:
|
|
|
|
Str - Supplies a pointer to the string
|
|
|
|
Return Value:
|
|
|
|
Length of the string in bytes
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG n;
|
|
|
|
for (n = 0; Str[n]; ++n)
|
|
;
|
|
|
|
return ++n;
|
|
}
|
|
|
|
|
|
PUCHAR
|
|
CbusFindString (
|
|
IN PUCHAR Str,
|
|
IN PUCHAR StartAddr,
|
|
IN LONG Len
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Searches a given virtual address for the specified string
|
|
up to the specified length.
|
|
|
|
Arguments:
|
|
|
|
Str - Supplies a pointer to the string
|
|
|
|
StartAddr - Supplies a pointer to memory to be searched
|
|
|
|
Len - Maximum length for the search
|
|
|
|
Return Value:
|
|
|
|
Pointer to the string if found, 0 if not.
|
|
|
|
--*/
|
|
|
|
{
|
|
LONG Index, n;
|
|
|
|
for (n = 0; Str[n]; ++n)
|
|
;
|
|
|
|
if (--n < 0) {
|
|
return StartAddr;
|
|
}
|
|
|
|
for (Len -= n; Len > 0; --Len, ++StartAddr) {
|
|
if ((StartAddr[0] == Str[0]) && (StartAddr[n] == Str[n])) {
|
|
for (Index = 1; Index < n; ++Index)
|
|
if (StartAddr[Index] != Str[Index])
|
|
break;
|
|
if (Index >= n) {
|
|
return StartAddr;
|
|
}
|
|
}
|
|
}
|
|
|
|
return (PUCHAR)0;
|
|
}
|
|
|
|
ULONG
|
|
CbusReadExtIDs(
|
|
IN PEXT_ID_INFO From,
|
|
IN PEXT_ID_INFO To
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Read in the C-bus II extended id information table.
|
|
|
|
Arguments:
|
|
|
|
From - Supplies a pointer to the RRD source table
|
|
|
|
To - Supplies a pointer to the destination storage for the table
|
|
|
|
Return Value:
|
|
|
|
Number of valid table entries.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Index = 0;
|
|
ULONG ValidEntries = 0;
|
|
|
|
for ( ; Index < MAX_CBUS_ELEMENTS && From->id != LAST_EXT_ID; Index++) {
|
|
|
|
//
|
|
// we cannot skip blank RRD entries
|
|
//
|
|
// if (From->pm == 0 && From->io_function == IOF_INVALID_ENTRY)
|
|
// continue;
|
|
|
|
RtlMoveMemory((PVOID)To, (PVOID)From, sizeof(EXT_ID_INFO_T));
|
|
|
|
From++;
|
|
To++;
|
|
ValidEntries++;
|
|
}
|
|
|
|
//
|
|
// WARNING: this is not necessarily the number of valid CPUs !!!
|
|
//
|
|
return ValidEntries;
|
|
}
|
|
|
|
PVOID
|
|
CbusMappings(
|
|
IN ULONG Processor,
|
|
IN PEXT_ID_INFO Idp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Map a given processor's CSR space and save an idp pointer as well.
|
|
|
|
Arguments:
|
|
|
|
Processor - Supplies a logical processor number
|
|
|
|
Idp - Supplies an RRD extended ID pointer for this processor element
|
|
|
|
Return Value:
|
|
|
|
Opaque pointer to this processor's CSR space.c
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// RRD specifies how much to map in per processor - this
|
|
// will usually be just 8K of the 64K CSR space for Cbus2.
|
|
// For Cbus1, RRD must give us a size which includes any
|
|
// processor-specific registers the HAL may access,
|
|
// generally indicated via the CbusGlobal structure.
|
|
//
|
|
CbusCSR[Processor].csr = HalpMapPhysicalMemoryWriteThrough (
|
|
(PVOID)Idp->pel_start,
|
|
(ULONG)ADDRESS_AND_SIZE_TO_SPAN_PAGES(
|
|
Idp->pel_start, Idp->pel_size));
|
|
|
|
CbusCSR[Processor].idp = (PVOID)Idp;
|
|
|
|
return CbusCSR[Processor].csr;
|
|
}
|
|
|
|
VOID
|
|
CbusMapMemoryRegisters(
|
|
IN PEXT_ID_INFO Idp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Maps a given RRD entry into the HAL's memory board structures.
|
|
This is used later to determine ECC error addresses, etc.
|
|
|
|
Arguments:
|
|
|
|
Idp - Supplies a pointer to the RRD extended information structure entry
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PMEMORY_CARD pm;
|
|
|
|
pm = &CbusMemoryBoards[CbusMemoryBoardIndex];
|
|
|
|
pm->physical_start = Idp->pel_start;
|
|
pm->physical_size = Idp->pel_size;
|
|
pm->io_attr = (ULONG)Idp->io_attr;
|
|
|
|
//
|
|
// map in the csr space for this memory card
|
|
//
|
|
pm->regmap = HalpMapPhysicalMemoryWriteThrough (
|
|
(PVOID)Idp->io_start,
|
|
(ULONG)ADDRESS_AND_SIZE_TO_SPAN_PAGES(
|
|
Idp->io_start, Idp->io_size));
|
|
|
|
CbusMemoryBoardIndex++;
|
|
}
|
|
|
|
VOID
|
|
CbusEstablishMaps(
|
|
IN PEXT_ID_INFO Table,
|
|
IN ULONG Count
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parse the given RRD extended ID configuration table, and construct
|
|
various HAL data structures accordingly.
|
|
|
|
Arguments:
|
|
|
|
Table - Supplies a pointer to the RRD extended information table
|
|
|
|
Count - Supplies a count of the maximum number of entries.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONG Index, processor = 0;
|
|
ULONG HighVector;
|
|
ULONG Length;
|
|
PEXT_ID_INFO Idp = Table;
|
|
PUCHAR csr;
|
|
extern VOID CbusMemoryFree(ULONG, ULONG);
|
|
extern VOID CbusIOPresent(ULONG, ULONG, ULONG, ULONG, ULONG, PVOID);
|
|
extern ULONG IxProfileVector;
|
|
|
|
for (Index = 0; Index < Count; Index++, Idp++) {
|
|
|
|
//
|
|
// Map in the broadcast CSR. Note this is not a processor.
|
|
//
|
|
|
|
if (Idp->id == CbusGlobal.broadcast_id) {
|
|
CbusBroadcastCSR = HalpMapPhysicalMemoryWriteThrough (
|
|
(PVOID)Idp->pel_start,
|
|
(ULONG)ADDRESS_AND_SIZE_TO_SPAN_PAGES(
|
|
Idp->pel_start, Idp->pel_size));
|
|
//
|
|
// Register the broadcast element's memory
|
|
// mapped I/O space
|
|
//
|
|
continue;
|
|
}
|
|
|
|
|
|
//
|
|
// Establish virtual maps for each processor
|
|
//
|
|
|
|
if (Idp->pm) {
|
|
|
|
if ((UCHAR)Idp->id == CbusGlobal.bootid) {
|
|
CbusMappings(0, Idp);
|
|
}
|
|
else {
|
|
|
|
//
|
|
// We have an additional processor - set up
|
|
// his maps and put him in reset. We will
|
|
// boot him shortly.
|
|
//
|
|
|
|
processor++;
|
|
|
|
csr = (PUCHAR)CbusMappings(processor, Idp);
|
|
|
|
csr += CbusGlobal.smp_sreset;
|
|
|
|
*((PULONG)csr) = CbusGlobal.smp_sreset_val;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Establish virtual maps for each I/O and/or
|
|
// memory board. Note that I/O devices may or may
|
|
// not have an attached processor - a CPU is NOT required!
|
|
// memory, on the other hand, may NOT have a processor
|
|
// on the same board.
|
|
//
|
|
|
|
switch (Idp->io_function) {
|
|
case IOF_INVALID_ENTRY:
|
|
case IOF_NO_IO:
|
|
break;
|
|
|
|
case IOF_MEMORY:
|
|
//
|
|
// If not a processor, must be a memory card.
|
|
// Add this memory card to our list
|
|
// of memory cards in the machine.
|
|
//
|
|
|
|
if (Idp->pm)
|
|
break;
|
|
|
|
CbusMapMemoryRegisters(Idp);
|
|
|
|
//
|
|
// Add this memory range to our list
|
|
// of additional memory to free later.
|
|
//
|
|
|
|
CbusMemoryFree(Idp->pel_start, Idp->pel_size);
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// Add this I/O functionality to our table
|
|
// to make available to Cbus hardware drivers.
|
|
// Since I/O card interpretation of the RRD
|
|
// table is strictly up to the driver, do not
|
|
// try to register any of this element's space
|
|
// in the HAL's public consumption list, as we
|
|
// do for memory and processor cards.
|
|
//
|
|
|
|
if (Idp->pel_features & ELEMENT_HAS_IO) {
|
|
|
|
//
|
|
// If there was an attached processor,
|
|
// we already mapped in the CSR. If
|
|
// no attached processor, map in the
|
|
// CSR now. We'll need it later for
|
|
// interrupt vector enabling.
|
|
//
|
|
|
|
if (Idp->pm == 0) {
|
|
csr = HalpMapPhysicalMemoryWriteThrough (
|
|
(PVOID)Idp->pel_start,
|
|
(ULONG)ADDRESS_AND_SIZE_TO_SPAN_PAGES(
|
|
Idp->pel_start, Idp->pel_size));
|
|
}
|
|
|
|
CbusIOPresent(
|
|
(ULONG)Idp->id,
|
|
(ULONG)Idp->io_function,
|
|
(ULONG)Idp->io_attr,
|
|
Idp->pel_start,
|
|
Idp->pel_size,
|
|
(PVOID)csr );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Ensure that the memory subsystem does not use areas mapped out by
|
|
// e820 in determining the system memory ranges.
|
|
//
|
|
Length = 0xffffffff - CbusGlobal.cbusio;
|
|
AddMemoryHole(CbusGlobal.cbusio, Length + 1);
|
|
if (CbusBackend->AddMemoryHoles)
|
|
(*CbusBackend->AddMemoryHoles)();
|
|
HalpRegisterAddressUsage (&HalpCbusMemoryResource);
|
|
|
|
//
|
|
// Set total number of processors and their global mask
|
|
//
|
|
|
|
CbusProcessors = processor + 1;
|
|
CbusProcessorMask = (1 << CbusProcessors) - 1;
|
|
|
|
//
|
|
// Initialize the platform data - done only ONCE.
|
|
// Backends are expected to initialize the global Cbus
|
|
// spurious interrupt vector and the irqltovec[] table.
|
|
// We then pull the dispatch, wake and profile vectors
|
|
// from the table.
|
|
//
|
|
|
|
(*CbusBackend->InitializePlatform)();
|
|
|
|
CbusRequestIPI = CbusBackend->HalRequestInterrupt;
|
|
CbusRequestSoftwareInterrupt = CbusBackend->HalRequestSoftwareInterrupt;
|
|
CbusQueryPerformanceCounter = CbusBackend->HalQueryPerformanceCounter;
|
|
|
|
ProfileVector = CbusIrqlToVector[PROFILE_LEVEL];
|
|
CbusClockVector = CbusIrqlToVector[CLOCK2_LEVEL];
|
|
CbusIpiVector = CbusIrqlToVector[IPI_LEVEL];
|
|
|
|
HighVector = CbusIrqlToVector[HIGH_LEVEL];
|
|
CbusVectorToIrql[HighVector] = HIGH_LEVEL;
|
|
|
|
//
|
|
// Initialize the standard IxProfileVector so that we can
|
|
// reuse the standard profile code.
|
|
//
|
|
|
|
IxProfileVector = ProfileVector;
|
|
}
|
|
|
|
VOID
|
|
HalpResetAllProcessors(VOID)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called to put all the other processors in reset prior to reboot for
|
|
the Corollary architectures. Highly architecture specific.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONG Processor;
|
|
|
|
Processor = KeGetPcr()->HalReserved[PCR_PROCESSOR];
|
|
|
|
(*CbusBackend->ResetAllOtherProcessors)(Processor);
|
|
}
|
|
|
|
UCHAR ObsoleteMachine[] = MSG_OBSOLETE;
|
|
|
|
VOID
|
|
FatalError(
|
|
IN PUCHAR ErrorString
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called to halt the HAL due to a fatal error, printing out a
|
|
string describing the cause of the failure.
|
|
|
|
Arguments:
|
|
|
|
ErrorString - Supplies a pointer to failure message
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
HalDisplayString(ErrorString);
|
|
HalDisplayString(MSG_HALT);
|
|
|
|
while (1)
|
|
;
|
|
}
|
|
|
|
static ULONG RRDextsignature[] = { 0xfeedbeef, 0 };
|
|
|
|
static ULONG RRDsignature[] = { 0xdeadbeef, 0 };
|
|
|
|
static UCHAR CorollaryOwns[] = "Copyright(C) Corollary, Inc. 1991. All Rights Reserved";
|
|
|
|
VOID
|
|
CbusReadRRD(VOID)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
For robustness, we check for the following before concluding that
|
|
we are indeed a Corollary C-bus I or C-bus II licensee supported
|
|
in multiprocessor mode under this HAL:
|
|
|
|
a) Corollary string in the BIOS ROM 64K area (0x000F0000)
|
|
b) Corollary string in the RRD RAM/ROM 64K area (0xFFFE0000)
|
|
c) 2 Corollary extended configuration tables
|
|
in the RRD RAM/ROM 64K area (0xFFFE0000)
|
|
|
|
If any of the above checks fail, it is assumed that this machine
|
|
is either a non-Corollary machine or an early Corollary machine
|
|
not supported by this HAL. Both of these types of machines are,
|
|
however, supported (in uniprocessor mode) by the standard
|
|
uniprocessor HAL.
|
|
|
|
If the above checks succeed, then we proceed to fill in various
|
|
configuration structures for later use.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONG Index;
|
|
PEXT_CFG_HEADER p;
|
|
PVOID s;
|
|
ULONG OverrideLength = 0, EntryLength;
|
|
PUCHAR Bios;
|
|
|
|
//
|
|
// Map in the 64K (== 0x10 pages) of BIOS ROM @ 0xF0000
|
|
// and scan it for our signature...
|
|
//
|
|
|
|
Bios = (PUCHAR)HalpMapPhysicalMemory ((PVOID)0xF0000, 0x10);
|
|
|
|
if (!CbusFindString((PUCHAR)"Corollary", Bios, (LONG)0x10000))
|
|
KeBugCheck (MISMATCHED_HAL);
|
|
|
|
//
|
|
// Map in the 64K (== 0x10 pages) of RRD @ 0xFFFE0000 and
|
|
// scan it for our signature. (Note we are taking advantage
|
|
// of the fact that the lengths are the same, thus reusing
|
|
// the above PTEs, as opposed to allocating new ones).
|
|
//
|
|
|
|
for (Index = 0; Index < 0x10; Index++) {
|
|
HalpRemapVirtualAddress(
|
|
Bios + (Index << PAGE_SHIFT),
|
|
(PVOID)(0xFFFE0000 + (Index << PAGE_SHIFT)),
|
|
FALSE);
|
|
}
|
|
|
|
if (!CbusFindString((PUCHAR)"Corollary", Bios, (LONG)0x10000))
|
|
KeBugCheck (MISMATCHED_HAL);
|
|
|
|
//
|
|
// Map in the 32K (== 8 pages) of RRD RAM information @ 0xE0000,
|
|
// again reusing previously gained PTEs. Note we are only reusing
|
|
// the low half this time.
|
|
//
|
|
|
|
for (Index = 0; Index < 8; Index++) {
|
|
HalpRemapVirtualAddress(
|
|
Bios + (Index << PAGE_SHIFT),
|
|
(PVOID)(RRD_RAM + (Index << PAGE_SHIFT)),
|
|
FALSE);
|
|
}
|
|
|
|
if (!CbusFindString((PUCHAR)CorollaryOwns, Bios, (LONG)0x8000))
|
|
FatalError(ObsoleteMachine);
|
|
|
|
//
|
|
// At this point, we are assured that it is indeed a
|
|
// Corollary architecture machine. Search for our
|
|
// extended configuration tables, note we still search for
|
|
// the existence of our earliest 'configuration' structure,
|
|
// ie: the 0xdeadbeef version. This is not to find out where
|
|
// the memory is, but to find out which Cbus1 megabytes have been
|
|
// 'jumpered' so that I/O cards can use the RAM address(es) for
|
|
// their own dual-ported RAM buffers. This early configuration
|
|
// structure will not be present in Cbus2.
|
|
//
|
|
// If there is no extended configuration structure,
|
|
// this must be an old rom. NO SUPPORT FOR THESE.
|
|
//
|
|
|
|
s = (PVOID)CbusFindString((PUCHAR)RRDsignature, Bios,
|
|
(LONG)0x8000);
|
|
|
|
if (s) {
|
|
RtlMoveMemory((PVOID)&CbusJumpers, (PVOID)s, JUMPER_SIZE);
|
|
}
|
|
#if DBG
|
|
else {
|
|
//
|
|
// RRD configuration is not expected on Cbus2, but is for Cbus1
|
|
//
|
|
HalDisplayString("HAL: No RRD ROM configuration table\n");
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Now go for the extended configuration structure which will tell
|
|
// us about memory, processors and I/O devices.
|
|
//
|
|
|
|
p = (PEXT_CFG_HEADER)CbusFindString((PUCHAR)RRDextsignature,
|
|
Bios, (LONG)0x8000);
|
|
|
|
if (!p) {
|
|
#if DBG
|
|
HalDisplayString("HAL: No extended configuration table\n");
|
|
#endif
|
|
FatalError(ObsoleteMachine);
|
|
}
|
|
|
|
//
|
|
// Read in the 'extended ID information' table which,
|
|
// among other things, will give us the processor
|
|
// configuration.
|
|
//
|
|
// Multiple structures are strung together with a "checkword",
|
|
// "length", and "data" structure. The first null "checkword"
|
|
// entry marks the end of the extended configuration
|
|
// structure.
|
|
//
|
|
// We are only actively reading two types of structures, and
|
|
// they MUST be in the following order, although not necessarily
|
|
// consecutive:
|
|
//
|
|
// - ext_id_info
|
|
//
|
|
// - ext_cfg_override
|
|
//
|
|
// We ignore all other extended configuration entries built
|
|
// by RRD - they are mainly for early UNIX kernels.
|
|
//
|
|
|
|
do {
|
|
EntryLength = p->ext_cfg_length;
|
|
|
|
switch (p->ext_cfg_checkword) {
|
|
|
|
case EXT_ID_INFO:
|
|
|
|
CbusValidIDs = CbusReadExtIDs((PEXT_ID_INFO)(p+1),
|
|
(PEXT_ID_INFO)CbusExtIDTable);
|
|
|
|
break;
|
|
|
|
case EXT_CFG_OVERRIDE:
|
|
//
|
|
// We just copy the size of the structures
|
|
// we know about. If an rrd tries to pass us
|
|
// more than we know about, we ignore the
|
|
// overflow. Underflow is interpreted as
|
|
// "this must be a pre-XM machine", and such
|
|
// machines must default to the standard Windows NT
|
|
// uniprocessor HAL.
|
|
//
|
|
|
|
if (EntryLength < sizeof(EXT_CFG_OVERRIDE_T)) {
|
|
FatalError(MSG_RRD_ERROR);
|
|
}
|
|
|
|
OverrideLength = MIN(sizeof(EXT_CFG_OVERRIDE_T),
|
|
EntryLength);
|
|
|
|
RtlMoveMemory((PVOID)&CbusGlobal,
|
|
(PVOID)(p + 1), OverrideLength);
|
|
|
|
break;
|
|
|
|
case EXT_CFG_END:
|
|
|
|
//
|
|
// If ancient C-bus box, it's not supported in MP mode
|
|
//
|
|
if (CbusValidIDs == 0 || OverrideLength == 0) {
|
|
#if DBG
|
|
HalDisplayString("HAL: Missing RRD tables\n");
|
|
#endif
|
|
FatalError(ObsoleteMachine);
|
|
}
|
|
|
|
if (CbusMPMachine() == FALSE) {
|
|
#if DBG
|
|
HalDisplayString("HAL: This Corollary machine is not supported under this HAL\n");
|
|
#endif
|
|
FatalError(ObsoleteMachine);
|
|
}
|
|
|
|
(*CbusBackend->ParseRRD)((PVOID)CbusExtIDTable,
|
|
&CbusValidIDs);
|
|
|
|
|
|
CbusEstablishMaps(CbusExtIDTable, CbusValidIDs);
|
|
|
|
return;
|
|
|
|
default:
|
|
//
|
|
// Skip unused or unrecognized configuration entries
|
|
//
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Get past the header, add in the length and then
|
|
// we're at the next entry.
|
|
//
|
|
p = (PEXT_CFG_HEADER) ((PUCHAR)(p + 1) + EntryLength);
|
|
|
|
} while (1);
|
|
|
|
// never reached
|
|
}
|
|
|
|
VOID
|
|
CbusCheckBusRanges(VOID)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check all buses and determine SystemBase
|
|
for all ranges within all buses.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (CbusBackend->CheckBusRanges) {
|
|
(*CbusBackend->CheckBusRanges)();
|
|
}
|
|
}
|
|
|
|
VOID
|
|
CbusAddMemoryHoles(VOID)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Find the holes in the C-bus memory space that is not
|
|
useable for device allocation.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (CbusBackend->AddMemoryHoles) {
|
|
(*CbusBackend->AddMemoryHoles)();
|
|
}
|
|
}
|
|
|
|
VOID
|
|
CbusInitializeOtherPciBus(VOID)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Find and initialize other PCI system buses.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
if (CbusBackend->InitializeOtherPciBus) {
|
|
(*CbusBackend->InitializeOtherPciBus)();
|
|
}
|
|
}
|
|
|
|
VOID
|
|
HalpDisableAllInterrupts (VOID)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This routine is called during a system crash. The Hal needs all
|
|
interrupts disabled. Interrupts will NOT be enabled upon leaving
|
|
this routine, nor is it allowed to turn them back on later. this
|
|
is a one-time thing, done as the system is coming down.
|
|
|
|
Disables all incoming interrupts for the calling processor.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None - all interrupts are masked off
|
|
|
|
--*/
|
|
{
|
|
KfRaiseIrql(HIGH_LEVEL);
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called by each processor in turn, to initialize himself.
|
|
|
|
- This is the earliest point at which the HAL gets control of
|
|
the system on each processor.
|
|
|
|
- The boot CPU runs it early on in kernel startup. Much later,
|
|
each additional CPU will also run it shortly after they are
|
|
brought out of reset during Phase 1.
|
|
|
|
- When called by the boot processor, this routine also reads in
|
|
the global RRD information which pertains to the entire system,
|
|
including all the processors.
|
|
|
|
- Later, the boot cpu will run HalInitSystem --> HalpInitMP.
|
|
This all occurs at Phase 0.
|
|
|
|
Much later, the Phase1 thread runs on the boot cpu, and calls
|
|
HalInitSystem --> HalpInitMP again, this time at Phase 1.
|
|
Then the boot cpu runs KeStartAllProcessors. this serially
|
|
invokes HalStartNextProcessor for each of our additional cpus
|
|
to start them running KiSystemStartup.
|
|
|
|
As each additional processor runs KiSystemStartup, he then
|
|
runs HalInitializeProcessor. This is when we will enable the
|
|
additional processor's incoming IPIs. After that, he will proceed
|
|
to KiInitializeKernel & ExpInitializeExecutive, who then calls
|
|
HalInitSystem. Each additional processor is always running
|
|
at Phase 1, never Phase 0.
|
|
|
|
The above dictates the actions of these routines:
|
|
|
|
- HalInitializeProcessor will read in (ONCE only, ie: only the
|
|
boot cpu will do this) all of the element space and set up
|
|
_global_ maps for each processor's CSR. each CPU will map
|
|
his own _local_ CSR into his HAL pcr. each CPU will
|
|
enable his incoming IPI here, and disable all other interrupts,
|
|
including all of this CPU's half-card CBC I/O interrupts.
|
|
|
|
- It would be nice to move some of the HalInitializeProcessor Phase0
|
|
code to HalInitSystem Phase0, but we need full mappings, etc,
|
|
for entering the debugger from KiSystemStartup early on.
|
|
|
|
- KeReadir/LowerIrq's must be available once this function
|
|
returns. (IPI's are only used once two or more processors are
|
|
available)
|
|
|
|
Arguments:
|
|
|
|
Processor - Supplies a logical processor number
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
VOID
|
|
HalInitializeProcessor(
|
|
IN ULONG Processor
|
|
)
|
|
{
|
|
extern VOID i486cacheon(VOID);
|
|
extern VOID HalpInitializeCoreIntrs(VOID);
|
|
extern VOID CbusDefaultStall(VOID);
|
|
extern VOID HalpIpiHandler( VOID );
|
|
extern PULONG CbusVectorToEoi[MAXIMUM_IDTVECTOR + 1];
|
|
extern KSPIN_LOCK CbusVectorLock;
|
|
ULONG i;
|
|
ELEMENT_T csr;
|
|
PEXT_ID_INFO Idp;
|
|
extern KAFFINITY HalpActiveProcessors;
|
|
|
|
if (Processor == 0) {
|
|
|
|
//
|
|
// Find our signature and configuration information
|
|
//
|
|
CbusReadRRD();
|
|
|
|
//
|
|
// CbusVectorLock needs to be initialized before
|
|
// any CBC interrupt vectors are given out via
|
|
// HalGetInterruptVector().
|
|
//
|
|
KeInitializeSpinLock(&CbusVectorLock);
|
|
|
|
//
|
|
// Initialize the Eoi addresses to point at a known don't-care.
|
|
// Any interrupt that gets enabled later will get the correct
|
|
// EOI address filled in by the hardware backend interrupt
|
|
// enabling code.
|
|
//
|
|
for (i = 0 ; i <= MAXIMUM_IDTVECTOR; i++) {
|
|
CbusVectorToEoi[i] = &CbusTemp;
|
|
}
|
|
CbusTimeStamp = &CbusTemp;
|
|
}
|
|
|
|
//
|
|
// Default stall execution to something reasonable
|
|
// until we initialize it later in HalInitSystem.
|
|
//
|
|
CbusDefaultStall();
|
|
|
|
//
|
|
// Enable this processor's internal cache - do this
|
|
// before stall execution is initialized in HalInitSystem.
|
|
//
|
|
csr = CbusCSR[Processor];
|
|
|
|
Idp = (PEXT_ID_INFO)csr.idp;
|
|
|
|
//
|
|
// Enable the processor internal cache here...
|
|
//
|
|
if (Idp->proc_attr == PA_CACHE_ON) {
|
|
i486cacheon();
|
|
}
|
|
|
|
//
|
|
// Map this CPU's CSR stuff into his local address space for
|
|
// fast access. Also his logical # and bit position.
|
|
//
|
|
|
|
(PVOID) KeGetPcr()->HalReserved[PCR_CSR] = CbusCSR[Processor].csr;
|
|
|
|
(ULONG) KeGetPcr()->HalReserved[PCR_PROCESSOR] = Processor;
|
|
|
|
(ULONG) KeGetPcr()->HalReserved[PCR_BIT] = (1 << Processor);
|
|
|
|
(ULONG) KeGetPcr()->HalReserved[PCR_ALL_OTHERS] =
|
|
(CbusProcessorMask & ~(1 << Processor));
|
|
|
|
(PVOID) KeGetPcr()->HalReserved[PCR_LED_ON] = (PVOID)
|
|
((PUCHAR)CbusCSR[Processor].csr + CbusGlobal.smp_sled);
|
|
|
|
(PVOID) KeGetPcr()->HalReserved[PCR_LED_OFF] = (PVOID)
|
|
((PUCHAR)CbusCSR[Processor].csr + CbusGlobal.smp_cled);
|
|
|
|
//
|
|
// Since our architecture is completely symmetric,
|
|
// update affinity to contain each booted processor.
|
|
//
|
|
HalpDefaultInterruptAffinity |= (1 << Processor);
|
|
|
|
//
|
|
// This parameter is returned by the HAL when the system asks
|
|
// for the HAL's configured resources list.
|
|
//
|
|
HalpActiveProcessors = HalpDefaultInterruptAffinity;
|
|
|
|
CbusBootedProcessors += 1;
|
|
CbusBootedProcessorsMask = (1 << CbusBootedProcessors) - 1;
|
|
|
|
//
|
|
// Initialize this processor's data - done ONCE by each processor.
|
|
//
|
|
// Typically, this processor's interrupt controller is initialized
|
|
// here. Also, if it's the first processor, any I/O interrupt
|
|
// controllers will also be initialized here, ie: EISA bridges or
|
|
// I/O APICs.
|
|
//
|
|
(*CbusBackend->InitializeCPU)(Processor);
|
|
|
|
//
|
|
// This is where we actually enable IPI, APC, DPC and
|
|
// SPURIOUS interrupts. Device interrupts (like clock and
|
|
// profile) will not be enabled until HalInitSystem calls
|
|
// HalpInitializePICs later. Since we are still cli'd, no
|
|
// interrupt could actually bop us until KiSystemStartup
|
|
// calls KiInitializeKernel who drops IRQL.
|
|
//
|
|
HalpInitializeCoreIntrs();
|
|
}
|
|
|
|
#define CBUS1_NMI_MASK (PUCHAR)0x70
|
|
#define CBUS1_IO_CHANNEL_CHECK (PUCHAR)0x61
|
|
|
|
VOID
|
|
CbusClearEISANMI(VOID)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function clears the NMI on the EISA bus. Typically this
|
|
was generated by one of Corollary's "NMI cards", used for
|
|
debugging purposes. Our caller will have pointed us at the
|
|
correct bus bridge prior to calling us. note therefore we cannot
|
|
display anything because we may not be pointing at the default
|
|
display - if we want to display, we must map the bridge containing
|
|
the default video adapter!
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
--*/
|
|
{
|
|
UCHAR IoChannelCheck;
|
|
|
|
WRITE_PORT_UCHAR(CBUS1_NMI_MASK, (UCHAR)0);
|
|
|
|
IoChannelCheck = READ_PORT_UCHAR(CBUS1_IO_CHANNEL_CHECK);
|
|
WRITE_PORT_UCHAR(CBUS1_IO_CHANNEL_CHECK,
|
|
(UCHAR)((IoChannelCheck & 0xF) | 0x08));
|
|
|
|
IoChannelCheck = READ_PORT_UCHAR(CBUS1_IO_CHANNEL_CHECK);
|
|
WRITE_PORT_UCHAR(CBUS1_IO_CHANNEL_CHECK,
|
|
(UCHAR)(IoChannelCheck & 0x7));
|
|
|
|
//
|
|
// Since the NMI we are clearing was caused by pressing the button,
|
|
// which generated an EISA NMI (not a Cbus NMI), don't clear the
|
|
// NMI in Cbus space.
|
|
//
|
|
// COUTB(CbusCSR[Processor].csr, CbusGlobal.smp_cnmi,
|
|
// CbusGlobal.smp_cnmi_val);
|
|
//
|
|
}
|