1
0
Files
2022-09-29 17:59:04 +03:00

719 lines
18 KiB
C

/**************************************************************************
* *
* Copyright (C) 1986-1994 Silicon Graphics, Inc. *
* *
* These coded instructions, statements, and computer programs contain *
* unpublished proprietary information of Silicon Graphics, Inc., and *
* are protected by Federal copyright law. They may not be disclosed *
* to third parties or copied or duplicated in any form, in whole or *
* in part, without the prior written consent of Silicon Graphics, Inc. *
* *
**************************************************************************/
#ident "$Revision: 1.95 $"
#include <sys/types.h>
#include <sys/sbd.h>
#include <sys/param.h>
#include <sys/reg.h>
#include <sys/pda.h>
#include <sys/systm.h>
#include <sys/cpu.h>
#include <sys/sysinfo.h>
#include <sys/cmn_err.h>
#include <sys/callo.h>
#include <sys/schedctl.h>
#include <sys/invent.h>
#include <sys/cmn_err.h>
#include <sys/edt.h>
#include <sys/EVEREST/everest.h>
#include <sys/EVEREST/addrs.h>
#include <sys/EVEREST/evintr.h>
#include <sys/EVEREST/evconfig.h>
#include <sys/EVEREST/evmp.h>
#include <sys/debug.h>
#include <sys/time.h>
#include <sys/arcs/spb.h> /* ARCS System Parameter Block */
#include <sys/arcs/debug_block.h>/* ARCS debug block */
#include <sys/arcs/kerncb.h> /* ARCS printf prototype */
#include <ctype.h>
#include <sys/errno.h>
#include <sys/syssgi.h>
#include <sys/strsubr.h>
#include <sys/sema.h>
#include <sys/fpu.h>
#if SABLE
#include <sys/i8251uart.h>
#endif
void mem_init(void);
void evio_init(void);
void he_arcs_set_vectors(void);
int maxcpus = EV_MAX_CPUS;
#if IP19
short cputype = CPU_IP19;
#endif
#if IP21
short cputype = CPU_IP21;
#endif
#if IP25
short cputype = CPU_IP25;
#endif
/* processor-dependent data area */
pdaindr_t pdaindr[EV_MAX_CPUS];
/* Convert logical cpuid to physical slot */
int cpuid_to_slot[EV_MAX_CPUS];
/* Convert logical cpuid to physical cpu# on board */
int cpuid_to_cpu[EV_MAX_CPUS];
/* convert physical slot/cpu# to logical cpu id */
cpuid_t logical_cpuid[EV_MAX_SLOTS][EV_CPU_PER_BOARD];
/*
* Band-aids for a circulating program that re-writes the in-core copy of
* a system id to allow s/w licensed for one machine to run on many.
* 1. Hide ev_serial symbol by using ld -x in Makefile
* 2. Introduce a new symbol id_number for crackers to waste their time on.
* 3. Scatter the real serial number throughout the ev_serial array: Bytes from
* the real serial number are stored in the 3rd byte of every 4 in ev_serial.
* 4. Alter the real serial number to make it harder to pick out of a crash dump.
* 5. The other 3 bytes of ev_serial are filled with junk that will tend to
* make the array look more like a set of pointers to functions.
*/
static char ev_serial[SERIALNUMSIZE * 4]; /* Store system serial number here */
#define EV_SER_FUDGE 0x1b /* must be less than 0x20 for validity test to work */
#define EV_SER_BAD_VAL 0xff
#define EV_SER_BYTE_1 0x80 /* somewhere in kernel text */
#define EV_SER_BYTE_2 0x35
/*#define EV_SER_BYTE_3 real ev_serial - EV_SER_FUDGE or NULL*/
/*#define EV_SER_BYTE_4 varies*/
/* logical cpuid of master cpu */
extern cpuid_t master_procid;
extern int cachewrback; /* 1 if cache is writeback */
extern int valid_icache_reasons;
extern int valid_dcache_reasons;
/*
* Everest-specific initialization functions.
*/
#ifdef SABLE
static void
everest_sable_init()
{
/* Sable does not execute prom code, so we construct prom
* information here, using knowledge of HW config which it
* supports.
*/
int slot, cpu, slice, vid;
evreg_t cpumask;
/* Memory configuration */
#ifdef IP25
EVCFGINFO->ecfg_memsize = 65536; /* 16 MB (65536 x 256 bytes) */
#else
EVCFGINFO->ecfg_memsize = 32768; /* 8 MB (32768 x 256 bytes) */
#endif
#ifndef SABLE_HW
/* CPU configuration */
cpumask = (EV_GET_LOCAL(EV_SYSCONFIG) & EV_CPU_MASK) >> EV_CPU_SHFT;
/* Which slot is CPU in ? */
if (cpumask & 0x01)
slot = 0;
else if (cpumask & 0x04)
slot = 2;
for (cpu=0; cpu<EV_CPU_PER_BOARD; cpu++) {
slice = cpu;
if (cpu == 0) {
vid = 0;
MPCONF[vid].phys_id = (slot<<EV_SLOTNUM_SHFT) | slice;
EVCFGINFO->ecfg_board[slot].eb_type = EVCLASS_CPU;
EVCFG_CPUSTRUCT(slot, slice).cpu_vpid = vid;
EVCFG_CPUSTRUCT(slot, slice).cpu_enable = 1;
} else {
/* Mark other cpus as failing the diags */
EVCFGINFO->ecfg_board[(slot)].eb_cpu.eb_cpus[(cpu)].cpu_diagval = -1;
}
}
/*
* Kernel ASSUMES that the proms have setup the uart.
* So perform setup here so UART is usable.
* Arbitrarily pick any of the ASYNC mode for sable -- as long as
* one of the two LSB is set, uart will operate.
*/
EV_SET_LOCAL(EV_UART_CMD,
I8251_ASYNC64X|I8251_8BITS|I8251_EVENPAR|I8251_STOPB2);
/* For now we don't enable RX until we hit idle loop - it makes
* sable execute about 5 times slower, continuously checking for
* input characters.
*/
/**** EV_SET_LOCAL(EV_UART_CMD, I8251_TXENB|I8251_RXENB); ****/
EV_SET_LOCAL(EV_UART_CMD, I8251_TXENB);
/* arcs info setup */
__TV = (FirmwareVector *)PHYS_TO_K1(0x1800);
SPB->DebugBlock = (LONG *)PHYS_TO_K1(0x85fd0);
#endif
}
#endif
/*
* Probe everest hardware to find out where cpu boards are,
* and set up mappings between physical CPU IDs and logical
* CPU IDs according to PROM mappings.
*
* Some cpus may have been disabled by the PROM, but they
* may be enabled later under operator control.
*
* Returns number of cpu's, including disabled cpu's.
*/
static int
cpu_probe(void)
{
int slot, cpu;
cpuid_t cpuid, max_cpuid = 0;
#if R4000 && IP19
extern int has_250; /* flag checked in hook_exc.c */
#endif
evreg_t cpumask =
(EV_GET_SYSCONFIG() & EV_CPU_MASK) >> EV_CPU_SHFT;
for (slot = 0; slot < EV_MAX_SLOTS; slot++) {
if (cpumask & 1) { /* Found a slot with a processor board */
for (cpu=0; cpu<EV_CPU_PER_BOARD; cpu++) {
if (EVCFG_CPUDIAGVAL(slot,cpu) ==
EVDIAG_NOTFOUND) {
logical_cpuid[slot][cpu] = EV_CPU_NONE;
continue;
}
cpuid = EVCFG_CPUID(slot,cpu);
#if LARGE_CPU_COUNT_EVEREST
/* Modify EVCFG structure so that odd numbered
* cpus are numbered as a negative offset from
* EV_MAXCPUS (i.e. cpu 1 == cpu 127, 3 == 125)
*/
if (cpuid & 0x01) {
cpuid = EV_MAX_CPUS - cpuid;
EVCFG_CPUSTRUCT(slot, 1).cpu_vpid =
cpuid;
}
#endif
cpuid_to_slot[cpuid] = slot;
cpuid_to_cpu[cpuid] = cpu;
logical_cpuid[slot][cpu] = cpuid;
if (cpuid > max_cpuid)
max_cpuid = cpuid;
#if R4000 && IP19
/* Note any 250MHz modules present */
if ((EVCFG_CPUSPEED(slot, cpu) * 2) == 250)
has_250++;
#endif
}
} else { /* No processor board in this slot */
for (cpu=0; cpu<EV_CPU_PER_BOARD; cpu++)
logical_cpuid[slot][cpu] = EV_CPU_NONE;
}
cpumask = cpumask >> 1;
}
return(max_cpuid+1);
}
extern void cpuintr(eframe_t*, void *);
extern void groupintr(eframe_t*, void *);
extern void tlbintr(eframe_t*, void *);
extern void slave_loop();
extern void nvram_init(void);
/*
* This array is when start_slave_loop is called by the master CPU
* during boot. A CPU is associated with an index using the same
* mapping as MPCONF array. When a CPU has entered the kernel slave
* loop and is ready to continue, it sets its entry to 1. This is used
* as a positive ack to indicate the IO4 image is no longer required.
*/
char slave_loop_ready[EV_MAX_CPUS] = {0}; /* Force part of data segment */
#define READYTIMEOUT 50000
/* Temp copy of system id number - crackers can play with this one all they like */
char id_number[SERIALNUMSIZE + 1] = {0};
/*
* mlreset - very early machine reset - at this point NO interrupts have been
* enabled; nor is memory, tlb, p0, etc setup
*/
void
mlreset(int first)
{
int i, t, bad_serial = 0, saw_null = 0;
if (first == 0) {
#ifdef SABLE
everest_sable_init();
#endif
/*
* Only the "master" or "first" processor does this
* global initialization.
*/
/* probe for all CPUs */
maxcpus = cpu_probe();
master_procid = getcpuid();
/*
* Wait for all processors to indicate they are ready. We
* do not print any messages at this point, we do that later
* in allowboot().
*/
#ifndef SABLE
for (t = READYTIMEOUT*maxcpus, i = 0; i < maxcpus; i++) {
if (cpu_enabled(i)) {
while (!slave_loop_ready[i] && t) {
t--;
DELAY(1);
}
}
}
#endif /* SABLE */
/* init interrupts */
evintr_init();
/* init memory subsystem */
mem_init();
/* setup IO subsystem */
evio_init();
/* init nvram spinlock */
nvram_init();
/*
* if _check_dbg() did not turn kdebug on, turn it off here.
*/
if (kdebug == -1)
kdebug = 0;
#if R4000
/*
* cachecolormask is set from the bits in a vaddr/paddr
* which the r4k looks at to determine if a VCE should
* be raised.
* Despite what some documents may say, these are
* bits 12..14
* These are shifted down to give a value between 0..7
* NOTE: VCE not an issue for TFP.
*/
cachecolormask = R4K_MAXPCACHESIZE/NBPP - 1;
#endif
cachewrback = 0; /* No writeback (I/O coherent) */
valid_icache_reasons &= ~CACH_IO_COHERENCY;
valid_dcache_reasons &= ~CACH_IO_COHERENCY;
#if TFP
/* TFP dcache is write-through, so no reason to flush
* the dcache for ICACHE_COHERENCY (though icache needs
* flushing).
*/
valid_dcache_reasons &= ~(CACH_ICACHE_COHERENCY|CACH_AVOID_VCES);
valid_icache_reasons &= ~CACH_AVOID_VCES;
#endif
#if R10000
valid_dcache_reasons &= ~CACH_AVOID_VCES;
valid_icache_reasons &= ~CACH_AVOID_VCES;
#endif
evintr_connect(0, EVINTR_LEVEL_CPUACTION, SPLMAX,
EVINTR_DEST_CPUACTION, cpuintr, 0);
evintr_connect(0, EVINTR_LEVEL_GROUPACTION, SPLMAX,
EVINTR_DEST_GROUPACTION, groupintr, 0);
#if EVINTR_LEVEL_TLB != EVINTR_LEVEL_CPUACTION
/* This should be executed on all systems except MUTLIKERNEL
* CELL where we don't actually use a different level.
* On that system we still use CPUACTION.
* NOTE: Could use SPLTLB except our EVINTR_LEVEL is
* greater than cpuintr which uses SPLMAX.
*/
evintr_connect(0, EVINTR_LEVEL_TLB, SPLMAX,
0, tlbintr, 0);
#endif
/*
* Since we've wiped out memory at this point, we
* need to reset the ARCS vector table so that it
* points to appropriate functions in the kernel
* itself. In this way, we can maintain the ARCS
* vector table conventions without having to actually
* keep redundant PROM code in memory.
*/
he_arcs_set_vectors();
/*
* Enable all Everest local interrupts on master.
*/
EV_SET_LOCAL(EV_ILE, /* EV_EBUSINT_MASK */
EV_CMPINT_MASK |
EV_UARTINT_MASK |
EV_ERTOINT_MASK |
EV_WGINT_MASK);
/* Clear Interrupt Group Mask */
EV_SET_LOCAL(EV_IGRMASK, 0);
/* Copy in the system serial number */
/* bcopy((char *)EVCFGINFO->ecfg_snum, ev_serial, SERIALNUMSIZE);*/
bcopy((char *)EVCFGINFO->ecfg_snum, id_number, SERIALNUMSIZE);
/* Obfuscate it */
for (i = 0; i < SERIALNUMSIZE; i++) {
t = i << 2;
ev_serial[t] = EV_SER_BYTE_1;
ev_serial[t+1] = EV_SER_BYTE_2;
/* NULL is special - terminates valid bytestring */
if (id_number[i] == '\0') {
ev_serial[t+2] = '\0';
saw_null = 1;
} else {
/* chars < 0x20 or > 0x7f are bad unless after a NULL */
if (!saw_null
&& (((id_number[i] & 0xe0) == 0) || (id_number[i] & 0x80))) {
bad_serial = 1;
}
/* Make it harder to spot the real data in a dump */
ev_serial[t+2] = id_number[i] - EV_SER_FUDGE;
}
ev_serial[t+3] = (id_number[i] + id_number[i+1]) & 0xfc;
}
if (bad_serial || !saw_null) {
ev_serial[1] = EV_SER_BAD_VAL; /* force ENODEV on subsequent reads */
}
} else {
/*
* This code is performed ONLY by slave processors.
*/
/*
* Enable Everest local interrupts on slaves.
* (Leave CCUART interrupt disabled.)
*/
EV_SET_LOCAL(EV_ILE, /* EV_EBUSINT_MASK */
EV_CMPINT_MASK |
EV_ERTOINT_MASK |
EV_WGINT_MASK);
/* Clear Interrupt Group Mask */
EV_SET_LOCAL(EV_IGRMASK, 0);
}
/*
* ALL processors do this initialization
*/
#if !SABLE /* Was !SABLE_RTL */
/* RTL simulator inits both the tlbs & the cache for us */
flush_tlb(TLBFLUSH_NONPDA); /* flush all BUT pda */
flush_cache(); /* flush all caches */
#endif
}
/*
* Allow interrupts to reach cpus.
*/
void
allowintrs(void)
{
evreg_t ile;
extern int ducw_intrs_enabled;
ile = EV_GET_LOCAL(EV_ILE);
EV_SET_LOCAL(EV_ILE, ile | EV_EBUSINT_MASK);
ducw_intrs_enabled = 1;
}
/*
* Return the logical cpu ID for the calling processor.
* Usually, the value private.p_cpuid (accessed via the
* "cpuid()" macro is sufficient for this purpose; however,
* this routine can be called early on, before the pda is
* fully set up.
*/
cpuid_t
getcpuid(void)
{
register evreg_t slotproc;
register int slot;
register int proc;
#if SABLE_RTL
return(0);
#endif /* SABLE_RTL */
slotproc = EV_GET_LOCAL(EV_SPNUM);
slot = (slotproc & EV_SLOTNUM_MASK) >> EV_SLOTNUM_SHFT;
proc = (slotproc & EV_PROCNUM_MASK) >> EV_PROCNUM_SHFT;
return(logical_cpuid[slot][proc]);
}
/*
* On EVEREST, unix overlays the prom's bss area. Therefore, only
* those prom entry points that do not use prom bss or are
* destructive (i.e. reboot) may be called. There is however,
* a period of time before the prom bss is overlayed in which
* the prom may be called. After unix wipes out the prom bss
* and before the console is inited, there is a very small window
* in which calls to dprintf will cause the system to hang.
*
* If symmon is being used, it will plug a pointer to its printf
* routine into the debug block which the kernel will then use
* for dprintfs. The advantage of this is that the kp command
* will not interfere with the kernel's own print buffers.
*
*/
# define ARGS a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15
void
dprintf(fmt,ARGS)
char *fmt;
__psint_t ARGS;
{
/*
* Check for presence of symmon
* Check the SPB magic number - there are several things
* going on here that make this check important. The 64
* bit IP19 kernel is started by a 32 bit prom, which builds
* a 32 bit spb. However, symmon, when initialized, rebuilds
* a 64 bit spb. In checking the magic number here, we are
* looking for the magic number in a 64 bit field - if that
* is present we assume there is a 64-bit symmon out there.
*/
if (SPB->Signature == SPBMAGIC &&
SPB->DebugBlock &&
((db_t *)SPB->DebugBlock)->db_magic == DB_MAGIC &&
((db_t *)SPB->DebugBlock)->db_printf)
(*((db_t *)SPB->DebugBlock)->db_printf)(fmt, ARGS);
else
/*
* cn_is_inited() implies that PROM bss has been wiped out
*/
if (cn_is_inited())
cmn_err(CE_CONT,fmt,ARGS);
else
/*
* try printing through the prom
*/
arcs_printf (fmt,ARGS);
}
/*
* fp_find - probe for floating point chip
*/
void
fp_find(void)
{
private.p_fputype_word = get_fpc_irr();
}
/*
* fp chip initialization
*/
void
fp_init(void)
{
set_fpc_csr(0);
}
/*
* get_except_norm
*
* return address of exception handler for all exceptions other
* then utlbmiss.
*/
inst_t *
get_except_norm(void)
{
extern inst_t exception[];
return exception;
}
int
cpuboard(void)
{
#if R4000
ASSERT(cputype == CPU_IP19);
return(INV_IP19BOARD);
#endif
#if TFP
ASSERT(cputype == CPU_IP21);
return(INV_IP21BOARD);
#endif
#if R10000
ASSERT(cputype == CPU_IP25);
return(INV_IP25BOARD);
#endif
}
/*
* add_ioboard
* Adds EVEREST-specific I/O information to the hardware inventory
* structure. We add the UARTS here because the duart driver is
* initialized before the dynamic memory allocater is.
*/
void
add_ioboard(void)
{
extern int ev_num_serialports;
int slot, my_slot;
evbrdinfo_t *brd;
int serial_found, ether_found;
int num_serial = 0;
ibus_t *ibus;
#if defined(MULTIKERNEL)
/* only the golden cell has I/O bpoards */
if (evmk_cellid != evmk_golden_cellid)
return;
#endif /* MULTIKERNEL */
/* Add the DUART information to the hardware inventory */
add_to_inventory(INV_SERIAL, INV_EPC_SERIAL, 0, 0, ev_num_serialports);
/* Add the I/O boards to the hardware inventory */
for (slot = EV_MAX_SLOTS; slot >= 0; slot--) {
brd = &(EVCFGINFO->ecfg_board[slot]);
/* Skip non-I/O boards */
if ((brd->eb_type & EVCLASS_MASK) != EVCLASS_IO)
continue;
add_to_inventory(INV_IOBD, INV_EVIO, 0, (char) slot,
brd->eb_type);
/* Make allowances for the master IO4 */
if (BOARD(slot)->eb_io.eb_winnum == 1)
my_slot = 0;
else
my_slot = slot;
#ifndef SABLE
/* Check to see if the serial ports or ethernet for
* this board are configured.
*/
ibus = ibus_adapters;
while (ibus->ibus_module) {
if ((ibus->ibus_adap >> IBUS_SLOTSHFT) == my_slot) {
if (ibus->ibus_module == EPC_SERIAL) {
serial_found++;
num_serial++;
}
if (ibus->ibus_module == EPC_ETHER)
ether_found++;
}
ibus++;
}
#endif
if (!serial_found && (num_serial < 4))
cmn_err(CE_NOTE,
"No system file entry for the IO4 slot %d serial ports was found.\n"
"Consult the serial(7) man page for information on configuring\n"
"these ports.\n", slot);
if (!ether_found)
cmn_err(CE_NOTE,
"No system file entry for the IO4 slot %d ethernet port was found.\n"
"Consult the ethernet(7) man page for information on configuring\n"
"this port.\n", slot);
serial_found = 0;
ether_found = 0;
}
}
/*
* timer_freq is the frequency of the 32 bit counter timestamping source.
* timer_high_unit is the XXX
* Routines that references these two are not called as often as
* other timer primitives. This is a compromise to keep the code
* well contained.
* Must be called early, before main().
*/
void
timestamp_init(void)
{
timer_freq = CYCLE_PER_SEC; /* RTC time source */
timer_unit = NSEC_PER_SEC/timer_freq;
timer_high_unit = timer_freq; /* don't change this */
timer_maxsec = TIMER_MAX/timer_freq;
}
/*
* Pass back the serial number associated with the system ID in the
* system controller's NVRAM. Return zero if the ID has been set to an
* appropriate string else zero it out and return ENODEV as clover2.c does.
* There really isn't a more appropriate already defined error number.
*/
int
getsysid(char *hostident)
{
int i;
char c;
/*
* serial number is up to 10 bytes long on Everest. Left justify
* in memory passed in... Zero out the balance.
*/
i = 0;
bzero(hostident, MAXSYSIDSIZE);
if (ev_serial[1] == EV_SER_BAD_VAL) {
return ENODEV;
}
/* Pull out the interesting bytes and reconstruct the serial number */
for (i = 0; i <= SERIALNUMSIZE; i++) {
if (i == SERIALNUMSIZE) {
return ENODEV;
}
c = ev_serial[(i << 2) + 2];
if (c == '\0') {
hostident[i] = c;
break;
}
hostident[i] = c + EV_SER_FUDGE;
}
return 0;
}