5a667d2381546a38524a16f4b4311f4666998e11
[unix-history] / usr / src / sys / hp300 / hp300 / machdep.c
/*
* Copyright (c) 1988 University of Utah.
* Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* the Systems Programming Group of the University of Utah Computer
* Science Department.
*
* %sccs.include.redist.c%
*
* from: Utah $Hdr: machdep.c 1.51 89/11/28$
*
* @(#)machdep.c 7.10 (Berkeley) %G%
*/
#include "sys/param.h"
#include "sys/systm.h"
#include "sys/user.h"
#include "sys/kernel.h"
#include "sys/map.h"
#include "sys/proc.h"
#include "sys/buf.h"
#include "sys/reboot.h"
#include "sys/conf.h"
#include "sys/file.h"
#include "sys/clist.h"
#include "sys/callout.h"
#include "sys/malloc.h"
#include "sys/mbuf.h"
#include "sys/msgbuf.h"
#ifdef SYSVSHM
#include "sys/shm.h"
#endif
#ifdef HPUXCOMPAT
#include "../hpux/hpux.h"
#endif
#include "../include/cpu.h"
#include "../include/reg.h"
#include "../include/psl.h"
#include "isr.h"
#include "net/netisr.h"
#define MAXMEM 64*1024*CLSIZE /* XXX - from cmap.h */
#include "vm/vm_param.h"
#include "vm/pmap.h"
#include "vm/vm_map.h"
#include "vm/vm_object.h"
#include "vm/vm_kern.h"
#include "vm/vm_page.h"
vm_map_t buffer_map;
extern vm_offset_t avail_end;
/*
* Declare these as initialized data so we can patch them.
*/
int nswbuf = 0;
#ifdef NBUF
int nbuf = NBUF;
#else
int nbuf = 0;
#endif
#ifdef BUFPAGES
int bufpages = BUFPAGES;
#else
int bufpages = 0;
#endif
int msgbufmapped; /* set when safe to use msgbuf */
int physmem = MAXMEM; /* max supported memory, changes to actual */
/*
* safepri is a safe priority for sleep to set for a spin-wait
* during autoconfiguration or after a panic.
*/
int safepri = PSL_LOWIPL;
extern u_int lowram;
/*
* Machine-dependent startup code
*/
startup(firstaddr)
int firstaddr;
{
register unsigned i;
register caddr_t v;
int base, residual;
extern long Usrptsize;
extern struct map *useriomap;
#ifdef DEBUG
extern int pmapdebug;
int opmapdebug = pmapdebug;
#endif
vm_offset_t minaddr, maxaddr;
vm_size_t size;
/*
* Set cpuspeed immediately since cninit() called routines
* might use delay.
*/
switch (machineid) {
case HP_320:
case HP_330:
case HP_340:
cpuspeed = MHZ_16;
break;
case HP_350:
case HP_360:
cpuspeed = MHZ_25;
break;
case HP_370:
cpuspeed = MHZ_33;
break;
case HP_375:
cpuspeed = MHZ_50;
break;
}
#ifndef DEBUG
/*
* Find what hardware is attached to this machine.
*/
find_devs();
/*
* Initialize the console before we print anything out.
*/
cninit();
#endif
/*
* Initialize error message buffer (at end of core).
*/
#ifdef DEBUG
pmapdebug = 0;
#endif
/* avail_end was pre-decremented in pmap_bootstrap to compensate */
for (i = 0; i < btoc(sizeof (struct msgbuf)); i++)
pmap_enter(pmap_kernel(), msgbufp, avail_end + i * NBPG,
VM_PROT_ALL, TRUE);
msgbufmapped = 1;
/*
* Good {morning,afternoon,evening,night}.
*/
printf(version);
identifycpu();
printf("real mem = %d\n", ctob(physmem));
/*
* Allocate space for system data structures.
* The first available real memory address is in "firstaddr".
* The first available kernel virtual address is in "v".
* As pages of kernel virtual memory are allocated, "v" is incremented.
* As pages of memory are allocated and cleared,
* "firstaddr" is incremented.
* An index into the kernel page table corresponding to the
* virtual memory address maintained in "v" is kept in "mapaddr".
*/
/*
* Make two passes. The first pass calculates how much memory is
* needed and allocates it. The second pass assigns virtual
* addresses to the various data structures.
*/
firstaddr = 0;
again:
v = (caddr_t)firstaddr;
#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)))
valloclim(file, struct file, nfile, fileNFILE);
valloclim(proc, struct proc, nproc, procNPROC);
valloc(cfree, struct cblock, nclist);
valloc(callout, struct callout, ncallout);
valloc(swapmap, struct map, nswapmap = nproc * 2);
#ifdef SYSVSHM
valloc(shmsegs, struct shmid_ds, shminfo.shmmni);
#endif
/*
* Determine how many buffers to allocate.
* Since HPs tend to be long on memory and short on disk speed,
* we allocate more buffer space than the BSD standard of
* use 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.
*/
if (bufpages == 0)
bufpages = physmem / 10 / CLSIZE;
if (nbuf == 0) {
nbuf = bufpages;
if (nbuf < 16)
nbuf = 16;
}
if (nswbuf == 0) {
nswbuf = (nbuf / 2) &~ 1; /* force even */
if (nswbuf > 256)
nswbuf = 256; /* sanity */
}
valloc(swbuf, struct buf, nswbuf);
valloc(buf, struct buf, nbuf);
/*
* End of first pass, size has been calculated so allocate memory
*/
if (firstaddr == 0) {
size = (vm_size_t)(v - firstaddr);
firstaddr = (int)kmem_alloc(kernel_map, round_page(size));
if (firstaddr == 0)
panic("startup: no room for tables");
goto again;
}
/*
* End of second pass, addresses have been assigned
*/
if ((vm_size_t)(v - firstaddr) != size)
panic("startup: table size inconsistency");
/*
* Now allocate buffers proper. They are different than the above
* in that they usually occupy more virtual memory than physical.
*/
size = MAXBSIZE * nbuf;
buffer_map = kmem_suballoc(kernel_map, (vm_offset_t)&buffers,
&maxaddr, size, FALSE);
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");
base = bufpages / nbuf;
residual = bufpages % nbuf;
for (i = 0; i < nbuf; i++) {
vm_size_t curbufsize;
vm_offset_t curbuf;
/*
* 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,
16*NCARGS, TRUE);
/*
* Allocate a submap for physio
*/
phys_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr,
VM_PHYS_SIZE, TRUE);
/*
* 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,
M_MBUF, M_NOWAIT);
bzero(mclrefcnt, NMBCLUSTERS+CLBYTES/MCLBYTES);
mb_map = kmem_suballoc(kernel_map, (vm_offset_t)&mbutl, &maxaddr,
VM_MBUF_SIZE, FALSE);
/*
* Initialize callouts
*/
callfree = callout;
for (i = 1; i < ncallout; i++)
callout[i-1].c_next = &callout[i];
#ifdef DEBUG
pmapdebug = opmapdebug;
#endif
printf("avail mem = %d\n", ptoa(vm_page_free_count));
printf("using %d buffers containing %d bytes of memory\n",
nbuf, bufpages * CLBYTES);
/*
* Set up CPU-specific registers, cache, etc.
*/
initcpu();
/*
* Set up buffers, so they can be used to read disk labels.
*/
bhinit();
binit();
/*
* Configure the system.
*/
configure();
}
#ifdef PGINPROF
/*
* Return the difference (in microseconds)
* between the current time and a previous
* time as represented by the arguments.
*/
/*ARGSUSED*/
vmtime(otime, olbolt, oicr)
register int otime, olbolt, oicr;
{
return (((time.tv_sec-otime)*100 + lbolt-olbolt)*10000);
}
#endif
/*
* Clear registers on exec
*/
setregs(entry, retval)
u_long entry;
int retval[2];
{
u.u_ar0[PC] = entry & ~1;
#ifdef FPCOPROC
/* restore a null state frame */
u.u_pcb.pcb_fpregs.fpf_null = 0;
m68881_restore(&u.u_pcb.pcb_fpregs);
#endif
#ifdef HPUXCOMPAT
if (u.u_procp->p_flag & SHPUX) {
u.u_ar0[A0] = 0; /* not 68010 (bit 31), no FPA (30) */
retval[0] = 0; /* no float card */
#ifdef FPCOPROC
retval[1] = 1; /* yes 68881 */
#else
retval[1] = 0; /* no 68881 */
#endif
}
/*
* Ensure we perform the right action on traps type 1 and 2:
* If our parent is an HPUX process and we are being traced, turn
* on HPUX style interpretation. Else if we were using the HPUX
* style interpretation, revert to the BSD interpretation.
*
* XXX This doesn't have much to do with setting registers but
* I didn't want to muck up kern_exec.c with this code, so I
* stuck it here.
*/
if ((u.u_procp->p_pptr->p_flag & SHPUX) &&
(u.u_procp->p_flag & STRC)) {
tweaksigcode(1);
u.u_pcb.pcb_flags |= PCB_HPUXTRACE;
} else if (u.u_pcb.pcb_flags & PCB_HPUXTRACE) {
tweaksigcode(0);
u.u_pcb.pcb_flags &= ~PCB_HPUXTRACE;
}
#endif
}
identifycpu()
{
printf("HP9000/");
switch (machineid) {
case HP_320:
printf("320 (16.67Mhz");
break;
case HP_330:
printf("318/319/330 (16.67Mhz");
break;
case HP_340:
printf("340 (16.67Mhz");
break;
case HP_350:
printf("350 (25Mhz");
break;
case HP_360:
printf("360 (25Mhz");
break;
case HP_370:
printf("370 (33.33Mhz");
break;
case HP_375:
printf("345/375 (50Mhz");
break;
default:
printf("\nunknown machine type %d\n", machineid);
panic("startup");
}
printf(" MC680%s CPU", mmutype == MMU_68030 ? "30" : "20");
switch (mmutype) {
case MMU_68030:
printf("+MMU");
break;
case MMU_68851:
printf(", MC68851 MMU");
break;
case MMU_HP:
printf(", HP MMU");
break;
default:
printf("\nunknown MMU type %d\n", mmutype);
panic("startup");
}
if (mmutype == MMU_68030)
printf(", %sMhz MC68882 FPU",
machineid == HP_340 ? "16.67" :
(machineid == HP_360 ? "25" :
(machineid == HP_370 ? "33.33" : "50")));
else
printf(", %sMhz MC68881 FPU",
machineid == HP_350 ? "20" : "16.67");
switch (ectype) {
case EC_VIRT:
printf(", %dK virtual-address cache",
machineid == HP_320 ? 16 : 32);
break;
case EC_PHYS:
printf(", %dK physical-address cache",
machineid == HP_370 ? 64 : 32);
break;
}
printf(")\n");
/*
* Now that we have told the user what they have,
* let them know if that machine type isn't configured.
*/
switch (machineid) {
case -1: /* keep compilers happy */
#if !defined(HP320) && !defined(HP350)
case HP_320:
case HP_350:
#endif
#ifndef HP330
case HP_330:
#endif
#if !defined(HP360) && !defined(HP370)
case HP_340:
case HP_360:
case HP_370:
#endif
panic("CPU type not configured");
default:
break;
}
}
#ifdef HPUXCOMPAT
tweaksigcode(ishpux)
{
static short *sigtrap = NULL;
/* locate trap instruction in pcb_sigc */
if (sigtrap == NULL) {
register struct pcb *pcp = &u.u_pcb;
sigtrap = &pcp->pcb_sigc[sizeof(pcp->pcb_sigc)/sizeof(short)];
while (--sigtrap >= pcp->pcb_sigc)
if ((*sigtrap & 0xFFF0) == 0x4E40)
break;
if (sigtrap < pcp->pcb_sigc)
panic("bogus sigcode\n");
}
*sigtrap = ishpux ? 0x4E42 : 0x4E41;
}
#endif
#define SS_RTEFRAME 1
#define SS_FPSTATE 2
#define SS_USERREGS 4
struct sigstate {
int ss_flags; /* which of the following are valid */
struct frame ss_frame; /* original exception frame */
struct fpframe ss_fpstate; /* 68881/68882 state info */
};
/*
* WARNING: code in locore.s assumes the layout shown for sf_signum
* thru sf_handler so... don't screw with them!
*/
struct sigframe {
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 sigstate sf_state; /* state of the hardware */
struct sigcontext sf_sc; /* actual context */
};
#ifdef HPUXCOMPAT
struct hpuxsigcontext {
int hsc_syscall;
char hsc_action;
char hsc_pad1;
char hsc_pad2;
char hsc_onstack;
int hsc_mask;
int hsc_sp;
short hsc_ps;
int hsc_pc;
/* the rest aren't part of the context but are included for our convenience */
short hsc_pad;
u_int hsc_magic; /* XXX sigreturn: cookie */
struct sigcontext *hsc_realsc; /* XXX sigreturn: ptr to BSD context */
};
/*
* For an HP-UX process, a partial hpuxsigframe follows the normal sigframe.
* Tremendous waste of space, but some HP-UX applications (e.g. LCL) need it.
*/
struct hpuxsigframe {
int hsf_signum;
int hsf_code;
struct sigcontext *hsf_scp;
struct hpuxsigcontext hsf_sc;
int hsf_regs[15];
};
#endif
#ifdef DEBUG
int sigdebug = 0;
int sigpid = 0;
#define SDB_FOLLOW 0x01
#define SDB_KSTACK 0x02
#define SDB_FPSTATE 0x04
#endif
/*
* Send an interrupt to process.
*/
sendsig(catcher, sig, mask, code)
sig_t catcher;
int sig, mask;
unsigned code;
{
register struct proc *p = u.u_procp;
register struct sigframe *fp, *kfp;
register struct frame *frame;
register short ft;
int oonstack, fsize;
frame = (struct frame *)u.u_ar0;
ft = frame->f_format;
oonstack = u.u_onstack;
/*
* Allocate and validate space for the signal handler
* context. Note that if the stack is in P0 space, the
* call to grow() is a nop, and the useracc() check
* will fail if the process has not already allocated
* the space with a `brk'.
*/
#ifdef HPUXCOMPAT
if (p->p_flag & SHPUX)
fsize = sizeof(struct sigframe) + sizeof(struct hpuxsigframe);
else
#endif
fsize = sizeof(struct sigframe);
if (!u.u_onstack && (u.u_sigonstack & sigmask(sig))) {
fp = (struct sigframe *)(u.u_sigsp - fsize);
u.u_onstack = 1;
} else
fp = (struct sigframe *)(frame->f_regs[SP] - fsize);
if ((unsigned)fp <= USRSTACK - ctob(u.u_ssize))
(void)grow((unsigned)fp);
#ifdef DEBUG
if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid)
printf("sendsig(%d): sig %d ssp %x usp %x scp %x ft %d\n",
p->p_pid, sig, &oonstack, fp, &fp->sf_sc, ft);
#endif
if (useracc((caddr_t)fp, fsize, B_WRITE) == 0) {
#ifdef DEBUG
if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid)
printf("sendsig(%d): useracc failed on sig %d\n",
p->p_pid, sig);
#endif
/*
* Process has trashed its stack; give it an illegal
* instruction to halt it in its tracks.
*/
SIGACTION(p, SIGILL) = SIG_DFL;
sig = sigmask(SIGILL);
p->p_sigignore &= ~sig;
p->p_sigcatch &= ~sig;
p->p_sigmask &= ~sig;
psignal(p, SIGILL);
return;
}
kfp = (struct sigframe *)malloc((u_long)fsize, M_TEMP, M_WAITOK);
/*
* Build the argument list for the signal handler.
*/
kfp->sf_signum = sig;
kfp->sf_code = code;
kfp->sf_scp = &fp->sf_sc;
kfp->sf_handler = catcher;
/*
* Save necessary hardware state. Currently this includes:
* - general registers
* - original exception frame (if not a "normal" frame)
* - FP coprocessor state
*/
kfp->sf_state.ss_flags = SS_USERREGS;
bcopy((caddr_t)frame->f_regs,
(caddr_t)kfp->sf_state.ss_frame.f_regs, sizeof frame->f_regs);
if (ft >= FMT9) {
#ifdef DEBUG
if (ft != FMT9 && ft != FMTA && ft != FMTB)
panic("sendsig: bogus frame type");
#endif
kfp->sf_state.ss_flags |= SS_RTEFRAME;
kfp->sf_state.ss_frame.f_format = frame->f_format;
kfp->sf_state.ss_frame.f_vector = frame->f_vector;
bcopy((caddr_t)&frame->F_u,
(caddr_t)&kfp->sf_state.ss_frame.F_u,
(ft == FMT9) ? FMT9SIZE :
(ft == FMTA) ? FMTASIZE : FMTBSIZE);
/*
* Gag! Leave an indicator that we need to clean up the
* kernel stack. We do this by setting the "pad word"
* above the hardware stack frame. "bexit" in locore
* will then know that it must compress the kernel stack
* and create a normal four word stack frame.
*/
frame->f_stackadj = -1;
#ifdef DEBUG
if (sigdebug & SDB_FOLLOW)
printf("sendsig(%d): copy out %d of frame %d\n",
p->p_pid,
(ft == FMT9) ? FMT9SIZE :
(ft == FMTA) ? FMTASIZE : FMTBSIZE, ft);
#endif
}
#ifdef FPCOPROC
kfp->sf_state.ss_flags |= SS_FPSTATE;
m68881_save(&kfp->sf_state.ss_fpstate);
#ifdef DEBUG
if ((sigdebug & SDB_FPSTATE) && *(char *)&kfp->sf_state.ss_fpstate)
printf("sendsig(%d): copy out FP state (%x) to %x\n",
p->p_pid, *(u_int *)&kfp->sf_state.ss_fpstate,
&kfp->sf_state.ss_fpstate);
#endif
#endif
/*
* Build the signal context to be used by sigreturn.
*/
kfp->sf_sc.sc_onstack = oonstack;
kfp->sf_sc.sc_mask = mask;
kfp->sf_sc.sc_sp = frame->f_regs[SP];
kfp->sf_sc.sc_fp = frame->f_regs[A6];
kfp->sf_sc.sc_ap = (int)&fp->sf_state;
kfp->sf_sc.sc_pc = frame->f_pc;
kfp->sf_sc.sc_ps = frame->f_sr;
#ifdef HPUXCOMPAT
/*
* Create an HP-UX style sigcontext structure and associated goo
*/
if (p->p_flag & SHPUX) {
register struct hpuxsigframe *hkfp;
hkfp = (struct hpuxsigframe *)&kfp[1];
hkfp->hsf_signum = bsdtohpuxsig(kfp->sf_signum);
hkfp->hsf_code = kfp->sf_code;
hkfp->hsf_scp = (struct sigcontext *)
&((struct hpuxsigframe *)(&fp[1]))->hsf_sc;
hkfp->hsf_sc.hsc_syscall = 0; /* XXX */
hkfp->hsf_sc.hsc_action = 0; /* XXX */
hkfp->hsf_sc.hsc_pad1 = hkfp->hsf_sc.hsc_pad2 = 0;
hkfp->hsf_sc.hsc_onstack = kfp->sf_sc.sc_onstack;
hkfp->hsf_sc.hsc_mask = kfp->sf_sc.sc_mask;
hkfp->hsf_sc.hsc_sp = kfp->sf_sc.sc_sp;
hkfp->hsf_sc.hsc_ps = kfp->sf_sc.sc_ps;
hkfp->hsf_sc.hsc_pc = kfp->sf_sc.sc_pc;
hkfp->hsf_sc.hsc_pad = 0;
hkfp->hsf_sc.hsc_magic = 0xdeadbeef;
hkfp->hsf_sc.hsc_realsc = kfp->sf_scp;
bcopy((caddr_t)frame->f_regs, (caddr_t)hkfp->hsf_regs,
sizeof (hkfp->hsf_regs));
kfp->sf_signum = hkfp->hsf_signum;
kfp->sf_scp = hkfp->hsf_scp;
}
#endif
(void) copyout((caddr_t)kfp, (caddr_t)fp, fsize);
frame->f_regs[SP] = (int)fp;
#ifdef DEBUG
if (sigdebug & SDB_FOLLOW)
printf("sendsig(%d): sig %d scp %x fp %x sc_sp %x sc_ap %x\n",
p->p_pid, sig, kfp->sf_scp, fp,
kfp->sf_sc.sc_sp, kfp->sf_sc.sc_ap);
#endif
/*
* Signal trampoline code is at base of user stack.
*/
frame->f_pc = USRSTACK - sizeof(u.u_pcb.pcb_sigc);
#ifdef DEBUG
if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid)
printf("sendsig(%d): sig %d returns\n",
p->p_pid, sig);
#endif
free((caddr_t)kfp, M_TEMP);
}
/*
* 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
* a machine fault.
*/
/* ARGSUSED */
sigreturn(p, uap, retval)
struct proc *p;
struct args {
struct sigcontext *sigcntxp;
} *uap;
int *retval;
{
register struct sigcontext *scp;
register struct frame *frame;
register int rf;
struct sigcontext tsigc;
struct sigstate tstate;
int flags;
scp = uap->sigcntxp;
#ifdef DEBUG
if (sigdebug & SDB_FOLLOW)
printf("sigreturn: pid %d, scp %x\n", p->p_pid, scp);
#endif
if ((int)scp & 1)
return (EINVAL);
#ifdef HPUXCOMPAT
/*
* Grab context as an HP-UX style context and determine if it
* was one that we contructed in sendsig.
*/
if (p->p_flag & SHPUX) {
struct hpuxsigcontext *hscp = (struct hpuxsigcontext *)scp;
struct hpuxsigcontext htsigc;
if (useracc((caddr_t)hscp, sizeof (*hscp), B_WRITE) == 0 ||
copyin((caddr_t)hscp, (caddr_t)&htsigc, sizeof htsigc))
return (EINVAL);
/*
* If not generated by sendsig or we cannot restore the
* BSD-style sigcontext, just restore what we can -- state
* will be lost, but them's the breaks.
*/
hscp = &htsigc;
if (hscp->hsc_magic != 0xdeadbeef ||
(scp = hscp->hsc_realsc) == 0 ||
useracc((caddr_t)scp, sizeof (*scp), B_WRITE) == 0 ||
copyin((caddr_t)scp, (caddr_t)&tsigc, sizeof tsigc)) {
u.u_onstack = hscp->hsc_onstack & 01;
p->p_sigmask = hscp->hsc_mask &~ sigcantmask;
frame = (struct frame *) u.u_ar0;
frame->f_regs[SP] = hscp->hsc_sp;
frame->f_pc = hscp->hsc_pc;
frame->f_sr = hscp->hsc_ps &~ PSL_USERCLR;
return (EJUSTRETURN);
}
/*
* Otherwise, overlay BSD context with possibly modified
* HP-UX values.
*/
tsigc.sc_onstack = hscp->hsc_onstack;
tsigc.sc_mask = hscp->hsc_mask;
tsigc.sc_sp = hscp->hsc_sp;
tsigc.sc_ps = hscp->hsc_ps;
tsigc.sc_pc = hscp->hsc_pc;
} else
#endif
/*
* Test and fetch the context structure.
* We grab it all at once for speed.
*/
if (useracc((caddr_t)scp, sizeof (*scp), B_WRITE) == 0 ||
copyin((caddr_t)scp, (caddr_t)&tsigc, sizeof tsigc))
return (EINVAL);
scp = &tsigc;
if ((scp->sc_ps & (PSL_MBZ|PSL_IPL|PSL_S)) != 0)
return (EINVAL);
/*
* Restore the user supplied information
*/
u.u_onstack = scp->sc_onstack & 01;
p->p_sigmask = scp->sc_mask &~ sigcantmask;
frame = (struct frame *) u.u_ar0;
frame->f_regs[SP] = scp->sc_sp;
frame->f_regs[A6] = scp->sc_fp;
frame->f_pc = scp->sc_pc;
frame->f_sr = scp->sc_ps;
/*
* Grab pointer to hardware state information.
* If zero, the user is probably doing a longjmp.
*/
if ((rf = scp->sc_ap) == 0)
return (EJUSTRETURN);
/*
* See if there is anything to do before we go to the
* expense of copying in close to 1/2K of data
*/
flags = fuword((caddr_t)rf);
#ifdef DEBUG
if (sigdebug & SDB_FOLLOW)
printf("sigreturn(%d): sc_ap %x flags %x\n",
p->p_pid, rf, flags);
#endif
if (flags == 0 || copyin((caddr_t)rf, (caddr_t)&tstate, sizeof tstate))
return (EJUSTRETURN);
#ifdef DEBUG
if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid)
printf("sigreturn(%d): ssp %x usp %x scp %x ft %d\n",
p->p_pid, &flags, scp->sc_sp, uap->sigcntxp,
(flags&SS_RTEFRAME) ? tstate.ss_frame.f_format : -1);
#endif
/*
* Restore most of the users registers except for A6 and SP
* which were handled above.
*/
if (flags & SS_USERREGS)
bcopy((caddr_t)tstate.ss_frame.f_regs,
(caddr_t)frame->f_regs, sizeof(frame->f_regs)-2*NBPW);
/*
* Restore long stack frames. Note that we do not copy
* back the saved SR or PC, they were picked up above from
* the sigcontext structure.
*/
if (flags & SS_RTEFRAME) {
register int sz;
/* grab frame type and validate */
sz = tstate.ss_frame.f_format;
if (sz == FMT9)
sz = FMT9SIZE;
else if (sz == FMTA)
sz = FMTASIZE;
else if (sz == FMTB) {
sz = FMTBSIZE;
/* no k-stack adjustment necessary */
frame->f_stackadj = 0;
} else
return (EINVAL);
frame->f_format = tstate.ss_frame.f_format;
frame->f_vector = tstate.ss_frame.f_vector;
bcopy((caddr_t)&tstate.ss_frame.F_u, (caddr_t)&frame->F_u, sz);
#ifdef DEBUG
if (sigdebug & SDB_FOLLOW)
printf("sigreturn(%d): copy in %d of frame type %d\n",
p->p_pid, sz, tstate.ss_frame.f_format);
#endif
}
#ifdef FPCOPROC
/*
* Finally we restore the original FP context
*/
if (flags & SS_FPSTATE)
m68881_restore(&tstate.ss_fpstate);
#ifdef DEBUG
if ((sigdebug & SDB_FPSTATE) && *(char *)&tstate.ss_fpstate)
printf("sigreturn(%d): copied in FP state (%x) at %x\n",
p->p_pid, *(u_int *)&tstate.ss_fpstate,
&tstate.ss_fpstate);
#endif
#endif
#ifdef DEBUG
if ((sigdebug & SDB_FOLLOW) ||
((sigdebug & SDB_KSTACK) && p->p_pid == sigpid))
printf("sigreturn(%d): returns\n", p->p_pid);
#endif
return (EJUSTRETURN);
}
int waittime = -1;
boot(howto)
register int howto;
{
/* take a snap shot before clobbering any registers */
if (u.u_procp)
resume((u_int)pcbb(u.u_procp));
boothowto = howto;
if ((howto&RB_NOSYNC) == 0 && waittime < 0 && bfreelist[0].b_forw) {
register struct buf *bp;
int iter, nbusy;
waittime = 0;
(void) spl0();
printf("syncing disks... ");
/*
* Release vnodes held by texts before sync.
*/
if (panicstr == 0)
vnode_pager_umount(NULL);
#include "fd.h"
#if NFD > 0
fdshutdown();
#endif
sync((struct sigcontext *)0);
for (iter = 0; iter < 20; iter++) {
nbusy = 0;
for (bp = &buf[nbuf]; --bp >= buf; )
if ((bp->b_flags & (B_BUSY|B_INVAL)) == B_BUSY)
nbusy++;
if (nbusy == 0)
break;
printf("%d ", nbusy);
DELAY(40000 * iter);
}
if (nbusy)
printf("giving up\n");
else
printf("done\n");
/*
* If we've been adjusting the clock, the todr
* will be out of synch; adjust it now.
*/
resettodr();
}
splhigh(); /* extreme priority */
if (howto&RB_HALT) {
printf("halted\n\n");
asm(" stop #0x2700");
} else {
if (howto & RB_DUMP)
dumpsys();
doboot();
/*NOTREACHED*/
}
/*NOTREACHED*/
}
int dumpmag = 0x8fca0101; /* magic number for savecore */
int dumpsize = 0; /* also for savecore */
dumpconf()
{
int nblks;
dumpsize = physmem;
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));
else if (dumplo == 0)
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))
dumplo = btodb(CLBYTES);
}
/*
* Doadump comes here after turning off memory management and
* getting on the dump stack, either when called above, or by
* the auto-restart code.
*/
dumpsys()
{
msgbufmapped = 0;
if (dumpdev == NODEV)
return;
/*
* For dumps during autoconfiguration,
* if dump device has already configured...
*/
if (dumpsize == 0)
dumpconf();
if (dumplo < 0)
return;
printf("\ndumping to dev %x, offset %d\n", dumpdev, dumplo);
printf("dump ");
switch ((*bdevsw[major(dumpdev)].d_dump)(dumpdev)) {
case ENXIO:
printf("device bad\n");
break;
case EFAULT:
printf("device not ready\n");
break;
case EINVAL:
printf("area improper\n");
break;
case EIO:
printf("i/o error\n");
break;
default:
printf("succeeded\n");
break;
}
}
/*
* Return the best possible estimate of the time in the timeval
* to which tvp points. We do this by returning the current time
* plus the amount of time since the last clock interrupt (clock.c:clkread).
*
* Check that this time is no less than any previously-reported time,
* which could happen around the time of a clock adjustment. Just for fun,
* we guarantee that the time will be greater than the value obtained by a
* previous call.
*/
microtime(tvp)
register struct timeval *tvp;
{
int s = splhigh();
static struct timeval lasttime;
*tvp = time;
tvp->tv_usec += clkread();
while (tvp->tv_usec > 1000000) {
tvp->tv_sec++;
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) {
tvp->tv_sec++;
tvp->tv_usec -= 1000000;
}
lasttime = *tvp;
splx(s);
}
initcpu()
{
parityenable();
}
straytrap(addr)
register int addr;
{
printf("stray trap, addr 0x%x\n", addr);
}
int *nofault;
badaddr(addr)
register caddr_t addr;
{
register int i;
label_t faultbuf;
#ifdef lint
i = *addr; if (i) return(0);
#endif
nofault = (int *) &faultbuf;
if (setjmp((label_t *)nofault)) {
nofault = (int *) 0;
return(1);
}
i = *(volatile short *)addr;
nofault = (int *) 0;
return(0);
}
badbaddr(addr)
register caddr_t addr;
{
register int i;
label_t faultbuf;
#ifdef lint
i = *addr; if (i) return(0);
#endif
nofault = (int *) &faultbuf;
if (setjmp((label_t *)nofault)) {
nofault = (int *) 0;
return(1);
}
i = *(volatile char *)addr;
nofault = (int *) 0;
return(0);
}
netintr()
{
#ifdef INET
if (netisr & (1 << NETISR_IP)) {
netisr &= ~(1 << NETISR_IP);
ipintr();
}
#endif
#ifdef NS
if (netisr & (1 << NETISR_NS)) {
netisr &= ~(1 << NETISR_NS);
nsintr();
}
#endif
#ifdef ISO
if (netisr & (1 << NETISR_ISO)) {
netisr &= ~(1 << NETISR_ISO);
clnlintr();
}
#endif
}
intrhand(sr)
int sr;
{
register struct isr *isr;
register int found = 0;
register int ipl;
extern struct isr isrqueue[];
ipl = (sr >> 8) & 7;
switch (ipl) {
case 3:
case 4:
case 5:
ipl = ISRIPL(ipl);
isr = isrqueue[ipl].isr_forw;
for (; isr != &isrqueue[ipl]; isr = isr->isr_forw) {
if ((isr->isr_intr)(isr->isr_arg)) {
found++;
break;
}
}
if (found == 0)
printf("stray interrupt, sr 0x%x\n", sr);
break;
case 0:
case 1:
case 2:
case 6:
case 7:
printf("intrhand: unexpected sr 0x%x\n", sr);
break;
}
}
#if defined(DEBUG) && !defined(PANICBUTTON)
#define PANICBUTTON
#endif
#ifdef PANICBUTTON
int panicbutton = 1; /* non-zero if panic buttons are enabled */
int crashandburn = 0;
int candbdelay = 50; /* give em half a second */
candbtimer()
{
crashandburn = 0;
}
#endif
/*
* Level 7 interrupts can be caused by the keyboard or parity errors.
*/
nmihand(frame)
struct frame frame;
{
if (kbdnmi()) {
#ifdef PANICBUTTON
printf("Got a keyboard NMI\n");
if (panicbutton) {
if (crashandburn) {
crashandburn = 0;
panic(panicstr ?
"forced crash, nosync" : "forced crash");
}
crashandburn++;
timeout(candbtimer, (caddr_t)0, candbdelay);
}
#endif
return;
}
if (parityerror(&frame))
return;
/* panic?? */
printf("unexpected level 7 interrupt ignored\n");
}
/*
* Parity error section. Contains magic.
*/
#define PARREG ((volatile short *)IOV(0x5B0000))
static int gotparmem = 0;
#ifdef DEBUG
int ignorekperr = 0; /* ignore kernel parity errors */
#endif
/*
* Enable parity detection
*/
parityenable()
{
label_t faultbuf;
nofault = (int *) &faultbuf;
if (setjmp((label_t *)nofault)) {
nofault = (int *) 0;
#ifdef DEBUG
printf("No parity memory\n");
#endif
return;
}
*PARREG = 1;
nofault = (int *) 0;
gotparmem = 1;
#ifdef DEBUG
printf("Parity detection enabled\n");
#endif
}
/*
* Determine if level 7 interrupt was caused by a parity error
* and deal with it if it was. Returns 1 if it was a parity error.
*/
parityerror(fp)
struct frame *fp;
{
if (!gotparmem)
return(0);
*PARREG = 0;
DELAY(10);
*PARREG = 1;
if (panicstr) {
printf("parity error after panic ignored\n");
return(1);
}
if (!findparerror())
printf("WARNING: transient parity error ignored\n");
else if (USERMODE(fp->f_sr)) {
printf("pid %d: parity error\n", u.u_procp->p_pid);
uprintf("sorry, pid %d killed due to memory parity error\n",
u.u_procp->p_pid);
psignal(u.u_procp, SIGKILL);
#ifdef DEBUG
} else if (ignorekperr) {
printf("WARNING: kernel parity error ignored\n");
#endif
} else {
regdump(fp->f_regs, 128);
panic("kernel parity error");
}
return(1);
}
/*
* Yuk! There has got to be a better way to do this!
* Searching all of memory with interrupts blocked can lead to disaster.
*/
findparerror()
{
static label_t parcatch;
static int looking = 0;
volatile struct pte opte;
volatile int pg, o, s;
register volatile int *ip;
register int i;
int found;
#ifdef lint
ip = &found;
i = o = pg = 0; if (i) return(0);
#endif
/*
* If looking is true we are searching for a known parity error
* and it has just occured. All we do is return to the higher
* level invocation.
*/
if (looking)
longjmp(&parcatch);
s = splhigh();
/*
* If setjmp returns true, the parity error we were searching
* for has just occured (longjmp above) at the current pg+o
*/
if (setjmp(&parcatch)) {
printf("Parity error at 0x%x\n", ctob(pg)|o);
found = 1;
goto done;
}
/*
* If we get here, a parity error has occured for the first time
* and we need to find it. We turn off any external caches and
* loop thru memory, testing every longword til a fault occurs and
* we regain control at setjmp above. Note that because of the
* setjmp, pg and o need to be volatile or their values will be lost.
*/
looking = 1;
ecacheoff();
for (pg = btoc(lowram); pg < btoc(lowram)+physmem; pg++) {
pmap_enter(pmap_kernel(), vmmap, ctob(pg), VM_PROT_READ, TRUE);
for (o = 0; o < NBPG; o += sizeof(int))
i = *(int *)(&vmmap[o]);
}
/*
* Getting here implies no fault was found. Should never happen.
*/
printf("Couldn't locate parity error\n");
found = 0;
done:
looking = 0;
pmap_remove(pmap_kernel(), vmmap, &vmmap[NBPG]);
ecacheon();
splx(s);
return(found);
}
regdump(rp, sbytes)
int *rp; /* must not be register */
int sbytes;
{
static int doingdump = 0;
register int i;
int s;
extern char *hexstr();
if (doingdump)
return;
s = splhigh();
doingdump = 1;
printf("pid = %d, pc = %s, ", u.u_procp->p_pid, hexstr(rp[PC], 8));
printf("ps = %s, ", hexstr(rp[PS], 4));
printf("sfc = %s, ", hexstr(getsfc(), 4));
printf("dfc = %s\n", hexstr(getdfc(), 4));
printf("Registers:\n ");
for (i = 0; i < 8; i++)
printf(" %d", i);
printf("\ndreg:");
for (i = 0; i < 8; i++)
printf(" %s", hexstr(rp[i], 8));
printf("\nareg:");
for (i = 0; i < 8; i++)
printf(" %s", hexstr(rp[i+8], 8));
if (sbytes > 0) {
if (rp[PS] & PSL_S) {
printf("\n\nKernel stack (%s):",
hexstr((int)(((int *)&rp)-1), 8));
dumpmem(((int *)&rp)-1, sbytes, 0);
} else {
printf("\n\nUser stack (%s):", hexstr(rp[SP], 8));
dumpmem((int *)rp[SP], sbytes, 1);
}
}
doingdump = 0;
splx(s);
}
#define KSADDR ((int *)&(((char *)&u)[(UPAGES-1)*NBPG]))
dumpmem(ptr, sz, ustack)
register int *ptr;
int sz;
{
register int i, val;
extern char *hexstr();
for (i = 0; i < sz; i++) {
if ((i & 7) == 0)
printf("\n%s: ", hexstr((int)ptr, 6));
else
printf(" ");
if (ustack == 1) {
if ((val = fuword(ptr++)) == -1)
break;
} else {
if (ustack == 0 && (ptr < KSADDR || ptr > KSADDR+(NBPG/4-1)))
break;
val = *ptr++;
}
printf("%s", hexstr(val, 8));
}
printf("\n");
}
char *
hexstr(val, len)
register int val;
{
static char nbuf[9];
register int x, i;
if (len > 8)
return("");
nbuf[len] = '\0';
for (i = len-1; i >= 0; --i) {
x = val & 0xF;
if (x > 9)
nbuf[i] = x - 10 + 'A';
else
nbuf[i] = x + '0';
val >>= 4;
}
return(nbuf);
}