ab27ec61cb055aabe7b2d7577f69c41d75c2f7a7
* Copyright (c) 1988 University of Utah.
* Copyright (c) 1992 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* the Systems Programming Group of the University of Utah Computer
* Science Department, The Mach Operating System project at
* Carnegie-Mellon University and Ralph Campbell.
* %sccs.include.redist.c%
* @(#)machdep.c 7.14 (Berkeley) %G%
/* from: Utah $Hdr: machdep.c 1.63 91/04/24$ */
#include <sys/signalvar.h>
#include <machine/dc7085cons.h>
#include <pmax/stand/dec_prom.h>
#include <pmax/dev/device.h>
#include <pmax/dev/sccreg.h>
#include <pmax/dev/ascreg.h>
#include <pmax/pmax/clockreg.h>
#include <pmax/pmax/kn01.h>
#include <pmax/pmax/kn02.h>
#include <pmax/pmax/kmin.h>
#include <pmax/pmax/maxine.h>
#include <pmax/pmax/kn03.h>
#include <pmax/pmax/asic.h>
#include <pmax/pmax/turbochannel.h>
#include <pmax/pmax/pmaxtype.h>
#include <pmax/pmax/cons.h>
extern int dcGetc(), dcparam();
extern int dtopKBDGetc();
extern int sccGetc(), sccparam();
extern struct consdev cn_tab
;
/* Will scan from max to min, inclusive */
static int tc_max_slot
= KN02_TC_MAX
;
static int tc_min_slot
= KN02_TC_MIN
;
static u_int tc_slot_phys_base
[TC_MAX_SLOTS
] = {
/* use 3max for default values */
KN02_PHYS_TC_0_START
, KN02_PHYS_TC_1_START
,
KN02_PHYS_TC_2_START
, KN02_PHYS_TC_3_START
,
KN02_PHYS_TC_4_START
, KN02_PHYS_TC_5_START
,
KN02_PHYS_TC_6_START
, KN02_PHYS_TC_7_START
* Declare these as initialized data so we can patch them.
int msgbufmapped
= 0; /* set when safe to use msgbuf */
int maxmem
; /* max memory per process */
int physmem
; /* max supported memory, changes to actual */
int pmax_boardtype
; /* Mother board type */
u_long le_iomem
; /* 128K for lance chip via. ASIC */
u_long asc_iomem
; /* and 7 * 8K buffers for the scsi */
u_long asic_base
; /* Base address of I/O asic */
const struct callback
*callv
; /* pointer to PROM entry points */
void (*tc_enable_interrupt
)();
extern int (*pmax_hardware_intr
)();
void pmax_slot_hand_fill();
int kn02_intr(), kmin_intr(), xine_intr(), pmax_intr();
extern int Mach_spl0(), Mach_spl1(), Mach_spl2(), Mach_spl3(), splhigh();
int (*Mach_splnet
)() = splhigh
;
int (*Mach_splbio
)() = splhigh
;
int (*Mach_splimp
)() = splhigh
;
int (*Mach_spltty
)() = splhigh
;
int (*Mach_splclock
)() = splhigh
;
int (*Mach_splstatclock
)() = splhigh
;
void (*tc_slot_hand_fill
)();
extern volatile struct chiptime
*Mach_clock_addr
;
u_long kmin_tc3_imask
, xine_tc3_imask
;
tc_option_t tc_slot_info
[TC_MAX_LOGICAL_SLOTS
];
extern void RemconsInit();
void kn02_enable_intr(), kn02_slot_hand_fill(),
kmin_enable_intr(), kmin_slot_hand_fill(),
xine_enable_intr(), xine_slot_hand_fill(),
void kn03_enable_intr(), kn03_slot_hand_fill();
* safepri is a safe priority for sleep to set for a spin-wait
* during autoconfiguration or after a panic.
int safepri
= PSL_LOWIPL
;
struct proc nullproc
; /* for use by swtch_exit() */
* Do all the stuff that locore normally does before calling main().
* Process arguments passed to us by the prom monitor.
* Return the first page address following the system.
mach_init(argc
, argv
, code
, cv
)
const struct callback
*cv
;
register unsigned firstaddr
;
extern char edata
[], end
[];
extern char MachUTLBMiss
[], MachUTLBMissEnd
[];
extern char MachException
[], MachExceptionEnd
[];
extern char *pmap_attributes
;
/* clear the BSS segment */
v
= (caddr_t
)pmax_round_page(end
);
/* check for direct boot from DS5000 PROM */
if (argc
> 0 && strcmp(argv
[0], "boot") == 0) {
/* look at argv[0] and compute bootdev */
* Look at arguments passed to us and compute boothowto.
boothowto
= RB_SINGLE
| RB_ASKNAME
;
for (i
= 1; i
< argc
; i
++) {
for (cp
= argv
[i
]; *cp
; cp
++) {
case 'd': /* use compiled in default root */
boothowto
|= RB_DFLTROOT
;
case 'm': /* mini root present in memory */
boothowto
|= RB_MINIROOT
;
case 'n': /* ask for names */
case 'N': /* don't ask for names */
boothowto
&= ~RB_ASKNAME
;
* Check to see if a mini-root was loaded into memory. It resides
* at the start of the next page just after the end of BSS.
if (boothowto
& RB_MINIROOT
)
v
+= mfs_initminiroot(v
);
* Init mapping for u page(s) for proc[0], pm_tlbpid 1.
curproc
->p_addr
= proc0paddr
= (struct user
*)v
;
curproc
->p_md
.md_regs
= proc0paddr
->u_pcb
.pcb_regs
;
firstaddr
= MACH_CACHED_TO_PHYS(v
);
for (i
= 0; i
< UPAGES
; i
++) {
(UADDR
+ (i
<< PGSHIFT
)) | (1 << VMMACH_TLB_PID_SHIFT
),
curproc
->p_md
.md_upte
[i
] = firstaddr
| PG_V
| PG_M
);
* init nullproc for swtch_exit().
* init mapping for u page(s), pm_tlbpid 0
* This could be used for an idle process.
nullproc
.p_addr
= (struct user
*)v
;
nullproc
.p_md
.md_regs
= ((struct user
*)v
)->u_pcb
.pcb_regs
;
for (i
= 0; i
< UPAGES
; i
++) {
nullproc
.p_md
.md_upte
[i
] = firstaddr
| PG_V
| PG_M
;
/* clear pages for u areas */
* Copy down exception vector code.
if (MachUTLBMissEnd
- MachUTLBMiss
> 0x80)
panic("startup: UTLB code too large");
bcopy(MachUTLBMiss
, (char *)MACH_UTLB_MISS_EXC_VEC
,
MachUTLBMissEnd
- MachUTLBMiss
);
bcopy(MachException
, (char *)MACH_GEN_EXC_VEC
,
MachExceptionEnd
- MachException
);
* Clear out the I and D caches.
* Determine what model of computer we are running on.
if (code
== DEC_PROM_MAGIC
) {
if (cp
= (*callv
->getenv
)("systype"))
/* check for MIPS based platform */
if (((i
>> 24) & 0xFF) != 0x82) {
printf("Unknown System type '%s' 0x%x\n", cp
, i
);
boot(RB_HALT
| RB_NOSYNC
);
/* check what model platform we are running on */
pmax_boardtype
= ((i
>> 16) & 0xff);
switch (pmax_boardtype
) {
case DS_PMAX
: /* DS3100 Pmax */
* Set up interrupt handling and I/O addresses.
pmax_hardware_intr
= pmax_intr
;
Mach_splclock
= Mach_spl3
;
Mach_splstatclock
= Mach_spl3
;
Mach_clock_addr
= (volatile struct chiptime
*)
MACH_PHYS_TO_UNCACHED(KN01_SYS_CLOCK
);
case DS_3MAX
: /* DS5000/200 3max */
(volatile int *)MACH_PHYS_TO_UNCACHED(KN02_SYS_CSR
);
/* disable all TURBOchannel interrupts */
*csr_addr
= i
& ~(KN02_CSR_WRESERVED
| 0xFF);
tc_slot_hand_fill
= kn02_slot_hand_fill
;
pmax_hardware_intr
= kn02_intr
;
tc_enable_interrupt
= kn02_enable_intr
;
Mach_splclock
= Mach_spl1
;
Mach_splstatclock
= Mach_spl1
;
Mach_clock_addr
= (volatile struct chiptime
*)
MACH_PHYS_TO_UNCACHED(KN02_SYS_CLOCK
);
* Probe the TURBOchannel to see what controllers are present.
/* clear any memory errors from probes */
*(unsigned *)MACH_PHYS_TO_UNCACHED(KN02_SYS_ERRADR
) = 0;
case DS_3MIN
: /* DS5000/1xx 3min */
tc_max_slot
= KMIN_TC_MAX
;
tc_min_slot
= KMIN_TC_MIN
;
tc_slot_phys_base
[0] = KMIN_PHYS_TC_0_START
;
tc_slot_phys_base
[1] = KMIN_PHYS_TC_1_START
;
tc_slot_phys_base
[2] = KMIN_PHYS_TC_2_START
;
asic_base
= MACH_PHYS_TO_UNCACHED(KMIN_SYS_ASIC
);
tc_slot_hand_fill
= kmin_slot_hand_fill
;
pmax_hardware_intr
= kmin_intr
;
tc_enable_interrupt
= kmin_enable_intr
;
* Since all the motherboard interrupts come through the
* I/O ASIC, it has to be turned off for all the spls and
* since we don't know what kinds of devices are in the
* turbochannel option slots, just splhigh().
Mach_splstatclock
= splhigh
;
Mach_clock_addr
= (volatile struct chiptime
*)
MACH_PHYS_TO_UNCACHED(KMIN_SYS_CLOCK
);
* Probe the TURBOchannel to see what controllers are present.
*(u_int
*)ASIC_REG_IMSK(asic_base
) = KMIN_IM0
;
*(u_int
*)ASIC_REG_INTR(asic_base
) = 0;
/* clear any memory errors from probes */
*(unsigned *)MACH_PHYS_TO_UNCACHED(KMIN_REG_TIMEOUT
) = 0;
case DS_MAXINE
: /* DS5000/xx maxine */
tc_max_slot
= XINE_TC_MAX
;
tc_min_slot
= XINE_TC_MIN
;
tc_slot_phys_base
[0] = XINE_PHYS_TC_0_START
;
tc_slot_phys_base
[1] = XINE_PHYS_TC_1_START
;
asic_base
= MACH_PHYS_TO_UNCACHED(XINE_SYS_ASIC
);
tc_slot_hand_fill
= xine_slot_hand_fill
;
pmax_hardware_intr
= xine_intr
;
tc_enable_interrupt
= xine_enable_intr
;
Mach_splclock
= Mach_spl1
;
Mach_splstatclock
= Mach_spl1
;
Mach_clock_addr
= (volatile struct chiptime
*)
MACH_PHYS_TO_UNCACHED(XINE_SYS_CLOCK
);
* Probe the TURBOchannel to see what controllers are present.
*(u_int
*)ASIC_REG_IMSK(asic_base
) = XINE_IM0
;
*(u_int
*)ASIC_REG_INTR(asic_base
) = 0;
/* clear any memory errors from probes */
*(unsigned *)MACH_PHYS_TO_UNCACHED(XINE_REG_TIMEOUT
) = 0;
case DS_3MAXPLUS
: /* DS5000/240 3max+ UNTESTED!! */
tc_max_slot
= KN03_TC_MAX
;
tc_min_slot
= KN03_TC_MIN
;
tc_slot_phys_base
[0] = KN03_PHYS_TC_0_START
;
tc_slot_phys_base
[1] = KN03_PHYS_TC_1_START
;
tc_slot_phys_base
[2] = KN03_PHYS_TC_2_START
;
asic_base
= MACH_PHYS_TO_UNCACHED(KN03_SYS_ASIC
);
tc_slot_hand_fill
= kn03_slot_hand_fill
;
pmax_hardware_intr
= kn03_intr
;
tc_enable_interrupt
= kn03_enable_intr
;
Mach_splclock
= Mach_spl1
;
Mach_splstatclock
= Mach_spl1
;
Mach_clock_addr
= (volatile struct chiptime
*)
MACH_PHYS_TO_UNCACHED(KN03_SYS_CLOCK
);
* Probe the TURBOchannel to see what controllers are present.
*(u_int
*)ASIC_REG_IMSK(asic_base
) = KN03_IM0
;
*(u_int
*)ASIC_REG_INTR(asic_base
) = 0;
/* clear any memory errors from probes */
*(unsigned *)MACH_PHYS_TO_UNCACHED(KN03_SYS_ERRADR
) = 0;
printf("kernel not configured for systype 0x%x\n", i
);
boot(RB_HALT
| RB_NOSYNC
);
* Find out how much memory is available.
physmem
= btoc(v
- KERNBASE
);
cp
= (char *)MACH_PHYS_TO_UNCACHED(physmem
<< PGSHIFT
);
while (cp
< (char *)MACH_MAX_MEM_ADDR
) {
* Data will persist on the bus if we read it right
* away. Have to be tricky here.
((int *)cp
)[4] = 0x5a5a5a5a;
if (*(int *)cp
!= 0xa5a5a5a5)
* Grab 128K at the top of physical memory for the lance chip
* on machines where it does dma through the I/O ASIC.
* It must be physically contiguous and aligned on a 128K boundary.
if (pmax_boardtype
== DS_3MIN
|| pmax_boardtype
== DS_MAXINE
||
pmax_boardtype
== DS_3MAXPLUS
) {
maxmem
-= btoc(128 * 1024);
le_iomem
= (maxmem
<< PGSHIFT
);
* Ditto for the scsi chip. There is probably a way to make asc.c
* do dma without these buffers, but it would require major
* re-engineering of the asc driver.
* They must be 8K in size and page aligned.
if (pmax_boardtype
== DS_3MIN
|| pmax_boardtype
== DS_MAXINE
||
pmax_boardtype
== DS_3MAXPLUS
) {
maxmem
-= btoc(ASC_NCMD
* 8192);
asc_iomem
= (maxmem
<< PGSHIFT
);
* Initialize error message buffer (at end of core).
maxmem
-= btoc(sizeof (struct msgbuf
));
msgbufp
= (struct msgbuf
*)(MACH_PHYS_TO_CACHED(maxmem
<< PGSHIFT
));
* Allocate space for system data structures.
* The first available kernel virtual address is in "v".
* As pages of kernel virtual memory are allocated, "v" is incremented.
* These data structures are allocated here instead of cpu_startup()
* because physical memory is directly addressable. We don't have
* to map these into virtual address space.
#define valloc(name, type, num) \
(name) = (type *)v; v = (caddr_t)((name)+(num))
#define valloclim(name, type, num, lim) \
(name) = (type *)v; v = (caddr_t)((lim) = ((name)+(num)))
valloc(cfree
, struct cblock
, nclist
);
valloc(callout
, struct callout
, ncallout
);
valloc(swapmap
, struct map
, nswapmap
= maxproc
* 2);
valloc(shmsegs
, struct shmid_ds
, shminfo
.shmmni
);
/* this is allocated here just to save a few bytes */
valloc(pmap_attributes
, char, physmem
);
* Determine how many buffers to allocate.
* We allocate more buffer space than the BSD standard of
* using 10% of memory for the first 2 Meg, 5% of remaining.
* We just allocate a flat 10%. Insure a minimum of 16 buffers.
* We allocate 1/2 as many swap buffer headers as file i/o buffers.
bufpages
= physmem
/ 10 / CLSIZE
;
nswbuf
= (nbuf
/ 2) &~ 1; /* force even */
nswbuf
= 256; /* sanity */
valloc(swbuf
, struct buf
, nswbuf
);
valloc(buf
, struct buf
, nbuf
);
* Clear allocated memory.
v
= (caddr_t
)pmax_round_page(v
);
* Initialize the virtual memory system.
pmap_bootstrap((vm_offset_t
)MACH_CACHED_TO_PHYS(v
));
* Console initialization: called early on from main,
* before vm init or startup. Do enough configuration
* to choose and initialize a console.
* First get the "osconsole" environment variable.
oscon
= (*callv
->getenv
)("osconsole");
if (oscon
&& *oscon
>= '0' && *oscon
<= '9') {
else if (cn_tab
.cn_screen
&&
*oscon
>= '0' && *oscon
<= '9') {
if (pmax_boardtype
== DS_PMAX
&& kbd
== 1)
* First try the keyboard/crt cases then fall through to the
switch (pmax_boardtype
) {
cn_tab
.cn_dev
= makedev(DCDEV
, DCKBD_PORT
);
cn_tab
.cn_getc
= KBDGetc
;
cn_tab
.cn_kbdgetc
= dcGetc
;
cn_tab
.cn_dev
= makedev(DTOPDEV
, 0);
cn_tab
.cn_getc
= dtopKBDGetc
;
if (crt
== 3 && xcfbinit()) {
cn_tab
.cn_dev
= makedev(DCDEV
, DCKBD_PORT
);
cn_tab
.cn_getc
= KBDGetc
;
cn_tab
.cn_kbdgetc
= dcGetc
;
cn_tab
.cn_dev
= makedev(SCCDEV
, SCCKBD_PORT
);
cn_tab
.cn_getc
= KBDGetc
;
cn_tab
.cn_kbdgetc
= sccGetc
;
* Check for a suitable turbochannel frame buffer.
if (tc_slot_info
[crt
].driver_name
) {
if (strcmp(tc_slot_info
[crt
].driver_name
, "mfb") == 0 &&
mfbinit(tc_slot_info
[crt
].k1seg_address
)) {
if (strcmp(tc_slot_info
[crt
].driver_name
, "cfb") == 0 &&
cfbinit(tc_slot_info
[crt
].k1seg_address
)) {
printf("crt: %s not supported as console device\n",
tc_slot_info
[crt
].driver_name
);
printf("No crt console device in slot %d\n", crt
);
* Configure a serial port as a remote console.
switch (pmax_boardtype
) {
cn_tab
.cn_dev
= makedev(DCDEV
, DCCOMM_PORT
);
cn_tab
.cn_dev
= makedev(DCDEV
, DCPRINTER_PORT
);
cn_tab
.cn_dev
= makedev(DCDEV
, DCPRINTER_PORT
);
cn_tab
.cn_dev
= makedev(SCCDEV
, SCCCOMM3_PORT
);
cn_tab
.cn_getc
= sccGetc
;
cn_tab
.cn_putc
= sccPutc
;
cn_tab
.cn_dev
= makedev(SCCDEV
, SCCCOMM2_PORT
);
cn_tab
.cn_getc
= sccGetc
;
cn_tab
.cn_putc
= sccPutc
;
if (cn_tab
.cn_dev
== NODEV
)
printf("Can't configure console!\n");
* cpu_startup: allocate memory for variable-sized tables,
* initialize cpu, and do autoconfiguration.
extern struct map
*useriomap
;
int opmapdebug
= pmapdebug
;
vm_offset_t minaddr
, maxaddr
;
* Good {morning,afternoon,evening,night}.
printf("real mem = %d\n", ctob(physmem
));
* Allocate virtual address space for file I/O buffers.
* Note they are different than the array of headers, 'buf',
* and usually occupy more virtual memory than physical.
buffer_map
= kmem_suballoc(kernel_map
, (vm_offset_t
*)&buffers
,
minaddr
= (vm_offset_t
)buffers
;
if (vm_map_find(buffer_map
, vm_object_allocate(size
), (vm_offset_t
)0,
&minaddr
, size
, FALSE
) != KERN_SUCCESS
)
panic("startup: cannot allocate buffers");
residual
= bufpages
% nbuf
;
for (i
= 0; i
< nbuf
; i
++) {
* First <residual> buffers get (base+1) physical pages
* allocated for them. The rest get (base) physical pages.
* The rest of each buffer occupies virtual space,
* but has no physical memory allocated for it.
curbuf
= (vm_offset_t
)buffers
+ i
* MAXBSIZE
;
curbufsize
= CLBYTES
* (i
< residual
? base
+1 : base
);
vm_map_pageable(buffer_map
, curbuf
, curbuf
+curbufsize
, FALSE
);
vm_map_simplify(buffer_map
, curbuf
);
* Allocate a submap for exec arguments. This map effectively
* limits the number of processes exec'ing at any time.
exec_map
= kmem_suballoc(kernel_map
, &minaddr
, &maxaddr
,
* Allocate a submap for physio
phys_map
= kmem_suballoc(kernel_map
, &minaddr
, &maxaddr
,
* Finally, allocate mbuf pool. Since mclrefcnt is an off-size
* we use the more space efficient malloc in place of kmem_alloc.
mclrefcnt
= (char *)malloc(NMBCLUSTERS
+CLBYTES
/MCLBYTES
,
bzero(mclrefcnt
, NMBCLUSTERS
+CLBYTES
/MCLBYTES
);
mb_map
= kmem_suballoc(kernel_map
, (vm_offset_t
*)&mbutl
, &maxaddr
,
for (i
= 1; i
< ncallout
; i
++)
callout
[i
-1].c_next
= &callout
[i
];
callout
[i
-1].c_next
= NULL
;
printf("avail mem = %d\n", ptoa(cnt
.v_free_count
));
printf("using %d buffers containing %d bytes of memory\n",
nbuf
, bufpages
* CLBYTES
);
* Set up CPU-specific registers, cache, etc.
* Set up buffers, so they can be used to read disk labels.
* Clear all registers except sp, pc.
setregs(p
, entry
, retval
)
int sp
= p
->p_md
.md_regs
[SP
];
extern struct proc
*machFPCurProcPtr
;
bzero((caddr_t
)p
->p_md
.md_regs
, (FSR
+ 1) * sizeof(int));
p
->p_md
.md_regs
[SP
] = sp
;
p
->p_md
.md_regs
[PC
] = entry
& ~3;
p
->p_md
.md_regs
[PS
] = PSL_USERSET
;
p
->p_md
.md_flags
& ~MDP_FPUSED
;
if (machFPCurProcPtr
== p
)
machFPCurProcPtr
= (struct proc
*)0;
* WARNING: code in locore.s assumes the layout shown for sf_signum
* thru sf_handler so... don't screw with them!
int sf_signum
; /* signo for handler */
int sf_code
; /* additional info for handler */
struct sigcontext
*sf_scp
; /* context ptr for handler */
sig_t sf_handler
; /* handler addr for u_sigc */
struct sigcontext sf_sc
; /* actual context */
* Send an interrupt to process.
sendsig(catcher
, sig
, mask
, code
)
register struct proc
*p
= curproc
;
register struct sigframe
*fp
;
register struct sigacts
*psp
= p
->p_sigacts
;
extern char sigcode
[], esigcode
[];
oonstack
= psp
->ps_sigstk
.ss_flags
& SA_ONSTACK
;
* Allocate and validate space for the signal handler
* context. Note that if the stack is in data space, the
* call to grow() is a nop, and the copyout()
* will fail if the process has not already allocated
* the space with a `brk'.
fsize
= sizeof(struct sigframe
);
if ((psp
->ps_flags
& SAS_ALTSTACK
) &&
(psp
->ps_sigstk
.ss_flags
& SA_ONSTACK
) == 0 &&
(psp
->ps_sigonstack
& sigmask(sig
))) {
fp
= (struct sigframe
*)(psp
->ps_sigstk
.ss_base
+
psp
->ps_sigstk
.ss_size
- fsize
);
psp
->ps_sigstk
.ss_flags
|= SA_ONSTACK
;
fp
= (struct sigframe
*)(regs
[SP
] - fsize
);
if ((unsigned)fp
<= USRSTACK
- ctob(p
->p_vmspace
->vm_ssize
))
(void)grow(p
, (unsigned)fp
);
if ((sigdebug
& SDB_FOLLOW
) ||
(sigdebug
& SDB_KSTACK
) && p
->p_pid
== sigpid
)
printf("sendsig(%d): sig %d ssp %x usp %x scp %x\n",
p
->p_pid
, sig
, &oonstack
, fp
, &fp
->sf_sc
);
* Build the signal context to be used by sigreturn.
ksc
.sc_onstack
= oonstack
;
ksc
.sc_regs
[ZERO
] = 0xACEDBADE; /* magic number */
bcopy((caddr_t
)®s
[1], (caddr_t
)&ksc
.sc_regs
[1],
sizeof(ksc
.sc_regs
) - sizeof(int));
ksc
.sc_fpused
= p
->p_md
.md_flags
& MDP_FPUSED
;
extern struct proc
*machFPCurProcPtr
;
/* if FPU has current state, save it first */
if (p
== machFPCurProcPtr
)
bcopy((caddr_t
)&p
->p_md
.md_regs
[F0
], (caddr_t
)ksc
.sc_fpregs
,
if (copyout((caddr_t
)&ksc
, (caddr_t
)&fp
->sf_sc
, sizeof(ksc
))) {
* Process has trashed its stack; give it an illegal
* instruction to halt it in its tracks.
SIGACTION(p
, SIGILL
) = SIG_DFL
;
* Build the argument list for the signal handler.
regs
[A2
] = (int)&fp
->sf_sc
;
* Signal trampoline code is at base of user stack.
regs
[RA
] = (int)PS_STRINGS
- (esigcode
- sigcode
);
if ((sigdebug
& SDB_FOLLOW
) ||
(sigdebug
& SDB_KSTACK
) && p
->p_pid
== sigpid
)
printf("sendsig(%d): sig %d returns\n",
* System call to cleanup state after a signal
* has been taken. Reset signal mask and
* stack state from context left by sendsig (above).
* Return to previous pc and psl as specified by
* context left by sendsig. Check carefully to
* make sure that the user has not modified the
* psl to gain improper priviledges or to cause
struct sigcontext
*sigcntxp
;
sigreturn(p
, uap
, retval
)
struct sigreturn_args
*uap
;
register struct sigcontext
*scp
;
if (sigdebug
& SDB_FOLLOW
)
printf("sigreturn: pid %d, scp %x\n", p
->p_pid
, scp
);
* Test and fetch the context structure.
* We grab it all at once for speed.
error
= copyin((caddr_t
)scp
, (caddr_t
)&ksc
, sizeof(ksc
));
if (error
|| ksc
.sc_regs
[ZERO
] != 0xACEDBADE) {
if (!(sigdebug
& SDB_FOLLOW
))
printf("sigreturn: pid %d, scp %x\n", p
->p_pid
, scp
);
printf(" old sp %x ra %x pc %x\n",
regs
[SP
], regs
[RA
], regs
[PC
]);
printf(" new sp %x ra %x pc %x err %d z %x\n",
ksc
.sc_regs
[SP
], ksc
.sc_regs
[RA
], ksc
.sc_regs
[PC
],
error
, ksc
.sc_regs
[ZERO
]);
* Restore the user supplied information
if (scp
->sc_onstack
& 01)
p
->p_sigacts
->ps_sigstk
.ss_flags
|= SA_ONSTACK
;
p
->p_sigacts
->ps_sigstk
.ss_flags
&= ~SA_ONSTACK
;
p
->p_sigmask
= scp
->sc_mask
&~ sigcantmask
;
bcopy((caddr_t
)&scp
->sc_regs
[1], (caddr_t
)®s
[1],
sizeof(scp
->sc_regs
) - sizeof(int));
bcopy((caddr_t
)scp
->sc_fpregs
, (caddr_t
)&p
->p_md
.md_regs
[F0
],
/* take a snap shot before clobbering any registers */
savectx(curproc
->p_addr
, 0);
howto
|= RB_HALT
; /* XXX */
if ((howto
&RB_NOSYNC
) == 0 && waittime
< 0) {
printf("syncing disks... ");
* Release vnodes held by texts before sync.
vnode_pager_umount(NULL
);
sync(&proc0
, (void *)NULL
, (int *)NULL
);
for (iter
= 0; iter
< 20; iter
++) {
for (bp
= &buf
[nbuf
]; --bp
>= buf
; )
if ((bp
->b_flags
& (B_BUSY
|B_INVAL
)) == B_BUSY
)
* If we've been adjusting the clock, the todr
* will be out of synch; adjust it now.
(void) splhigh(); /* extreme priority */
} else if (howto
& RB_HALT
) {
volatile void (*f
)() = (volatile void (*)())DEC_PROM_REINIT
;
(*f
)(); /* jump back to prom monitor */
volatile void (*f
)() = (volatile void (*)())DEC_PROM_AUTOBOOT
;
(*f
)(); /* jump back to prom monitor and do 'auto' cmd */
int dumpmag
= 0x8fca0101; /* magic number for savecore */
int dumpsize
= 0; /* also for savecore */
if (dumpdev
!= NODEV
&& bdevsw
[major(dumpdev
)].d_psize
) {
nblks
= (*bdevsw
[major(dumpdev
)].d_psize
)(dumpdev
);
if (dumpsize
> btoc(dbtob(nblks
- dumplo
)))
dumpsize
= btoc(dbtob(nblks
- dumplo
));
dumplo
= nblks
- btodb(ctob(physmem
));
* Don't dump on the first CLBYTES (why CLBYTES?)
* in case the dump device includes a disk label.
if (dumplo
< btodb(CLBYTES
))
* Doadump comes here after turning off memory management and
* getting on the dump stack, either when called above, or by
* For dumps during autoconfiguration,
* if dump device has already configured...
printf("\ndumping to dev %x, offset %d\n", dumpdev
, dumplo
);
switch (error
= (*bdevsw
[major(dumpdev
)].d_dump
)(dumpdev
)) {
printf("device not ready\n");
printf("area improper\n");
printf("error %d\n", error
);
* Return the best possible estimate of the time in the timeval
* to which tvp points. Unfortunately, we can't read the hardware registers.
* We guarantee that the time will be greater than the value obtained by a
register struct timeval
*tvp
;
static struct timeval lasttime
;
tvp
->tv_usec
+= clkread();
while (tvp
->tv_usec
> 1000000) {
if (tvp
->tv_sec
== lasttime
.tv_sec
&&
tvp
->tv_usec
<= lasttime
.tv_usec
&&
(tvp
->tv_usec
= lasttime
.tv_usec
+ 1) > 1000000) {
register volatile struct chiptime
*c
;
/* disable clock interrupts (until startrtclock()) */
c
->regb
= REGB_DATA_MODE
| REGB_HOURS_FORMAT
;
spl0(); /* safe to turn interrupts on now */
* Convert an ASCII string into an integer.
if (s
== 0 || (c
= *s
++) == 0)
while (c
== ' ' || c
== '\t')
/* parse sign, allow more than one (compat) */
/* parse base specification, if any */
/* parse number proper */
if (c
>= '0' && c
<= '9')
else if (c
>= 'a' && c
<= 'z')
else if (c
>= 'A' && c
<= 'Z')
* Fill in the pmax addresses by hand.
static struct pmax_address
{
{ "pm", (char *)MACH_PHYS_TO_CACHED(KN01_PHYS_FBUF_START
), 3 },
{ "dc", (char *)MACH_PHYS_TO_UNCACHED(KN01_SYS_DZ
), 2 },
{ "le", (char *)MACH_PHYS_TO_UNCACHED(KN01_SYS_LANCE
), 1 },
{ "sii",(char *)MACH_PHYS_TO_UNCACHED(KN01_SYS_SII
), 0 },
register struct pmax_ctlr
*cp
;
register struct driver
*drp
;
register struct pmax_address
*pmap
;
* Find the device driver entry and fill in the address.
for (cp
= pmax_cinit
; drp
= cp
->pmax_driver
; cp
++) {
for (pmap
= pmax_addresses
; pmap
->pmax_name
; pmap
++) {
if (strcmp(drp
->d_name
, pmap
->pmax_name
))
if (cp
->pmax_addr
== (char *)QUES
) {
cp
->pmax_addr
= pmap
->pmax_addr
;
cp
->pmax_pri
= pmap
->pmax_pri
;
* Copyright (c) 1991,1990,1989 Carnegie Mellon University
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
* Carnegie Mellon requests users of this software to return to
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
* Driver map: associates a device driver to an option type.
* Drivers name are (arbitrarily) defined in each driver and
* used in the various config tables.
char module_name
[TC_ROM_LLEN
]; /* from ROM, literally! */
char *driver_name
; /* in bus_??_init[] tables */
{ "KN02 ", "dc"}, /* (*) 3max system board (with DC) */
{ "PMAD-AA ", "le"}, /* Ether */
{ "PMAZ-AA ", "asc"}, /* SCSI */
{ "PMAG-AA ", "mfb"}, /* Mono Frame Buffer */
{ "PMAG-BA ", "cfb"}, /* Color Frame Buffer */
{ "PMAG-CA ", "ga"}, /* 2D graphic board */
{ "PMAG-DA ", "gq"}, /* 3D graphic board (LM) */
{ "PMAG-FA ", "gq"}, /* 3D graphic board (HE) */
{ "PMAG-DV ", "xcfb"}, /* (*) maxine Color Frame Buffer */
{ "Z8530 ", "scc"}, /* (*) 3min/maxine serial lines */
{ "ASIC ", "asic"}, /* (*) 3min/maxine DMA controller */
{ "XINE-FDC", "fdc"}, /* (*) maxine floppy controller */
{ "DTOP ", "dtop"}, /* (*) maxine desktop bus */
{ "AMD79c30", "isdn"}, /* (*) maxine ISDN chip */
{ "XINE-FRC", "frc"}, /* (*) maxine free-running counter */
* Identify an option on the TC. Looks at the mandatory
* info in the option's ROM and checks it.
tc_identify_option(addr
, slot
, complain
)
char firmwr
[TC_ROM_LLEN
+1], vendor
[TC_ROM_LLEN
+1],
module
[TC_ROM_LLEN
+1], host_type
[TC_ROM_SLEN
+1];
* We do not really use the 'width' info, but take advantage
* of the restriction that the spec impose on the portion
* of the ROM that maps between +0x3e0 and +0x470, which
* is the only piece we need to look at.
width
= addr
->rom_width
.value
;
if (tc_verbose
&& complain
)
printf("%s (x%x) at x%x\n", "Invalid ROM width",
if (addr
->rom_stride
.value
!= 4) {
if (tc_verbose
&& complain
)
printf("%s (x%x) at x%x\n", "Invalid ROM stride",
addr
->rom_stride
.value
, addr
);
if ((addr
->test_data
[0] != 0x55) ||
(addr
->test_data
[4] != 0x00) ||
(addr
->test_data
[8] != 0xaa) ||
(addr
->test_data
[12] != 0xff)) {
if (tc_verbose
&& complain
)
printf("%s x%x\n", "Test pattern failed, option at",
for (i
= 0; i
< TC_ROM_LLEN
; i
++) {
firmwr
[i
] = addr
->firmware_rev
[i
].value
;
vendor
[i
] = addr
->vendor_name
[i
].value
;
module
[i
] = addr
->module_name
[i
].value
;
host_type
[i
] = addr
->host_firmware_type
[i
].value
;
firmwr
[TC_ROM_LLEN
] = vendor
[TC_ROM_LLEN
] =
module
[TC_ROM_LLEN
] = host_type
[TC_ROM_SLEN
] = '\0';
printf("%s %s '%s' at 0x%x\n %s %s %s '%s'\n %s %d %s %d %s\n",
"Found a", vendor
, module
, addr
,
"diagnostics for a", host_type
,
"ROM size is", addr
->rom_size
.value
<< 3,
"Kbytes, uses", addr
->slot_size
.value
, "TC slot(s)");
bcopy(module
, slot
->module_name
, TC_ROM_LLEN
);
bcopy(vendor
, slot
->module_id
, TC_ROM_LLEN
);
bcopy(firmwr
, &slot
->module_id
[TC_ROM_LLEN
], TC_ROM_LLEN
);
slot
->slot_size
= addr
->slot_size
.value
;
* TURBOchannel autoconf procedure. Finds in one sweep what is
* hanging on the bus and fills in the tc_slot_info array.
* This is only the first part of the autoconf scheme, at this
* time we are basically only looking for a graphics board to
* use as system console (all workstations).
register tc_option_t
*sl
;
register struct pmax_ctlr
*cp
;
register struct driver
*drp
;
bzero(tc_slot_info
, sizeof(tc_slot_info
));
for (i
= tc_max_slot
; i
>= tc_min_slot
;) {
addr
= MACH_PHYS_TO_UNCACHED(tc_slot_phys_base
[i
]);
found
= tc_probe_slot(addr
, &tc_slot_info
[i
]);
* Found a slot, make a note of it
tc_slot_info
[i
].present
= 1;
tc_slot_info
[i
].k1seg_address
= addr
;
i
-= tc_slot_info
[i
].slot_size
;
* Some slots (e.g. the system slot on 3max) might require
* hand-filling. If so, do it now.
(*tc_slot_hand_fill
) (tc_slot_info
);
* Now for each alive slot see if we have a device driver that
* handles it. This is done in "priority order", meaning that
* always present devices are at higher slot numbers on all
* current TC machines, and option slots are at lowest numbers.
for (i
= TC_MAX_LOGICAL_SLOTS
- 1; i
>= 0; i
--) {
for (map
= tc_drivers_map
; map
->driver_name
; map
++) {
if (bcmp(sl
->module_name
, map
->module_name
, TC_ROM_LLEN
))
sl
->driver_name
= map
->driver_name
;
"Cannot associate a device driver to",
sl
->module_name
, ". Will (try to) ignore it.");
* Find the device driver entry and fill in the address.
for (cp
= pmax_cinit
; drp
= cp
->pmax_driver
; cp
++) {
if (strcmp(drp
->d_name
, map
->driver_name
))
if (cp
->pmax_addr
== (char *)QUES
) {
cp
->pmax_addr
= (char *)sl
->k1seg_address
;
* Only enable interrupts if there is an
* interrupt handler for it. (e.g., PMAG-BA
* can't disable the vertical retrace interrupt
* and we might want to ignore it).
(*tc_enable_interrupt
)(i
, 1);
if (cp
->pmax_addr
!= (char *)sl
->k1seg_address
) {
cp
->pmax_addr
= (char *)QUES
;
printf("%s: device not at configued address (expected at %x, found at %x)\n",
cp
->pmax_addr
, sl
->k1seg_address
);
* Probe a slot in the TURBOchannel. Return TRUE if a valid option
* is present, FALSE otherwise. A side-effect is to fill the slot
* descriptor with the size of the option, whether it is
tc_probe_slot(addr
, slot
)
static unsigned tc_offset_rom
[] = {
TC_OFF_PROTO_ROM
, TC_OFF_ROM
#define TC_N_OFFSETS sizeof(tc_offset_rom)/sizeof(unsigned)
for (i
= 0; i
< TC_N_OFFSETS
; i
++) {
if (badaddr(addr
+ tc_offset_rom
[i
], 4))
/* complain only on last chance */
if (tc_identify_option((tc_rommap_t
*)(addr
+ tc_offset_rom
[i
]),
slot
, i
== (TC_N_OFFSETS
-1)))
* Enable/Disable interrupts for a TURBOchannel slot.
kn02_enable_intr(slotno
, on
)
register volatile int *p_csr
=
(volatile int *)MACH_PHYS_TO_UNCACHED(KN02_SYS_CSR
);
slotno
= 1 << (slotno
+ KN02_CSR_IOINTEN_SHIFT
);
csr
= *p_csr
& ~(KN02_CSR_WRESERVED
| 0xFF);
* kmin_enable_intr EXPORTED function
* Enable/Disable interrupts from a TURBOchannel slot.
* We pretend we actually have 8 slots even if we really have
* only 4: TCslots 0-2 maps to slots 0-2, TCslot3 maps to
* slots 3-7 (see kmin_slot_hand_fill).
kmin_enable_intr(slotno
, on
)
register unsigned int slotno
;
mask
= (KMIN_INTR_SCSI
| KMIN_INTR_SCSI_PTR_LOAD
|
KMIN_INTR_SCSI_OVRUN
| KMIN_INTR_SCSI_READ_E
);
* xine_enable_intr EXPORTED function
* Enable/Disable interrupts from a TURBOchannel slot.
* We pretend we actually have 11 slots even if we really have
* only 3: TCslots 0-1 maps to slots 0-1, TCslot 2 is used for
* the system (TCslot3), TCslot3 maps to slots 3-10
* (see xine_slot_hand_fill).
* Note that all these interrupts come in via the IMR.
xine_enable_intr(slotno
, on
)
register unsigned int slotno
;
case 0: /* a real slot, but */
case 1: /* a real slot, but */
mask
= (XINE_INTR_SCSI
| XINE_INTR_SCSI_PTR_LOAD
|
XINE_INTR_SCSI_OVRUN
| XINE_INTR_SCSI_READ_E
);
mask
= XINE_INTR_DTOP_RX
;
* kn03_enable_intr EXPORTED function
* Enable/Disable interrupts from a TURBOchannel slot.
* We pretend we actually have 8 slots even if we really have
* only 4: TCslots 0-2 maps to slots 0-2, TCslot3 maps to
* slots 3-7 (see kn03_slot_hand_fill).
kn03_enable_intr(slotno
, on
)
register unsigned int slotno
;
mask
= (KN03_INTR_SCSI
| KN03_INTR_SCSI_PTR_LOAD
|
KN03_INTR_SCSI_OVRUN
| KN03_INTR_SCSI_READ_E
);
* kn02_slot_hand_fill EXPORTED function
* Fill in by hand the info for TC slots that are non-standard.
* This is basically just the system slot on a 3max, it does not
* look to me like it follows the TC rules although some of the
* required info is indeed there.
kn02_slot_hand_fill(slot
)
bcopy(0xbffc0410, slot
[7].module_name
, TC_ROM_LLEN
+1);
bcopy("KN02 ", slot
[7].module_name
, TC_ROM_LLEN
+1);
bcopy("DEC xxxx", slot
[7].module_id
, TC_ROM_LLEN
+1);
slot
[7].k1seg_address
= MACH_PHYS_TO_UNCACHED(KN02_SYS_DZ
);
* kmin_slot_hand_fill EXPORTED function
* Fill in by hand the info for TC slots that are non-standard.
* This is the system slot on a 3min, which we think of as a
* set of non-regular size TC slots.
kmin_slot_hand_fill(slot
)
for (i
= KMIN_SCSI_SLOT
; i
< KMIN_ASIC_SLOT
+1; i
++) {
bcopy("DEC KMIN", slot
[i
].module_id
, TC_ROM_LLEN
+1);
bcopy("PMAZ-AA ", slot
[KMIN_SCSI_SLOT
].module_name
, TC_ROM_LLEN
+1);
slot
[KMIN_SCSI_SLOT
].k1seg_address
=
MACH_PHYS_TO_UNCACHED(KMIN_SYS_SCSI
);
bcopy("PMAD-AA ", slot
[KMIN_LANCE_SLOT
].module_name
, TC_ROM_LLEN
+1);
slot
[KMIN_LANCE_SLOT
].k1seg_address
= 0;
bcopy("Z8530 ", slot
[KMIN_SCC0_SLOT
].module_name
, TC_ROM_LLEN
+1);
slot
[KMIN_SCC0_SLOT
].k1seg_address
=
MACH_PHYS_TO_UNCACHED(KMIN_SYS_SCC_0
);
slot
[KMIN_SCC1_SLOT
].unit
= 1;
bcopy("Z8530 ", slot
[KMIN_SCC1_SLOT
].module_name
, TC_ROM_LLEN
+1);
slot
[KMIN_SCC1_SLOT
].k1seg_address
=
MACH_PHYS_TO_UNCACHED(KMIN_SYS_SCC_1
);
bcopy("ASIC ", slot
[KMIN_ASIC_SLOT
].module_name
, TC_ROM_LLEN
+1);
slot
[KMIN_ASIC_SLOT
].k1seg_address
=
MACH_PHYS_TO_UNCACHED(KMIN_SYS_ASIC
);
* xine_slot_hand_fill EXPORTED function
* Fill in by hand the info for TC slots that are non-standard.
* This is the system slot on a 3min, which we think of as a
* set of non-regular size TC slots.
xine_slot_hand_fill(slot
)
for (i
= XINE_FLOPPY_SLOT
; i
< XINE_FRC_SLOT
+1; i
++) {
bcopy("DEC XINE", slot
[i
].module_id
, TC_ROM_LLEN
+1);
bcopy("XINE-FDC", slot
[XINE_FLOPPY_SLOT
].module_name
, TC_ROM_LLEN
+1);
slot
[XINE_FLOPPY_SLOT
].k1seg_address
=
MACH_PHYS_TO_UNCACHED(XINE_SYS_FLOPPY
);
bcopy("PMAZ-AA ", slot
[XINE_SCSI_SLOT
].module_name
, TC_ROM_LLEN
+1);
slot
[XINE_SCSI_SLOT
].k1seg_address
=
MACH_PHYS_TO_UNCACHED(XINE_SYS_SCSI
);
bcopy("PMAD-AA ", slot
[XINE_LANCE_SLOT
].module_name
, TC_ROM_LLEN
+1);
slot
[XINE_LANCE_SLOT
].k1seg_address
=
MACH_PHYS_TO_UNCACHED(XINE_SYS_LANCE
);
bcopy("Z8530 ", slot
[XINE_SCC0_SLOT
].module_name
, TC_ROM_LLEN
+1);
slot
[XINE_SCC0_SLOT
].k1seg_address
=
MACH_PHYS_TO_UNCACHED(XINE_SYS_SCC_0
);
bcopy("DTOP ", slot
[XINE_DTOP_SLOT
].module_name
, TC_ROM_LLEN
+1);
slot
[XINE_DTOP_SLOT
].k1seg_address
=
MACH_PHYS_TO_UNCACHED(XINE_SYS_DTOP
+0x20000); /* why? */
bcopy("AMD79c30", slot
[XINE_ISDN_SLOT
].module_name
, TC_ROM_LLEN
+1);
slot
[XINE_ISDN_SLOT
].k1seg_address
=
MACH_PHYS_TO_UNCACHED(XINE_SYS_ISDN
);
bcopy("PMAG-DV ", slot
[XINE_CFB_SLOT
].module_name
, TC_ROM_LLEN
+1);
slot
[XINE_CFB_SLOT
].k1seg_address
=
MACH_PHYS_TO_CACHED(XINE_PHYS_CFB_START
);
bcopy("ASIC ", slot
[XINE_ASIC_SLOT
].module_name
, TC_ROM_LLEN
+1);
slot
[XINE_ASIC_SLOT
].k1seg_address
=
MACH_PHYS_TO_UNCACHED(XINE_SYS_ASIC
);
/* free-running counter (high resolution mapped time) */
bcopy("XINE-FRC", slot
[XINE_FRC_SLOT
].module_name
, TC_ROM_LLEN
+1);
slot
[XINE_FRC_SLOT
].k1seg_address
=
MACH_PHYS_TO_UNCACHED(XINE_REG_FCTR
);
* kn03_slot_hand_fill EXPORTED function
* Fill in by hand the info for TC slots that are non-standard.
* This is the system slot on a 3max+, which we think of as a
* set of non-regular size TC slots.
kn03_slot_hand_fill(slot
)
for (i
= KN03_SCSI_SLOT
; i
< KN03_ASIC_SLOT
+1; i
++) {
bcopy("DEC KN03", slot
[i
].module_id
, TC_ROM_LLEN
+1);
bcopy("PMAZ-AA ", slot
[KN03_SCSI_SLOT
].module_name
, TC_ROM_LLEN
+1);
slot
[KN03_SCSI_SLOT
].k1seg_address
=
MACH_PHYS_TO_UNCACHED(KN03_SYS_SCSI
);
bcopy("PMAD-AA ", slot
[KN03_LANCE_SLOT
].module_name
, TC_ROM_LLEN
+1);
slot
[KN03_LANCE_SLOT
].k1seg_address
= 0;
bcopy("Z8530 ", slot
[KN03_SCC0_SLOT
].module_name
, TC_ROM_LLEN
+1);
slot
[KN03_SCC0_SLOT
].k1seg_address
=
MACH_PHYS_TO_UNCACHED(KN03_SYS_SCC_0
);
slot
[KN03_SCC1_SLOT
].unit
= 1;
bcopy("Z8530 ", slot
[KN03_SCC1_SLOT
].module_name
, TC_ROM_LLEN
+1);
slot
[KN03_SCC1_SLOT
].k1seg_address
=
MACH_PHYS_TO_UNCACHED(KN03_SYS_SCC_1
);
bcopy("ASIC ", slot
[KN03_ASIC_SLOT
].module_name
, TC_ROM_LLEN
+1);
slot
[KN03_ASIC_SLOT
].k1seg_address
=
MACH_PHYS_TO_UNCACHED(KN03_SYS_ASIC
);
* Initialize the I/O asic
/* These are common between 3min and maxine */
decoder
= (volatile u_int
*)ASIC_REG_LANCE_DECODE(asic_base
);
*decoder
= KMIN_LANCE_CONFIG
;