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

546 lines
13 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) 1992, 1993, 1994 Corollary Inc.
Module Name:
cbdetect.c
Abstract:
This module detects the presence of a Corollary architecture machine
which can utilize the Corollary-developed HAL for Windows NT. Currently,
the picture looks as follows:
C-bus I original: uses standard Windows NT HAL
C-bus I XM: uses standard Windows NT HAL
C-bus I Symmetric XM: uses Corollary-developed Windows NT HAL
C-bus II: uses Corollary-developed Windows NT HAL
Thus, we return 0 for the first two cases, and non-zero for the last two.
Author:
Landy Wang (landy@corollary.com) 05-Oct-1992
Environment:
Kernel mode only. This module must compile standalone,
and thus, any needed #defines have been copied directly
into this module.
--*/
#ifndef _NTOS_
#include "nthal.h"
#endif
PVOID
HalpMapPhysicalMemory(
IN PVOID PhysicalAddress,
IN ULONG NumberPages
);
//
// address of configuration passed
//
#define RRD_RAM 0xE0000
//
// extended structures passed by RRD ROMs to various kernels/HALs
// for the Corollary smp architectures
//
// layout of information passed to the kernels/HALs:
// The exact format of the configuration structures is hard
// coded in info.s (rrd). The layout is designed such that
// the ROM version need not be in sync with the kernel/HAL version.
//
// checkword: ULONG
// - extended configuration list must be terminated
// with EXT_CFG_END (0)
// length: ULONG
// - length is for structure body only; does not include
// either the checkword or length word
//
// structure body: format determined by checkword
//
//
typedef struct _ext_cfg_header {
ULONG ext_cfg_checkword;
ULONG ext_cfg_length;
} EXT_CFG_HEADER_T, *PEXT_CFG_HEADER;
//
// slot parameter structure (overrides any matching previous entry,
// but is usually used in conjunction with the ext_cfg_override)
// in processor_configuration or ext_memory_board.
//
// checkword is EXT_ID_INFO
//
// each structure is 16 bytes wide, and any number
// of these structures can be presented by the ROM.
// the kernel/HAL will keep reading them until either:
//
// a) an entry with id == 0x7f (this is treated as the list delimiter)
// OR
// b) the kernel (or HAL)'s internal tables fill up. at which point, only
// the entries read thus far will be used and the rest ignored.
//
#define EXT_ID_INFO 0x01badcab
typedef struct _ext_id_info {
ULONG id:7;
ULONG pm:1;
ULONG proc_type:4;
ULONG proc_attr:4;
ULONG io_function:8;
ULONG io_attr:8;
ULONG pel_start;
ULONG pel_size;
ULONG pel_features;
ULONG io_start;
ULONG io_size;
} EXT_ID_INFO_T, *PEXT_ID_INFO;
#define LAST_EXT_ID 0x7f // delimit the extended ID list
//
// configuration parameter override structure
//
// checkword is EXT_CFG_OVERRIDE.
// can be any length up to the kernel/HAL limit. this
// is a SYSTEMWIDE configuration override structure.
//
#define EXT_CFG_OVERRIDE 0xdeedcafe
typedef struct _ext_cfg_override {
ULONG baseram;
ULONG memory_ceiling;
ULONG resetvec;
//
// cbusio is the base of global C-bus I/O space.
//
ULONG cbusio;
UCHAR bootid;
UCHAR useholes;
UCHAR rrdarb;
UCHAR nonstdecc;
ULONG smp_creset;
ULONG smp_creset_val;
ULONG smp_sreset;
ULONG smp_sreset_val;
ULONG smp_contend;
ULONG smp_contend_val;
ULONG smp_setida;
ULONG smp_setida_val;
ULONG smp_cswi;
ULONG smp_cswi_val;
ULONG smp_sswi;
ULONG smp_sswi_val;
ULONG smp_cnmi;
ULONG smp_cnmi_val;
ULONG smp_snmi;
ULONG smp_snmi_val;
ULONG smp_sled;
ULONG smp_sled_val;
ULONG smp_cled;
ULONG smp_cled_val;
ULONG machine_type;
ULONG supported_environments;
ULONG broadcast_id;
} EXT_CFG_OVERRIDE_T, *PEXT_CFG_OVERRIDE;
#define EXT_CFG_END 0
#define MAX_CBUS_ELEMENTS 32 // max number of processors + I/O
//
// Bit fields of pel_features if pm indicates it's a processor
//
#define ELEMENT_SIO 0x00001 // SIO present
#define ELEMENT_SCSI 0x00002 // SCSI present
#define ELEMENT_IOBUS 0x00004 // IO bus is accessible
#define ELEMENT_BRIDGE 0x00008 // IO bus Bridge
#define ELEMENT_HAS_8259 0x00010 // local 8259s present
#define ELEMENT_HAS_CBC 0x00020 // local Corollary CBC
#define ELEMENT_HAS_APIC 0x00040 // local Intel APIC
#define ELEMENT_RRD_RESERVED 0x20000 // Old RRDs used this
//
// Bit fields of machine types
//
#define MACHINE_CBUS1 0x1 // Original C-bus 1
#define MACHINE_CBUS1_XM 0x2 // XM C-bus 1
#define MACHINE_CBUS2 0x4 // C-bus 2
//
// Bit fields of supported environment types - each bit signifies that
// the specified operating system release is supported in full multiprocessor
// mode. Note that since the Cbus2 hardware changed, and initial hardware
// wasn't available until Q2 1994, Cbus2 RRDs will _NEVER_ set the
// 0x4 bit, and will instead set the 0x10 bit. This will have the effect
// of Cbus2 being supported in MP mode by NT release 3.5 and up. Cbus1
// will be supported in MP mode by all NT releases (3.1 and up).
//
#define SCO_UNIX 0x01
#define USL_UNIX 0x02
#define WINDOWS_NT 0x04 // release 3.1 and up (July 1993)
#define NOVELL 0x08
#define OS2 0x10
#define WINDOWS_NT_R2 0x20 // release 3.5 and up (June 1994)
extern ULONG CorollaryHalNeeded(PEXT_CFG_OVERRIDE, PEXT_ID_INFO,
PBOOLEAN);
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;
}
//
// for robustness, we check for the following before concluding that
// we are indeed a Corollary C-bus I or C-bus II licensee:
//
// a) Corollary C-bus II string in the BIOS ROM 64K area (0x000F0000)
// b) Corollary C-bus II 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 fail, we assume we are not a Corollary
// C-bus I or C-bus II box, and revert to normal uniprocessor
// behavior.
//
static ULONG RRDextsignature[] = { 0xfeedbeef, 0 };
static CHAR crllry_owns[] = "Copyright(C) Corollary, Inc. 1991. All Rights Reserved";
ULONG
DetectCbusII(
OUT PBOOLEAN IsConfiguredMp
)
/*++
Routine Description:
Determine which Corollary platform, if any, is present.
Arguments:
none.
Return Value:
Return TRUE to indicate the machine is a Corollary MP machine
which requires the Corollary Windows NT HAL for full performance.
We only set IsConfiguredMp if we find more than 1 processor,
since it is only then that we want to incur the overhead of the
fully-built multiprocessor kernel. note that as long as we return
TRUE, our HAL will be used, so we will still get our improved
interrupt controller, ECC, additional memory, etc, etc.
All other cases will return FALSE, and clear IsConfiguredMp as well.
--*/
{
PEXT_CFG_HEADER p;
PEXT_ID_INFO Idp = (PEXT_ID_INFO)0;
PEXT_CFG_OVERRIDE CbusGlobal = (PEXT_CFG_OVERRIDE)0;
ULONG EntryLength;
PUCHAR Bios;
//
// assume it's not a Corollary MP machine (requiring the
// Corollary Windows NT HAL for full performance)
// unless we detect otherwise below.
//
*IsConfiguredMp = FALSE;
//
// map in the 64K (== 0x10 pages) of BIOS ROM @ 0xF0000
// and scan it for our signature. Note that when this
// code runs, the entire low 16MB address space is
// identity mapped, so the HalpMapPhysicalMemory call
// just returns (virtual address == physical address).
// the upshot of this, is that we need not worry about
// exhausting PTEs and doing Remaps or Frees. however,
// this also means we cannot map in the 64K of
// RRD @ 0xFFFE0000 since HalpMapPhysicalMemory will fail.
// so skip this second check until HalpMapPhysicalMemory is fixed.
//
Bios = (PUCHAR)HalpMapPhysicalMemory ((PVOID)0xF0000, 0x10);
if (!CbusFindString((PUCHAR)"Corollary", Bios, (LONG)0x10000))
return 0;
//
// we'd like to map in the 64K (== 0x10 pages) of RRD @ 0xFFFE0000 and
// scan it for our signature. but we can't in the detect code,
// because HalpMapPhysicalMemory() can't deal with memory over
// the 16MB boundary. so leave it for the HAL to check this.
//
#if 0
Bios = (PUCHAR)HalpMapPhysicalMemory ((PVOID)0xFFFE0000, 0x10);
if (!CbusFindString((PULONG)"Corollary", Bios, (LONG)0x10000))
return 0;
#endif
//
// map in the 32K (== 8 pages) of RRD RAM information @ 0xE0000,
//
Bios = (PUCHAR)HalpMapPhysicalMemory ((PVOID)RRD_RAM, 8);
if (!CbusFindString((PUCHAR)crllry_owns, Bios, (LONG)0x8000))
return 0;
//
// at this point, we are assured that it is indeed a
// Corollary architecture machine. search for our
// extended configuration tables, note we don't require
// (or even look for!) the existence of our earliest
// 'configuration' structure, ie: the 0xdeadbeef version.
// if there is no extended configuration structure,
// this must be an old rom. NO SUPPORT FOR THESE.
//
p = (PEXT_CFG_HEADER)CbusFindString((PUCHAR)RRDextsignature,
Bios, (LONG)0x8000);
//
// check for no extended configuration table: if it's not there,
// something is really wrong. we found our copyrights but not our
// machine? someone is copying us! no support for them!
//
if (!p)
return 0;
//
// 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 let the HAL deal with all the other extended configuration
// entries built by RRD.
//
do {
EntryLength = p->ext_cfg_length;
switch (p->ext_cfg_checkword) {
case EXT_ID_INFO:
Idp = (PEXT_ID_INFO)(p + 1);
break;
case EXT_CFG_OVERRIDE:
//
// reference up to 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))
return 0;
CbusGlobal = (PEXT_CFG_OVERRIDE)(p + 1);
break;
case EXT_CFG_END:
//
// If ancient C-bus box, it's not supported in MP mode
//
if (!Idp || !CbusGlobal)
return 0;
return CorollaryHalNeeded(
CbusGlobal,
Idp,
IsConfiguredMp);
default:
//
// skip unused or unrecognized configuration entries
// note that here we only care about EXT_ID_INFO as far
// as presence checking goes, but the HAL will care
// about more than just that.
//
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);
}
//
// process the tables we have built to determine whether
// the machine is a Corollary MP machine which requires
// the Corollary Windows NT HAL for full performance.
//
// We always set IsConfiguredMp for this case even if
// this machine is configured as a uniprocessor, because it
// will still see improved performance from our HAL.
//
ULONG
CorollaryHalNeeded(
IN PEXT_CFG_OVERRIDE CbusGlobal,
IN PEXT_ID_INFO p,
IN OUT PBOOLEAN IsConfiguredMp
)
{
ULONG Index;
ULONG Processors = 0;
BOOLEAN MachineSupported = FALSE;
ULONG machine;
machine = CbusGlobal->machine_type;
//
// first check global platform data. if this indicates that
// this is an early C-bus machine (which will be
// supported in uniprocessor mode only by Windows NT),
// and thus, should use the default Windows NT HAL.
//
if (machine & MACHINE_CBUS2) {
if ((CbusGlobal->supported_environments & WINDOWS_NT_R2) == 0)
return 0;
MachineSupported = TRUE;
}
if (machine & MACHINE_CBUS1_XM) {
if ((CbusGlobal->supported_environments & (WINDOWS_NT|WINDOWS_NT_R2)) == 0)
return 0;
MachineSupported = TRUE;
}
if (MachineSupported == FALSE)
return 0;
//
// then scan the table of IDs to make sure everything's ok
//
for (Index = 0; Index < MAX_CBUS_ELEMENTS; Index++, p++)
{
if (p->id == LAST_EXT_ID) {
break;
}
// check only processor elements...
if (p->pm == 0)
continue;
//
// at least the base bridge must have a
// distributed interrupt chip (because
// any CPUs without them will be disabled).
//
if (p->pel_features&(ELEMENT_HAS_APIC|ELEMENT_HAS_CBC)) {
Processors++;
}
else {
if (CbusGlobal->bootid == p->id)
return 0;
}
}
// This is an MP hal
*IsConfiguredMp = TRUE;
return 1;
}