-/* $OpenBSD: hpux_machdep.c,v 1.3 1997/01/12 15:13:16 downsj Exp $ */
-/* $NetBSD: hpux_machdep.c,v 1.5 1996/10/14 06:51:50 thorpej Exp $ */
+/* $OpenBSD: hpux_machdep.c,v 1.4 1997/03/26 08:32:41 downsj Exp $ */
+/* $NetBSD: hpux_machdep.c,v 1.9 1997/03/16 10:00:45 thorpej Exp $ */
/*
- * Copyright (c) 1995, 1996 Jason R. Thorpe. All rights reserved.
+ * Copyright (c) 1995, 1996, 1997 Jason R. Thorpe. All rights reserved.
* Copyright (c) 1988 University of Utah.
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
#include <machine/hpux_machdep.h>
+extern short exframesize[];
+
#define NHIL 1 /* XXX */
#include "grf.h"
extern int hilopen __P((dev_t dev, int oflags, int devtype, struct proc *p));
#endif
-static struct {
- int machine_id;
- char *machine_str;
-} machine_table[] = {
+struct valtostr {
+ int val;
+ const char *str;
+};
+
+static struct valtostr machine_table[] = {
{ HP_320, "320" },
{ HP_330, "330" }, /* includes 318 and 319 */
{ HP_340, "340" },
{ -1, "3?0" }, /* unknown system (???) */
};
-/* 6.0 and later style context */
-#ifdef M68040
-static char hpux_040context[] =
- "standalone HP-MC68040 HP-MC68881 HP-MC68020 HP-MC68010 localroot default";
-#endif
-#ifdef FPCOPROC
-static char hpux_context[] =
- "standalone HP-MC68881 HP-MC68020 HP-MC68010 localroot default";
-#else
-static char hpux_context[] =
- "standalone HP-MC68020 HP-MC68010 localroot default";
-#endif
+/*
+ * 6.0 and later context.
+ * XXX what are the HP-UX "localroot" semantics? Should we handle
+ * XXX diskless systems here?
+ */
+static struct valtostr context_table[] = {
+ { FPU_68040,
+ "standalone HP-MC68040 HP-MC68881 HP-MC68020 HP-MC68010 localroot default"
+ },
+ { FPU_68881,
+ "standalone HP-MC68881 HP-MC68020 HP-MC68010 localroot default"
+ },
+ { FPU_NONE,
+ "standalone HP-MC68020 HP-MC68010 localroot default"
+ },
+ { 0, NULL },
+};
#define UOFF(f) ((int)&((struct user *)0)->f)
#define HPUOFF(f) ((int)&((struct hpux_user *)0)->f)
* Find the current machine-ID in the table and
* copy the string into the uname.
*/
- for (i = 0; machine_table[i].machine_id != -1; ++i)
- if (machine_table[i].machine_id == machineid)
+ for (i = 0; machine_table[i].val != -1; ++i)
+ if (machine_table[i].val == machineid)
break;
- sprintf(ut->machine, "9000/%s", machine_table[i].machine_str);
+ sprintf(ut->machine, "9000/%s", machine_table[i].str);
}
/*
register_t *retval;
{
struct hpux_sys_getcontext_args *uap = v;
- int error = 0;
+ int l, i, error = 0;
register int len;
-#ifdef M68040
- if ((machineid == HP_380) || (machineid == HP_433)) {
- len = min(SCARG(uap, len), sizeof(hpux_040context));
- if (len)
- error = copyout(hpux_040context, SCARG(uap, buf), len);
- if (error == 0)
- *retval = sizeof(hpux_040context);
- return (error);
+ for (i = 0; context_table[i].str != NULL; i++)
+ if (context_table[i].val == fputype)
+ break;
+ if (context_table[i].str == NULL) {
+ /*
+ * XXX What else? It's not like this can happen...
+ */
+ return (EINVAL);
}
-#endif
- len = min(SCARG(uap, len), sizeof(hpux_context));
+
+ /* + 1 ... count the terminating \0. */
+ l = strlen(context_table[i].str) + 1;
+ len = min(SCARG(uap, len), l);
+
if (len)
- error = copyout(hpux_context, SCARG(uap, buf), (u_int)len);
+ error = copyout(context_table[i].str, SCARG(uap, buf), len);
if (error == 0)
- *retval = sizeof(hpux_context);
- return (error);
+ *retval = l;
+ return (0);
}
/*
if ((int)off == HPUOFF(hpuxu_ar0))
return(UOFF(U_ar0));
+ if (fputype) {
+ /* FP registers from PCB */
+ hp = (struct hpux_fp *)HPUOFF(hpuxu_fp);
+ bp = (struct bsdfp *)UOFF(u_pcb.pcb_fpregs);
-#ifdef FPCOPROC
- /* FP registers from PCB */
- hp = (struct hpux_fp *)HPUOFF(hpuxu_fp);
- bp = (struct bsdfp *)UOFF(u_pcb.pcb_fpregs);
-
- if (off >= hp->hpfp_ctrl && off < &hp->hpfp_ctrl[3])
- return((int)&bp->ctrl[off - hp->hpfp_ctrl]);
+ if (off >= hp->hpfp_ctrl && off < &hp->hpfp_ctrl[3])
+ return((int)&bp->ctrl[off - hp->hpfp_ctrl]);
- if (off >= hp->hpfp_reg && off < &hp->hpfp_reg[24])
- return((int)&bp->reg[off - hp->hpfp_reg]);
-#endif
+ if (off >= hp->hpfp_reg && off < &hp->hpfp_reg[24])
+ return((int)&bp->reg[off - hp->hpfp_reg]);
+ }
/*
* Everything else we recognize comes from the kernel stack,
return (-1);
}
+#define HSS_RTEFRAME 0x01
+#define HSS_FPSTATE 0x02
+#define HSS_USERREGS 0x04
+
+struct hpuxsigstate {
+ int hss_flags; /* which of the following are valid */
+ struct frame hss_frame; /* original exception frame */
+ struct fpframe hss_fpstate; /* 68881/68882 state info */
+};
+
/*
- * Kludge up a uarea dump so that HP-UX debuggers can find out
- * what they need. IMPORTANT NOTE: we do not EVEN attempt to
- * convert the entire user struct.
+ * WARNING: code in locore.s assumes the layout shown here for hsf_signum
+ * thru hsf_handler so... don't screw with them!
*/
-int
-hpux_dumpu(vp, cred)
- struct vnode *vp;
- struct ucred *cred;
+struct hpuxsigframe {
+ int hsf_signum; /* signo for handler */
+ int hsf_code; /* additional info for handler */
+ struct hpuxsigcontext *hsf_scp; /* context ptr for handler */
+ sig_t hsf_handler; /* handler addr for u_sigc */
+ struct hpuxsigstate hsf_sigstate; /* state of the hardware */
+ struct hpuxsigcontext hsf_sc; /* actual context */
+};
+
+#ifdef DEBUG
+int hpuxsigdebug = 0;
+int hpuxsigpid = 0;
+#define SDB_FOLLOW 0x01
+#define SDB_KSTACK 0x02
+#define SDB_FPSTATE 0x04
+#endif
+
+/*
+ * Send an interrupt to process.
+ */
+/* ARGSUSED */
+void
+hpux_sendsig(catcher, sig, mask, code, type, val)
+ sig_t catcher;
+ int sig, mask;
+ u_long code;
+ int type;
+ union sigval val;
{
- int error = 0;
- struct proc *p = curproc;
- struct hpux_user *faku;
- struct bsdfp *bp;
- short *foop;
+ register struct proc *p = curproc;
+ register struct hpuxsigframe *kfp, *fp;
+ register struct frame *frame;
+ register struct sigacts *psp = p->p_sigacts;
+ register short ft;
+ int oonstack, fsize;
+ extern char sigcode[], esigcode[];
+
+ frame = (struct frame *)p->p_md.md_regs;
+ ft = frame->f_format;
+ oonstack = psp->ps_sigstk.ss_flags & SS_ONSTACK;
/*
- * Make sure there is no mistake about this being a real
- * user structure.
+ * 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'.
*/
- faku = (struct hpux_user *)malloc((u_long)ctob(1), M_TEMP, M_WAITOK);
- bzero((caddr_t)faku, ctob(1));
+ fsize = sizeof(struct hpuxsigframe);
+ if ((psp->ps_flags & SAS_ALTSTACK) && !oonstack &&
+ (psp->ps_sigonstack & sigmask(sig))) {
+ fp = (struct hpuxsigframe *)(psp->ps_sigstk.ss_sp +
+ psp->ps_sigstk.ss_size - fsize);
+ psp->ps_sigstk.ss_flags |= SS_ONSTACK;
+ } else
+ fp = (struct hpuxsigframe *)(frame->f_regs[SP] - fsize);
+ if ((unsigned)fp <= USRSTACK - ctob(p->p_vmspace->vm_ssize))
+ (void)grow(p, (unsigned)fp);
+
+#ifdef DEBUG
+ if ((hpuxsigdebug & SDB_KSTACK) && p->p_pid == hpuxsigpid)
+ printf("hpux_sendsig(%d): sig %d ssp %x usp %x scp %x ft %d\n",
+ p->p_pid, sig, &oonstack, fp, &fp->sf_sc, ft);
+#endif
- /* Fill in the process sizes. */
- faku->hpuxu_tsize = p->p_vmspace->vm_tsize;
- faku->hpuxu_dsize = p->p_vmspace->vm_dsize;
- faku->hpuxu_ssize = p->p_vmspace->vm_ssize;
+ if (useracc((caddr_t)fp, fsize, B_WRITE) == 0) {
+#ifdef DEBUG
+ if ((hpuxsigdebug & SDB_KSTACK) && p->p_pid == hpuxsigpid)
+ printf("hpux_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 hpuxsigframe *)malloc((u_long)fsize, M_TEMP, M_WAITOK);
+
+ /*
+ * Build the argument list for the signal handler.
+ */
+ kfp->hsf_signum = bsdtohpuxsig(sig);
+ kfp->hsf_code = code;
+ kfp->hsf_scp = &fp->hsf_sc;
+ kfp->hsf_handler = catcher;
/*
- * Fill in the exec header for CDB.
- * This was saved back in exec(). As far as I can tell CDB
- * only uses this information to verify that a particular
- * core file goes with a particular binary.
+ * Save necessary hardware state. Currently this includes:
+ * - general registers
+ * - original exception frame (if not a "normal" frame)
+ * - FP coprocessor state
*/
- bcopy((caddr_t)p->p_addr->u_md.md_exec,
- (caddr_t)&faku->hpuxu_exdata, sizeof (struct hpux_exec));
+ kfp->hsf_sigstate.hss_flags = HSS_USERREGS;
+ bcopy((caddr_t)frame->f_regs,
+ (caddr_t)kfp->hsf_sigstate.hss_frame.f_regs, sizeof frame->f_regs);
+ if (ft >= FMT7) {
+#ifdef DEBUG
+ if (ft > 15 || exframesize[ft] < 0)
+ panic("hpux_sendsig: bogus frame type");
+#endif
+ kfp->hsf_sigstate.hss_flags |= HSS_RTEFRAME;
+ kfp->hsf_sigstate.hss_frame.f_format = frame->f_format;
+ kfp->hsf_sigstate.hss_frame.f_vector = frame->f_vector;
+ bcopy((caddr_t)&frame->F_u,
+ (caddr_t)&kfp->hsf_sigstate.hss_frame.F_u, exframesize[ft]);
+
+ /*
+ * 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 to the amount the stack must be
+ * adjusted by.
+ *
+ * N.B. we increment rather than just set f_stackadj in
+ * case we are called from syscall when processing a
+ * sigreturn. In that case, f_stackadj may be non-zero.
+ */
+ frame->f_stackadj += exframesize[ft];
+ frame->f_format = frame->f_vector = 0;
+#ifdef DEBUG
+ if (hpuxsigdebug & SDB_FOLLOW)
+ printf("hpux_sendsig(%d): copy out %d of frame %d\n",
+ p->p_pid, exframesize[ft], ft);
+#endif
+ }
+ if (fputype) {
+ kfp->hsf_sigstate.hss_flags |= HSS_FPSTATE;
+ m68881_save(&kfp->hsf_sigstate.hss_fpstate);
+ }
+
+#ifdef DEBUG
+ if ((hpuxsigdebug & SDB_FPSTATE) && *(char *)&kfp->sf_state.ss_fpstate)
+ printf("hpux_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
/*
- * Adjust user's saved registers (on kernel stack) to reflect
- * HP-UX order. Note that HP-UX saves the SR as 2 bytes not 4
- * so we have to move it up.
+ * Build the signal context to be used by hpux_sigreturn.
*/
- faku->hpuxu_ar0 = p->p_md.md_regs;
- foop = (short *) p->p_md.md_regs;
- foop[32] = foop[33];
- foop[33] = foop[34];
- foop[34] = foop[35];
+ kfp->hsf_sc.hsc_syscall = 0; /* XXX */
+ kfp->hsf_sc.hsc_action = 0; /* XXX */
+ kfp->hsf_sc.hsc_pad1 = kfp->hsf_sc.hsc_pad2 = 0;
+ kfp->hsf_sc.hsc_onstack = oonstack;
+ kfp->hsf_sc.hsc_mask = mask;
+ kfp->hsf_sc.hsc_sp = frame->f_regs[SP];
+ kfp->hsf_sc.hsc_ps = frame->f_sr;
+ kfp->hsf_sc.hsc_pc = frame->f_pc;
+
+ /* How amazingly convenient! */
+ kfp->hsf_sc._hsc_pad = 0;
+ kfp->hsf_sc._hsc_ap = (int)&fp->hsf_sigstate;
+
+ (void) copyout((caddr_t)kfp, (caddr_t)fp, fsize);
+ frame->f_regs[SP] = (int)fp;
+
+#ifdef DEBUG
+ if (hpuxsigdebug & SDB_FOLLOW) {
+ printf(
+ "hpux_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
-#ifdef FPCOPROC
/*
- * Copy 68881 registers from our PCB format to HP-UX format
+ * Signal trampoline code is at base of user stack.
*/
- bp = (struct bsdfp *) &p->p_addr->u_pcb.pcb_fpregs;
- bcopy((caddr_t)bp->save, (caddr_t)faku->hpuxu_fp.hpfp_save,
- sizeof(bp->save));
- bcopy((caddr_t)bp->ctrl, (caddr_t)faku->hpuxu_fp.hpfp_ctrl,
- sizeof(bp->ctrl));
- bcopy((caddr_t)bp->reg, (caddr_t)faku->hpuxu_fp.hpfp_reg,
- sizeof(bp->reg));
+ frame->f_pc = (int)PS_STRINGS - (esigcode - sigcode);
+#ifdef DEBUG
+ if ((hpuxsigdebug & SDB_KSTACK) && p->p_pid == hpuxsigpid)
+ printf("hpux_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 */
+int
+hpux_sys_sigreturn(p, v, retval)
+ struct proc *p;
+ void *v;
+ register_t *retval;
+{
+ struct hpux_sys_sigreturn_args /* {
+ syscallarg(struct hpuxsigcontext *) sigcntxp;
+ } */ *uap = v;
+ register struct hpuxsigcontext *scp;
+ register struct frame *frame;
+ register int rf;
+ struct hpuxsigcontext tsigc;
+ struct hpuxsigstate tstate;
+ int flags;
+
+ scp = SCARG(uap, sigcntxp);
+#ifdef DEBUG
+ if (hpuxsigdebug & SDB_FOLLOW)
+ printf("sigreturn: pid %d, scp %x\n", p->p_pid, scp);
#endif
+ if ((int)scp & 1)
+ return (EINVAL);
/*
- * Slay the dragon
+ * Fetch and test the HP-UX context structure.
+ * We grab it all at once for speed.
*/
- faku->hpuxu_dragon = -1;
+ 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->hsc_ps & (PSL_MBZ|PSL_IPL|PSL_S)) != 0)
+ return (EINVAL);
/*
- * Dump this artfully constructed page in place of the
- * user struct page.
+ * Restore the user supplied information
*/
- error = vn_rdwr(UIO_WRITE, vp, (caddr_t)faku, ctob(1), (off_t)0,
- UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *)NULL, p);
+ if (scp->hsc_onstack & 01)
+ p->p_sigacts->ps_sigstk.ss_flags |= SS_ONSTACK;
+ else
+ p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK;
+ p->p_sigmask = scp->hsc_mask &~ sigcantmask;
+ frame = (struct frame *) p->p_md.md_regs;
+ frame->f_regs[SP] = scp->hsc_sp;
+ frame->f_pc = scp->hsc_pc;
+ frame->f_sr = scp->hsc_ps;
/*
- * Dump the remaining UPAGES-1 pages normally
- * XXX Spot the wild guess.
+ * Grab a pointer to the hpuxsigstate.
+ * If zero, the user is probably doing a longjmp.
+ * (This will never happen, really, since HP-UX doesn't
+ * know/care about the state pointer.)
*/
- if (error == 0)
- error = vn_rdwr(UIO_WRITE, vp, (caddr_t)p->p_addr + ctob(1),
- ctob(UPAGES-1), (off_t)ctob(1), UIO_SYSSPACE,
- IO_NODELOCKED|IO_UNIT, cred, (int *)NULL, p);
+ if ((rf = scp->_hsc_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 (hpuxsigdebug & SDB_FOLLOW)
+ printf("sigreturn(%d): sc_ap %x flags %x\n",
+ p->p_pid, rf, flags);
+#endif
+ /*
+ * fuword failed (bogus _hsc_ap value).
+ */
+ if (flags == -1)
+ return (EINVAL);
+ if (flags == 0 || copyin((caddr_t)rf, (caddr_t)&tstate, sizeof tstate))
+ return (EJUSTRETURN);
+#ifdef DEBUG
+ if ((hpuxsigdebug & SDB_KSTACK) && p->p_pid == hpuxsigpid)
+ printf("sigreturn(%d): ssp %x usp %x scp %x ft %d\n",
+ p->p_pid, &flags, scp->sc_sp, SCARG(uap, sigcntxp),
+ (flags & HSS_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 & HSS_USERREGS)
+ bcopy((caddr_t)tstate.hss_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 & HSS_RTEFRAME) {
+ register int sz;
+
+ /* grab frame type and validate */
+ sz = tstate.hss_frame.f_format;
+ if (sz > 15 || (sz = exframesize[sz]) < 0)
+ return (EINVAL);
+ frame->f_stackadj -= sz;
+ frame->f_format = tstate.hss_frame.f_format;
+ frame->f_vector = tstate.hss_frame.f_vector;
+ bcopy((caddr_t)&tstate.hss_frame.F_u,
+ (caddr_t)&frame->F_u, sz);
+#ifdef DEBUG
+ if (hpuxsigdebug & SDB_FOLLOW)
+ printf("sigreturn(%d): copy in %d of frame type %d\n",
+ p->p_pid, sz, tstate.ss_frame.f_format);
+#endif
+ }
- free((caddr_t)faku, M_TEMP);
+ /*
+ * Finally we restore the original FP context
+ */
+ if (flags & HSS_FPSTATE)
+ m68881_restore(&tstate.hss_fpstate);
+
+#ifdef DEBUG
+ if ((hpuxsigdebug & 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);
+
+ if ((hpuxsigdebug & SDB_FOLLOW) ||
+ ((hpuxsigdebug & SDB_KSTACK) && p->p_pid == hpuxsigpid))
+ printf("sigreturn(%d): returns\n", p->p_pid);
+#endif
+ return (EJUSTRETURN);
+}
- return (error);
+/*
+ * Set registers on exec.
+ * XXX Should clear registers except sp, pc.
+ */
+void
+hpux_setregs(p, pack, stack, retval)
+ register struct proc *p;
+ struct exec_package *pack;
+ u_long stack;
+ register_t *retval;
+{
+ struct frame *frame = (struct frame *)p->p_md.md_regs;
+
+ frame->f_pc = pack->ep_entry & ~1;
+ frame->f_regs[SP] = stack;
+ frame->f_regs[A2] = (int)PS_STRINGS;
+
+ /* restore a null state frame */
+ p->p_addr->u_pcb.pcb_fpregs.fpf_null = 0;
+ if (fputype)
+ m68881_restore(&p->p_addr->u_pcb.pcb_fpregs);
+
+ p->p_md.md_flags &= ~MDP_HPUXMMAP;
+ frame->f_regs[A0] = 0; /* not 68010 (bit 31), no FPA (30) */
+ retval[0] = 0; /* no float card */
+ if (fputype)
+ retval[1] = 1; /* yes 68881 */
+ else
+ retval[1] = 0; /* no 68881 */
}
-/* $OpenBSD: locore.s,v 1.12 1997/02/23 21:42:54 downsj Exp $ */
-/* $NetBSD: locore.s,v 1.63 1997/02/02 07:55:52 thorpej Exp $ */
+/* $OpenBSD: locore.s,v 1.13 1997/03/26 08:32:41 downsj Exp $ */
+/* $NetBSD: locore.s,v 1.67 1997/03/16 10:49:43 thorpej Exp $ */
/*
* Copyright (c) 1997 Theo de Raadt
*/
#include "assym.h"
+#include <machine/trap.h>
#define MMUADDR(ar) movl _MMUbase,ar
#define CLKADDR(ar) movl _CLKbase,ar
.text
/*
- * Do a dump.
- * Called by auto-restart.
- */
- .globl _dumpsys
- .globl _doadump
-_doadump:
- jbsr _dumpsys
- jbsr _doboot
- /*NOTREACHED*/
-
-/*
- * Trap/interrupt vector routines
- */
-
- .globl _trap, _nofault, _longjmp
-_buserr:
- /*
- * XXX TODO: look at the mac68k _buserr and generalize
- * XXX the saving of the fault address so this routine
- * XXX can be shared.
- */
- tstl _nofault | device probe?
- jeq Lberr | no, handle as usual
- movl _nofault,sp@- | yes,
- jbsr _longjmp | longjmp(nofault)
-Lberr:
-#if defined(M68040)
-#if defined(M68020) || defined(M68030)
- cmpl #MMU_68040,_mmutype | 68040?
- jne _addrerr | no, skip
-#endif
- clrl sp@- | stack adjust count
- moveml #0xFFFF,sp@- | save user registers
- movl usp,a0 | save the user SP
- movl a0,sp@(FR_SP) | in the savearea
- lea sp@(FR_HW),a1 | grab base of HW berr frame
- moveq #0,d0
- movw a1@(12),d0 | grab SSW
- movl a1@(20),d1 | and fault VA
- btst #11,d0 | check for mis-aligned access
- jeq Lberr2 | no, skip
- addl #3,d1 | yes, get into next page
- andl #PG_FRAME,d1 | and truncate
-Lberr2:
- movl d1,sp@- | push fault VA
- movl d0,sp@- | and padded SSW
- btst #10,d0 | ATC bit set?
- jeq Lisberr | no, must be a real bus error
- movc dfc,d1 | yes, get MMU fault
- movc d0,dfc | store faulting function code
- movl sp@(4),a0 | get faulting address
- .word 0xf568 | ptestr a0@
- movc d1,dfc
- .long 0x4e7a0805 | movc mmusr,d0
- movw d0,sp@ | save (ONLY LOW 16 BITS!)
- jra Lismerr
-#endif
-_addrerr:
- clrl sp@- | stack adjust count
- moveml #0xFFFF,sp@- | save user registers
- movl usp,a0 | save the user SP
- movl a0,sp@(FR_SP) | in the savearea
- lea sp@(FR_HW),a1 | grab base of HW berr frame
-#if defined(M68040)
-#if defined(M68020) || defined(M68030)
- cmpl #MMU_68040,_mmutype | 68040?
- jne Lbenot040 | no, skip
-#endif
- movl a1@(8),sp@- | yes, push fault address
- clrl sp@- | no SSW for address fault
- jra Lisaerr | go deal with it
-Lbenot040:
-#endif
- moveq #0,d0
- movw a1@(10),d0 | grab SSW for fault processing
- btst #12,d0 | RB set?
- jeq LbeX0 | no, test RC
- bset #14,d0 | yes, must set FB
- movw d0,a1@(10) | for hardware too
-LbeX0:
- btst #13,d0 | RC set?
- jeq LbeX1 | no, skip
- bset #15,d0 | yes, must set FC
- movw d0,a1@(10) | for hardware too
-LbeX1:
- btst #8,d0 | data fault?
- jeq Lbe0 | no, check for hard cases
- movl a1@(16),d1 | fault address is as given in frame
- jra Lbe10 | thats it
-Lbe0:
- btst #4,a1@(6) | long (type B) stack frame?
- jne Lbe4 | yes, go handle
- movl a1@(2),d1 | no, can use save PC
- btst #14,d0 | FB set?
- jeq Lbe3 | no, try FC
- addql #4,d1 | yes, adjust address
- jra Lbe10 | done
-Lbe3:
- btst #15,d0 | FC set?
- jeq Lbe10 | no, done
- addql #2,d1 | yes, adjust address
- jra Lbe10 | done
-Lbe4:
- movl a1@(36),d1 | long format, use stage B address
- btst #15,d0 | FC set?
- jeq Lbe10 | no, all done
- subql #2,d1 | yes, adjust address
-Lbe10:
- movl d1,sp@- | push fault VA
- movl d0,sp@- | and padded SSW
- movw a1@(6),d0 | get frame format/vector offset
- andw #0x0FFF,d0 | clear out frame format
- cmpw #12,d0 | address error vector?
- jeq Lisaerr | yes, go to it
-#if defined(M68K_MMU_MOTOROLA)
-#if defined(M68K_MMU_HP)
- tstl _mmutype | HP MMU?
- jeq Lbehpmmu | yes, skip
-#endif
- movl d1,a0 | fault address
- movl sp@,d0 | function code from ssw
- btst #8,d0 | data fault?
- jne Lbe10a
- movql #1,d0 | user program access FC
- | (we dont separate data/program)
- btst #5,a1@ | supervisor mode?
- jeq Lbe10a | if no, done
- movql #5,d0 | else supervisor program access
-Lbe10a:
- ptestr d0,a0@,#7 | do a table search
- pmove psr,sp@ | save result
- movb sp@,d1
- btst #2,d1 | invalid? (incl. limit viol and berr)
- jeq Lmightnotbemerr | no -> wp check
- btst #7,d1 | is it MMU table berr?
- jeq Lismerr | no, must be fast
- jra Lisberr1 | real bus err needs not be fast
-Lmightnotbemerr:
- btst #3,d1 | write protect bit set?
- jeq Lisberr1 | no, must be bus error
- movl sp@,d0 | ssw into low word of d0
- andw #0xc0,d0 | write protect is set on page:
- cmpw #0x40,d0 | was it read cycle?
- jeq Lisberr1 | yes, was not WPE, must be bus err
- jra Lismerr | no, must be mem err
-Lbehpmmu:
-#endif
-#if defined(M68K_MMU_HP)
- MMUADDR(a0)
- movl a0@(MMUSTAT),d0 | read status
- btst #3,d0 | MMU fault?
- jeq Lisberr | no, just a non-MMU bus error so skip
- andl #~MMU_FAULT,a0@(MMUSTAT)| yes, clear fault bits
- movw d0,sp@ | pass MMU stat in upper half of code
-#endif
-Lismerr:
- movl #T_MMUFLT,sp@- | show that we are an MMU fault
- jra Ltrapnstkadj | and deal with it
-Lisaerr:
- movl #T_ADDRERR,sp@- | mark address error
- jra Ltrapnstkadj | and deal with it
-Lisberr1:
- clrw sp@ | re-clear pad word
-Lisberr:
- movl #T_BUSERR,sp@- | mark bus error
-Ltrapnstkadj:
- jbsr _trap | handle the error
- lea sp@(12),sp | pop value args
- movl sp@(FR_SP),a0 | restore user SP
- movl a0,usp | from save area
- movw sp@(FR_ADJ),d0 | need to adjust stack?
- jne Lstkadj | yes, go to it
- moveml sp@+,#0x7FFF | no, restore most user regs
- addql #8,sp | toss SSP and stkadj
- jra rei | all done
-Lstkadj:
- lea sp@(FR_HW),a1 | pointer to HW frame
- addql #8,a1 | source pointer
- movl a1,a0 | source
- addw d0,a0 | + hole size = dest pointer
- movl a1@-,a0@- | copy
- movl a1@-,a0@- | 8 bytes
- movl a0,sp@(FR_SP) | new SSP
- moveml sp@+,#0x7FFF | restore user registers
- movl sp@,sp | and our SP
- jra rei | all done
-
-/*
- * FP exceptions.
- */
-_fpfline: /* XXXthorpej - candidate for vector patch */
-#if defined(M68040)
- cmpw #0x202c,sp@(6) | format type 2?
- jne _illinst | no, not an FP emulation
-#ifdef FPSP
- .globl fpsp_unimp
- jmp fpsp_unimp | yes, go handle it
-#else
- clrl sp@- | stack adjust count
- moveml #0xFFFF,sp@- | save registers
- moveq #T_FPEMULI,d0 | denote as FP emulation trap
- jra fault | do it
-#endif
-#else
- jra _illinst
-#endif
-
-_fpunsupp: /* XXXthorpej - candidate for vector patch */
-#if defined(M68040)
- cmpl #MMU_68040,_mmutype | 68040?
- jne _illinst | no, treat as illinst
-#ifdef FPSP
- .globl fpsp_unsupp
- jmp fpsp_unsupp | yes, go handle it
-#else
- clrl sp@- | stack adjust count
- moveml #0xFFFF,sp@- | save registers
- moveq #T_FPEMULD,d0 | denote as FP emulation trap
- jra fault | do it
-#endif
-#else
- jra _illinst
-#endif
-
-/*
- * Handles all other FP coprocessor exceptions.
- * Note that since some FP exceptions generate mid-instruction frames
- * and may cause signal delivery, we need to test for stack adjustment
- * after the trap call.
- */
- .globl _fpfault
-_fpfault:
-#ifdef FPCOPROC
- clrl sp@- | stack adjust count
- moveml #0xFFFF,sp@- | save user registers
- movl usp,a0 | and save
- movl a0,sp@(FR_SP) | the user stack pointer
- clrl sp@- | no VA arg
- movl _curpcb,a0 | current pcb
- lea a0@(PCB_FPCTX),a0 | address of FP savearea
- fsave a0@ | save state
-#if defined(M68040) || defined(M68060)
- /* always null state frame on 68040, 68060 */
- cmpl #MMU_68040,_mmutype
- jle Lfptnull
-#endif
- tstb a0@ | null state frame?
- jeq Lfptnull | yes, safe
- clrw d0 | no, need to tweak BIU
- movb a0@(1),d0 | get frame size
- bset #3,a0@(0,d0:w) | set exc_pend bit of BIU
-Lfptnull:
- fmovem fpsr,sp@- | push fpsr as code argument
- frestore a0@ | restore state
- movl #T_FPERR,sp@- | push type arg
- jra Ltrapnstkadj | call trap and deal with stack cleanup
-#else
- jra _badtrap | treat as an unexpected trap
-#endif
-
-/*
- * Coprocessor and format errors can generate mid-instruction stack
- * frames and cause signal delivery hence we need to check for potential
- * stack adjustment.
- */
-_coperr:
- clrl sp@- | stack adjust count
- moveml #0xFFFF,sp@-
- movl usp,a0 | get and save
- movl a0,sp@(FR_SP) | the user stack pointer
- clrl sp@- | no VA arg
- clrl sp@- | or code arg
- movl #T_COPERR,sp@- | push trap type
- jra Ltrapnstkadj | call trap and deal with stack adjustments
-
-_fmterr:
- clrl sp@- | stack adjust count
- moveml #0xFFFF,sp@-
- movl usp,a0 | get and save
- movl a0,sp@(FR_SP) | the user stack pointer
- clrl sp@- | no VA arg
- clrl sp@- | or code arg
- movl #T_FMTERR,sp@- | push trap type
- jra Ltrapnstkadj | call trap and deal with stack adjustments
-
-/*
- * Other exceptions only cause four and six word stack frame and require
- * no post-trap stack adjustment.
- */
-_illinst:
- clrl sp@-
- moveml #0xFFFF,sp@-
- moveq #T_ILLINST,d0
- jra fault
-
-_zerodiv:
- clrl sp@-
- moveml #0xFFFF,sp@-
- moveq #T_ZERODIV,d0
- jra fault
-
-_chkinst:
- clrl sp@-
- moveml #0xFFFF,sp@-
- moveq #T_CHKINST,d0
- jra fault
-
-_trapvinst:
- clrl sp@-
- moveml #0xFFFF,sp@-
- moveq #T_TRAPVINST,d0
- jra fault
-
-_privinst:
- clrl sp@-
- moveml #0xFFFF,sp@-
- moveq #T_PRIVINST,d0
- jra fault
-
- .globl fault
-fault:
- movl usp,a0 | get and save
- movl a0,sp@(FR_SP) | the user stack pointer
- clrl sp@- | no VA arg
- clrl sp@- | or code arg
- movl d0,sp@- | push trap type
- jbsr _trap | handle trap
- lea sp@(12),sp | pop value args
- movl sp@(FR_SP),a0 | restore
- movl a0,usp | user SP
- moveml sp@+,#0x7FFF | restore most user regs
- addql #8,sp | pop SP and stack adjust
- jra rei | all done
-
- .globl _straytrap
-_badtrap:
- moveml #0xC0C0,sp@- | save scratch regs
- movw sp@(22),sp@- | push exception vector info
- clrw sp@-
- movl sp@(22),sp@- | and PC
- jbsr _straytrap | report
- addql #8,sp | pop args
- moveml sp@+,#0x0303 | restore regs
- jra rei | all done
-
- .globl _syscall
-_trap0:
- clrl sp@- | stack adjust count
- moveml #0xFFFF,sp@- | save user registers
- movl usp,a0 | save the user SP
- movl a0,sp@(FR_SP) | in the savearea
- movl d0,sp@- | push syscall number
- jbsr _syscall | handle it
- addql #4,sp | pop syscall arg
- tstl _astpending
- jne Lrei2
- tstb _ssir
- jeq Ltrap1
- movw #SPL1,sr
- tstb _ssir
- jne Lsir1
-Ltrap1:
- movl sp@(FR_SP),a0 | grab and restore
- movl a0,usp | user SP
- moveml sp@+,#0x7FFF | restore most registers
- addql #8,sp | pop SP and stack adjust
- rte
-
-/*
- * Routines for traps 1 and 2. The meaning of the two traps depends
- * on whether we are an HPUX compatible process or a native 4.3 process.
- * Our native 4.3 implementation uses trap 1 as sigreturn() and trap 2
- * as a breakpoint trap. HPUX uses trap 1 for a breakpoint, so we have
- * to make adjustments so that trap 2 is used for sigreturn.
- */
-_trap1:
- btst #MDP_TRCB,mdpflag | being traced by an HPUX process?
- jeq sigreturn | no, trap1 is sigreturn
- jra _trace | yes, trap1 is breakpoint
-
-_trap2:
- btst #MDP_TRCB,mdpflag | being traced by an HPUX process?
- jeq _trace | no, trap2 is breakpoint
- jra sigreturn | yes, trap2 is sigreturn
-
-/*
- * Trap 12 is the entry point for the cachectl "syscall" (both HPUX & BSD)
- * cachectl(command, addr, length)
- * command in d0, addr in a1, length in d1
- */
- .globl _cachectl
-_trap12:
- movl d1,sp@- | push length
- movl a1,sp@- | push addr
- movl d0,sp@- | push command
- jbsr _cachectl | do it
- lea sp@(12),sp | pop args
- jra rei | all done
-
-/*
- * Trace (single-step) trap. Kernel-mode is special.
- * User mode traps are simply passed on to trap().
+ * Macro to relocate a symbol, used before MMU is enabled.
*/
-_trace:
- clrl sp@- | stack adjust count
- moveml #0xFFFF,sp@-
- moveq #T_TRACE,d0
- movw sp@(FR_HW),d1 | get PSW
- andw #PSL_S,d1 | from system mode?
- jne kbrkpt | yes, kernel breakpoint
- jra fault | no, user-mode fault
+#define RELOC(var, ar) \
+ lea var,ar; \
+ addl a5,ar
/*
- * Trap 15 is used for:
- * - GDB breakpoints (in user programs)
- * - KGDB breakpoints (in the kernel)
- * - trace traps for SUN binaries (not fully supported yet)
- * User mode traps are simply passed to trap().
+ * Initialization
+ *
+ * A4 contains the address of the end of the symtab
+ * A5 contains physical load point from boot
+ * VBR contains zero from ROM. Exceptions will continue to vector
+ * through ROM until MMU is turned on at which time they will vector
+ * through our table (vectors.s).
*/
-_trap15:
- clrl sp@- | stack adjust count
- moveml #0xFFFF,sp@-
- moveq #T_TRAP15,d0
- movw sp@(FR_HW),d1 | get PSW
- andw #PSL_S,d1 | from system mode?
- jne kbrkpt | yes, kernel breakpoint
- jra fault | no, user-mode fault
+ .comm _lowram,4
+ .comm _esym,4
-kbrkpt: | Kernel-mode breakpoint or trace trap. (d0=trap_type)
- | Save the system sp rather than the user sp.
- movw #PSL_HIGHIPL,sr | lock out interrupts
- lea sp@(FR_SIZE),a6 | Save stack pointer
- movl a6,sp@(FR_SP) | from before trap
+ .text
+ .globl _edata
+ .globl _etext,_end
+ .globl start
+start:
+ movw #PSL_HIGHIPL,sr | no interrupts
+ RELOC(tmpstk, a0)
+ movl a0,sp | give ourselves a temporary stack
+ RELOC(_esym, a0)
+#if 1
+ movl a4,a0@ | store end of symbol table
+#else
+ clrl a0@ | no symbol table, yet
+#endif
+ RELOC(_lowram, a0)
+ movl a5,a0@ | store start of physical memory
+ movl #CACHE_OFF,d0
+ movc d0,cacr | clear and disable on-chip cache(s)
- | If were are not on tmpstk switch to it.
- | (so debugger can change the stack pointer)
- movl a6,d1
- cmpl #tmpstk,d1
- jls Lbrkpt2 | already on tmpstk
- | Copy frame to the temporary stack
- movl sp,a0 | a0=src
- lea tmpstk-96,a1 | a1=dst
- movl a1,sp | sp=new frame
- moveq #FR_SIZE,d1
-Lbrkpt1:
- movl a0@+,a1@+
- subql #4,d1
- bgt Lbrkpt1
+/* check for internal HP-IB in SYSFLAG */
+ btst #5,0xfffffed2 | internal HP-IB?
+ jeq Lhaveihpib | yes, have HP-IB just continue
+ RELOC(_internalhpib, a0)
+ movl #0,a0@ | no, clear associated address
+Lhaveihpib:
-Lbrkpt2:
- | Call the trap handler for the kernel debugger.
- | Do not call trap() to do it, so that we can
- | set breakpoints in trap() if we want. We know
- | the trap type is either T_TRACE or T_BREAKPOINT.
- | If we have both DDB and KGDB, let KGDB see it first,
- | because KGDB will just return 0 if not connected.
- | Save args in d2, a2
- movl d0,d2 | trap type
- movl sp,a2 | frame ptr
-#ifdef KGDB
- | Let KGDB handle it (if connected)
- movl a2,sp@- | push frame ptr
- movl d2,sp@- | push trap type
- jbsr _kgdb_trap | handle the trap
- addql #8,sp | pop args
- cmpl #0,d0 | did kgdb handle it?
- jne Lbrkpt3 | yes, done
-#endif
-#ifdef DDB
- | Let DDB handle it
- movl a2,sp@- | push frame ptr
- movl d2,sp@- | push trap type
- jbsr _kdb_trap | handle the trap
- addql #8,sp | pop args
-#if 0 /* not needed on hp300 */
- cmpl #0,d0 | did ddb handle it?
- jne Lbrkpt3 | yes, done
-#endif
-#endif
- /* Sun 3 drops into PROM here. */
-Lbrkpt3:
- | The stack pointer may have been modified, or
- | data below it modified (by kgdb push call),
- | so push the hardware frame at the current sp
- | before restoring registers and returning.
+ RELOC(_boothowto, a0) | save reboot flags
+ movl d7,a0@
+ RELOC(_bootdev, a0) | and boot device
+ movl d6,a0@
- movl sp@(FR_SP),a0 | modified sp
- lea sp@(FR_SIZE),a1 | end of our frame
- movl a1@-,a0@- | copy 2 longs with
- movl a1@-,a0@- | ... predecrement
- movl a0,sp@(FR_SP) | sp = h/w frame
- moveml sp@+,#0x7FFF | restore all but sp
- movl sp@,sp | ... and sp
- rte | all done
+ /*
+ * All data registers are now free. All address registers
+ * except a5 are free. a5 is used by the RELOC() macro,
+ * and cannot be used until after the MMU is enabled.
+ */
-/* Use common m68k sigreturn */
-#include <m68k/m68k/sigreturn.s>
+/* determine our CPU/MMU combo - check for all regardless of kernel config */
+ movl #INTIOBASE+MMUBASE,a1
+ movl #0x200,d0 | data freeze bit
+ movc d0,cacr | only exists on 68030
+ movc cacr,d0 | read it back
+ tstl d0 | zero?
+ jeq Lnot68030 | yes, we have 68020/68040
+ RELOC(_mmutype, a0) | no, we have 68030
+ movl #MMU_68030,a0@ | set to reflect 68030 PMMU
+ RELOC(_cputype, a0)
+ movl #CPU_68030,a0@ | and 68030 CPU
+ RELOC(_machineid, a0)
+ movl #0x80,a1@(MMUCMD) | set magic cookie
+ movl a1@(MMUCMD),d0 | read it back
+ btst #7,d0 | cookie still on?
+ jeq Lnot370 | no, 360 or 375
+ movl #0,a1@(MMUCMD) | clear magic cookie
+ movl a1@(MMUCMD),d0 | read it back
+ btst #7,d0 | still on?
+ jeq Lisa370 | no, must be a 370
+ movl #HP_340,a0@ | yes, must be a 340
+ jra Lstart1
+Lnot370:
+ movl #HP_360,a0@ | type is at least a 360
+ movl #0,a1@(MMUCMD) | clear magic cookie2
+ movl a1@(MMUCMD),d0 | read it back
+ btst #16,d0 | still on?
+ jeq Lstart1 | no, must be a 360
+ movl #HP_375,a0@ | yes, must be a 345/375
+ jra Lhaspac
+Lisa370:
+ movl #HP_370,a0@ | set to 370
+Lhaspac:
+ RELOC(_ectype, a0)
+ movl #EC_PHYS,a0@ | also has a physical address cache
+ jra Lstart1
+Lnot68030:
+ bset #31,d0 | data cache enable bit
+ movc d0,cacr | only exists on 68040
+ movc cacr,d0 | read it back
+ tstl d0 | zero?
+ beq Lis68020 | yes, we have 68020
+ moveq #0,d0 | now turn it back off
+ movec d0,cacr | before we access any data
+ RELOC(_mmutype, a0)
+ movl #MMU_68040,a0@ | with a 68040 MMU
+ RELOC(_cputype, a0)
+ movl #CPU_68040,a0@ | and a 68040 CPU
+ RELOC(_fputype, a0)
+ movl #FPU_68040,a0@ | ...and FPU
+ RELOC(_ectype, a0)
+ movl #EC_NONE,a0@ | and no cache (for now XXX)
+ RELOC(_machineid, a0)
+ movl a1@(MMUCMD),d0 | read MMU register
+ lsrl #8,d0 | get apparent ID
+ cmpb #6,d0 | id == 6?
+ jeq Lis33mhz | yes, we have a 433s
+ movl #HP_380,a0@ | no, we have a 380/425t
+ jra Lstart1
+Lis33mhz:
+ movl #HP_433,a0@ | 433s (XXX 425s returns same ID, ugh!)
+ jra Lstart1
+Lis68020:
+ movl #1,a1@(MMUCMD) | a 68020, write HP MMU location
+ movl a1@(MMUCMD),d0 | read it back
+ btst #0,d0 | non-zero?
+ jne Lishpmmu | yes, we have HP MMU
+ RELOC(_mmutype, a0)
+ movl #MMU_68851,a0@ | no, we have PMMU
+ RELOC(_machineid, a0)
+ movl #HP_330,a0@ | and 330 CPU
+ jra Lstart1
+Lishpmmu:
+ RELOC(_ectype, a0) | 320 or 350
+ movl #EC_VIRT,a0@ | both have a virtual address cache
+ movl #0x80,a1@(MMUCMD) | set magic cookie
+ movl a1@(MMUCMD),d0 | read it back
+ btst #7,d0 | cookie still on?
+ jeq Lis320 | no, just a 320
+ RELOC(_machineid, a0)
+ movl #HP_350,a0@ | yes, a 350
+ jra Lstart1
+Lis320:
+ RELOC(_machineid, a0)
+ movl #HP_320,a0@
+
+Lstart1:
+ movl #0,a1@(MMUCMD) | clear out MMU again
+/* initialize source/destination control registers for movs */
+ moveq #FC_USERD,d0 | user space
+ movc d0,sfc | as source
+ movc d0,dfc | and destination of transfers
+/* initialize memory sizes (for pmap_bootstrap) */
+ movl #MAXADDR,d1 | last page
+ moveq #PGSHIFT,d2
+ lsrl d2,d1 | convert to page (click) number
+ RELOC(_maxmem, a0)
+ movl d1,a0@ | save as maxmem
+ movl a5,d0 | lowram value from ROM via boot
+ lsrl d2,d0 | convert to page number
+ subl d0,d1 | compute amount of RAM present
+ RELOC(_physmem, a0)
+ movl d1,a0@ | and physmem
+/* configure kernel and proc0 VA space so we can get going */
+ .globl _Sysseg, _pmap_bootstrap, _avail_start
+#ifdef DDB
+ RELOC(_esym,a0) | end of static kernel test/data/syms
+ movl a0@,d5
+ jne Lstart2
+#endif
+ movl #_end,d5 | end of static kernel text/data
+Lstart2:
+ addl #NBPG-1,d5
+ andl #PG_FRAME,d5 | round to a page
+ movl d5,a4
+ addl a5,a4 | convert to PA
+ pea a5@ | firstpa
+ pea a4@ | nextpa
+ RELOC(_pmap_bootstrap,a0)
+ jbsr a0@ | pmap_bootstrap(firstpa, nextpa)
+ addql #8,sp
/*
- * Interrupt handlers.
- * All device interrupts are auto-vectored. The CPU provides
- * the vector 0x18+level. Note we count spurious interrupts, but
- * we don't do anything else with them.
+ * Prepare to enable MMU.
+ * Since the kernel is not mapped logical == physical we must insure
+ * that when the MMU is turned on, all prefetched addresses (including
+ * the PC) are valid. In order guarentee that, we use the last physical
+ * page (which is conveniently mapped == VA) and load it up with enough
+ * code to defeat the prefetch, then we execute the jump back to here.
+ *
+ * Is this all really necessary, or am I paranoid??
*/
+ RELOC(_Sysseg, a0) | system segment table addr
+ movl a0@,d1 | read value (a KVA)
+ addl a5,d1 | convert to PA
+ RELOC(_mmutype, a0)
+ tstl a0@ | HP MMU?
+ jeq Lhpmmu2 | yes, skip
+ cmpl #MMU_68040,a0@ | 68040?
+ jne Lmotommu1 | no, skip
+ .long 0x4e7b1807 | movc d1,srp
+ jra Lstploaddone
+Lmotommu1:
+ RELOC(_protorp, a0)
+ movl #0x80000202,a0@ | nolimit + share global + 4 byte PTEs
+ movl d1,a0@(4) | + segtable address
+ pmove a0@,srp | load the supervisor root pointer
+ movl #0x80000002,a0@ | reinit upper half for CRP loads
+ jra Lstploaddone | done
+Lhpmmu2:
+ moveq #PGSHIFT,d2
+ lsrl d2,d1 | convert to page frame
+ movl d1,INTIOBASE+MMUBASE+MMUSSTP | load in sysseg table register
+Lstploaddone:
+ lea MAXADDR,a2 | PA of last RAM page
+ RELOC(Lhighcode, a1) | addr of high code
+ RELOC(Lehighcode, a3) | end addr
+Lcodecopy:
+ movw a1@+,a2@+ | copy a word
+ cmpl a3,a1 | done yet?
+ jcs Lcodecopy | no, keep going
+ jmp MAXADDR | go for it!
-#define INTERRUPT_SAVEREG moveml #0xC0C0,sp@-
-#define INTERRUPT_RESTOREREG moveml sp@+,#0x0303
+ /*
+ * BEGIN MMU TRAMPOLINE. This section of code is not
+ * executed in-place. It's copied to the last page
+ * of RAM (mapped va == pa) and executed there.
+ */
- /* Externs. */
- .globl _hilint, _isrdispatch, _nmihand
- .globl _hardclock, _statintr
+Lhighcode:
+ /*
+ * Set up the vector table, and race to get the MMU
+ * enabled.
+ */
+ movl #_vectab,d0 | set Vector Base Register
+ movc d0,vbr
-_spurintr: /* Level 0 */
- addql #1,_intrcnt+0
- addql #1,_cnt+V_INTR
- jra rei
+ RELOC(_mmutype, a0)
+ tstl a0@ | HP MMU?
+ jeq Lhpmmu3 | yes, skip
+ cmpl #MMU_68040,a0@ | 68040?
+ jne Lmotommu2 | no, skip
+ movw #0,INTIOBASE+MMUBASE+MMUCMD+2
+ movw #MMU_IEN+MMU_CEN+MMU_FPE,INTIOBASE+MMUBASE+MMUCMD+2
+ | enable FPU and caches
+ moveq #0,d0 | ensure TT regs are disabled
+ .long 0x4e7b0004 | movc d0,itt0
+ .long 0x4e7b0005 | movc d0,itt1
+ .long 0x4e7b0006 | movc d0,dtt0
+ .long 0x4e7b0007 | movc d0,dtt1
+ .word 0xf4d8 | cinva bc
+ .word 0xf518 | pflusha
+ movl #0x8000,d0
+ .long 0x4e7b0003 | movc d0,tc
+ movl #0x80008000,d0
+ movc d0,cacr | turn on both caches
+ jmp Lenab1
+Lmotommu2:
+ movl #MMU_IEN+MMU_FPE,INTIOBASE+MMUBASE+MMUCMD
+ | enable 68881 and i-cache
+ RELOC(_prototc, a2)
+ movl #0x82c0aa00,a2@ | value to load TC with
+ pmove a2@,tc | load it
+ jmp Lenab1
+Lhpmmu3:
+ movl #0,INTIOBASE+MMUBASE+MMUCMD | clear external cache
+ movl #MMU_ENAB,INTIOBASE+MMUBASE+MMUCMD | turn on MMU
+ jmp Lenab1 | jmp to mapped code
+Lehighcode:
-_lev1intr: /* Level 1: HIL XXX this needs to go away */
- INTERRUPT_SAVEREG
- jbsr _hilint
- INTERRUPT_RESTOREREG
- addql #1,_intrcnt+4
- addql #1,_cnt+V_INTR
- jra rei
+ /*
+ * END MMU TRAMPOLINE. Address register a5 is now free.
+ */
-_intrhand: /* Levels 2 through 5 */
- INTERRUPT_SAVEREG
- movw sp@(22),sp@- | push exception vector info
- clrw sp@-
- jbsr _isrdispatch | call dispatch routine
- addql #4,sp
- INTERRUPT_RESTOREREG
- jra rei | all done
+/*
+ * Should be running mapped from this point on
+ */
+Lenab1:
+/* select the software page size now */
+ lea tmpstk,sp | temporary stack
+ jbsr _vm_set_page_size | select software page size
+/* set kernel stack, user SP, and initial pcb */
+ movl _proc0paddr,a1 | get proc0 pcb addr
+ lea a1@(USPACE-4),sp | set kernel stack to end of area
+ lea _proc0,a2 | initialize proc0.p_addr so that
+ movl a1,a2@(P_ADDR) | we don't deref NULL in trap()
+ movl #USRSTACK-4,a2
+ movl a2,usp | init user SP
+ movl a1,_curpcb | proc0 is running
-_lev6intr: /* Level 6: clock */
- INTERRUPT_SAVEREG
- CLKADDR(a0)
- movb a0@(CLKSR),d0 | read clock status
-Lclkagain:
- btst #0,d0 | clear timer1 int immediately to
- jeq Lnotim1 | minimize chance of losing another
- movpw a0@(CLKMSB1),d1 | due to statintr processing delay
-Lnotim1:
- btst #2,d0 | timer3 interrupt?
- jeq Lnotim3 | no, skip statclock
- movpw a0@(CLKMSB3),d1 | clear timer3 interrupt
- addql #1,_intrcnt+28 | count clock interrupts
- lea sp@(16),a1 | a1 = &clockframe
- movl d0,sp@- | save status
- movl a1,sp@-
- jbsr _statintr | statintr(&frame)
- addql #4,sp
- movl sp@+,d0 | restore pre-statintr status
- CLKADDR(a0)
-Lnotim3:
- btst #0,d0 | timer1 interrupt?
- jeq Lrecheck | no, skip hardclock
- addql #1,_intrcnt+24 | count hardclock interrupts
- lea sp@(16),a1 | a1 = &clockframe
+ tstl _fputype | Have an FPU?
+ jeq Lenab2 | No, skip.
+ clrl a1@(PCB_FPCTX) | ensure null FP context
movl a1,sp@-
-#ifdef USELEDS
- .globl _ledaddr, _inledcontrol, _ledcontrol, _hz
- tstl _ledaddr | using LEDs?
- jeq Lnoled0 | no, skip this code
- movl heartbeat,d0 | get tick count
- addql #1,d0 | increment
- movl _hz,d1
- addl #50,d1 | get the timing a little closer
- cmpl #0,beatstatus | time to slow down?
- jeq SlowThrob
- lsrl #3,d1 | fast throb
-SlowThrob:
- lsrl #1,d1 | slow throb
- cmpl d0,d1 | are we there yet?
- jne Lnoled1 | no, nothing to do
- tstl _inledcontrol | already updating LEDs?
- jne Lnoled2 | yes, skip it
- addl #1,beatstatus | incr beat status
- cmpl #3,beatstatus | time to reset?
- ble SkipReset
- movl #0,beatstatus | reset the status indicator
-SkipReset:
- movl #LED_PULSE,sp@-
- movl #LED_DISK+LED_LANRCV+LED_LANXMT,sp@-
- clrl sp@-
- jbsr _ledcontrol | toggle pulse, turn all others off
- lea sp@(12),sp
-Lnoled2:
- movql #0,d0
-Lnoled1:
- movl d0,heartbeat
-Lnoled0:
-#endif
- jbsr _hardclock | hardclock(&frame)
+ jbsr _m68881_restore | restore it (does not kill a1)
addql #4,sp
- CLKADDR(a0)
-Lrecheck:
- addql #1,_cnt+V_INTR | chalk up another interrupt
- movb a0@(CLKSR),d0 | see if anything happened
- jmi Lclkagain | while we were in hardclock/statintr
- INTERRUPT_RESTOREREG
- jra rei | all done
+Lenab2:
+/* flush TLB and turn on caches */
+ jbsr _TBIA | invalidate TLB
+ cmpl #MMU_68040,_mmutype | 68040?
+ jeq Lnocache0 | yes, cache already on
+ movl #CACHE_ON,d0
+ movc d0,cacr | clear cache(s)
+ tstl _ectype
+ jeq Lnocache0
+ MMUADDR(a0)
+ orl #MMU_CEN,a0@(MMUCMD) | turn on external cache
+Lnocache0:
+/* Final setup for call to main(). */
+ jbsr _isrinit | initialize interrupt handlers
+ jbsr _hp300_calibrate_delay | calibrate delay() loop
-_lev7intr: /* Level 7: Parity errors, reset key */
- addql #1,_intrcnt+32
- clrl sp@-
- moveml #0xFFFF,sp@- | save registers
- movl usp,a0 | and save
- movl a0,sp@(FR_SP) | the user stack pointer
- jbsr _nmihand | call handler
- movl sp@(FR_SP),a0 | restore
+/*
+ * Create a fake exception frame so that cpu_fork() can copy it.
+ * main() nevers returns; we exit to user mode from a forked process
+ * later on.
+ */
+ clrw sp@- | vector offset/frame type
+ clrl sp@- | PC - filled in by "execve"
+ movw #PSL_USER,sp@- | in user mode
+ clrl sp@- | stack adjust count and padding
+ lea sp@(-64),sp | construct space for D0-D7/A0-A7
+ lea _proc0,a0 | save pointer to frame
+ movl sp,a0@(P_MD_REGS) | in proc0.p_md.md_regs
+
+ jra _main | main()
+
+ pea Lmainreturned | Yow! Main returned!
+ jbsr _panic
+ /* NOTREACHED */
+Lmainreturned:
+ .asciz "main() returned"
+ .even
+
+ .globl _proc_trampoline
+_proc_trampoline:
+ movl a3,sp@-
+ jbsr a2@
+ addql #4,sp
+ movl sp@(FR_SP),a0 | grab and load
movl a0,usp | user SP
- moveml sp@+,#0x7FFF | and remaining registers
- addql #8,sp | pop SP and stack adjust
- jra rei | all done
+ moveml sp@+,#0x7FFF | restore most user regs
+ addql #8,sp | toss SP and stack adjust
+ jra rei | and return
+
/*
- * Emulation of VAX REI instruction.
- *
- * This code deals with checking for and servicing ASTs
- * (profiling, scheduling) and software interrupts (network, softclock).
- * We check for ASTs first, just like the VAX. To avoid excess overhead
- * the T_ASTFLT handling code will also check for software interrupts so we
- * do not have to do it here. After identifing that we need an AST we
- * drop the IPL to allow device interrupts.
- *
- * This code is complicated by the fact that sendsig may have been called
- * necessitating a stack cleanup.
- */
- .comm _ssir,1
- .globl _astpending
- .globl rei
-rei:
- tstl _astpending | AST pending?
- jeq Lchksir | no, go check for SIR
-Lrei1:
- btst #5,sp@ | yes, are we returning to user mode?
- jne Lchksir | no, go check for SIR
- movw #PSL_LOWIPL,sr | lower SPL
- clrl sp@- | stack adjust
- moveml #0xFFFF,sp@- | save all registers
- movl usp,a1 | including
- movl a1,sp@(FR_SP) | the users SP
-Lrei2:
- clrl sp@- | VA == none
- clrl sp@- | code == none
- movl #T_ASTFLT,sp@- | type == async system trap
- jbsr _trap | go handle it
+ * Trap/interrupt vector routines
+ */
+
+ .globl _trap, _nofault, _longjmp
+_buserr:
+ /*
+ * XXX TODO: look at the mac68k _buserr and generalize
+ * XXX the saving of the fault address so this routine
+ * XXX can be shared.
+ */
+ tstl _nofault | device probe?
+ jeq Lberr | no, handle as usual
+ movl _nofault,sp@- | yes,
+ jbsr _longjmp | longjmp(nofault)
+Lberr:
+#if defined(M68040)
+#if defined(M68020) || defined(M68030)
+ cmpl #MMU_68040,_mmutype | 68040?
+ jne _addrerr | no, skip
+#endif
+ clrl sp@- | stack adjust count
+ moveml #0xFFFF,sp@- | save user registers
+ movl usp,a0 | save the user SP
+ movl a0,sp@(FR_SP) | in the savearea
+ lea sp@(FR_HW),a1 | grab base of HW berr frame
+ moveq #0,d0
+ movw a1@(12),d0 | grab SSW
+ movl a1@(20),d1 | and fault VA
+ btst #11,d0 | check for mis-aligned access
+ jeq Lberr2 | no, skip
+ addl #3,d1 | yes, get into next page
+ andl #PG_FRAME,d1 | and truncate
+Lberr2:
+ movl d1,sp@- | push fault VA
+ movl d0,sp@- | and padded SSW
+ btst #10,d0 | ATC bit set?
+ jeq Lisberr | no, must be a real bus error
+ movc dfc,d1 | yes, get MMU fault
+ movc d0,dfc | store faulting function code
+ movl sp@(4),a0 | get faulting address
+ .word 0xf568 | ptestr a0@
+ movc d1,dfc
+ .long 0x4e7a0805 | movc mmusr,d0
+ movw d0,sp@ | save (ONLY LOW 16 BITS!)
+ jra Lismerr
+#endif
+_addrerr:
+ clrl sp@- | stack adjust count
+ moveml #0xFFFF,sp@- | save user registers
+ movl usp,a0 | save the user SP
+ movl a0,sp@(FR_SP) | in the savearea
+ lea sp@(FR_HW),a1 | grab base of HW berr frame
+#if defined(M68040)
+#if defined(M68020) || defined(M68030)
+ cmpl #MMU_68040,_mmutype | 68040?
+ jne Lbenot040 | no, skip
+#endif
+ movl a1@(8),sp@- | yes, push fault address
+ clrl sp@- | no SSW for address fault
+ jra Lisaerr | go deal with it
+Lbenot040:
+#endif
+ moveq #0,d0
+ movw a1@(10),d0 | grab SSW for fault processing
+ btst #12,d0 | RB set?
+ jeq LbeX0 | no, test RC
+ bset #14,d0 | yes, must set FB
+ movw d0,a1@(10) | for hardware too
+LbeX0:
+ btst #13,d0 | RC set?
+ jeq LbeX1 | no, skip
+ bset #15,d0 | yes, must set FC
+ movw d0,a1@(10) | for hardware too
+LbeX1:
+ btst #8,d0 | data fault?
+ jeq Lbe0 | no, check for hard cases
+ movl a1@(16),d1 | fault address is as given in frame
+ jra Lbe10 | thats it
+Lbe0:
+ btst #4,a1@(6) | long (type B) stack frame?
+ jne Lbe4 | yes, go handle
+ movl a1@(2),d1 | no, can use save PC
+ btst #14,d0 | FB set?
+ jeq Lbe3 | no, try FC
+ addql #4,d1 | yes, adjust address
+ jra Lbe10 | done
+Lbe3:
+ btst #15,d0 | FC set?
+ jeq Lbe10 | no, done
+ addql #2,d1 | yes, adjust address
+ jra Lbe10 | done
+Lbe4:
+ movl a1@(36),d1 | long format, use stage B address
+ btst #15,d0 | FC set?
+ jeq Lbe10 | no, all done
+ subql #2,d1 | yes, adjust address
+Lbe10:
+ movl d1,sp@- | push fault VA
+ movl d0,sp@- | and padded SSW
+ movw a1@(6),d0 | get frame format/vector offset
+ andw #0x0FFF,d0 | clear out frame format
+ cmpw #12,d0 | address error vector?
+ jeq Lisaerr | yes, go to it
+#if defined(M68K_MMU_MOTOROLA)
+#if defined(M68K_MMU_HP)
+ tstl _mmutype | HP MMU?
+ jeq Lbehpmmu | yes, skip
+#endif
+ movl d1,a0 | fault address
+ movl sp@,d0 | function code from ssw
+ btst #8,d0 | data fault?
+ jne Lbe10a
+ movql #1,d0 | user program access FC
+ | (we dont separate data/program)
+ btst #5,a1@ | supervisor mode?
+ jeq Lbe10a | if no, done
+ movql #5,d0 | else supervisor program access
+Lbe10a:
+ ptestr d0,a0@,#7 | do a table search
+ pmove psr,sp@ | save result
+ movb sp@,d1
+ btst #2,d1 | invalid? (incl. limit viol and berr)
+ jeq Lmightnotbemerr | no -> wp check
+ btst #7,d1 | is it MMU table berr?
+ jeq Lismerr | no, must be fast
+ jra Lisberr1 | real bus err needs not be fast
+Lmightnotbemerr:
+ btst #3,d1 | write protect bit set?
+ jeq Lisberr1 | no, must be bus error
+ movl sp@,d0 | ssw into low word of d0
+ andw #0xc0,d0 | write protect is set on page:
+ cmpw #0x40,d0 | was it read cycle?
+ jeq Lisberr1 | yes, was not WPE, must be bus err
+ jra Lismerr | no, must be mem err
+Lbehpmmu:
+#endif
+#if defined(M68K_MMU_HP)
+ MMUADDR(a0)
+ movl a0@(MMUSTAT),d0 | read status
+ btst #3,d0 | MMU fault?
+ jeq Lisberr | no, just a non-MMU bus error so skip
+ andl #~MMU_FAULT,a0@(MMUSTAT)| yes, clear fault bits
+ movw d0,sp@ | pass MMU stat in upper half of code
+#endif
+Lismerr:
+ movl #T_MMUFLT,sp@- | show that we are an MMU fault
+ jra Ltrapnstkadj | and deal with it
+Lisaerr:
+ movl #T_ADDRERR,sp@- | mark address error
+ jra Ltrapnstkadj | and deal with it
+Lisberr1:
+ clrw sp@ | re-clear pad word
+Lisberr:
+ movl #T_BUSERR,sp@- | mark bus error
+Ltrapnstkadj:
+ jbsr _trap | handle the error
lea sp@(12),sp | pop value args
movl sp@(FR_SP),a0 | restore user SP
movl a0,usp | from save area
movw sp@(FR_ADJ),d0 | need to adjust stack?
- jne Laststkadj | yes, go to it
+ jne Lstkadj | yes, go to it
moveml sp@+,#0x7FFF | no, restore most user regs
- addql #8,sp | toss SP and stack adjust
- rte | and do real RTE
-Laststkadj:
+ addql #8,sp | toss SSP and stkadj
+ jra rei | all done
+Lstkadj:
lea sp@(FR_HW),a1 | pointer to HW frame
addql #8,a1 | source pointer
movl a1,a0 | source
movl a0,sp@(FR_SP) | new SSP
moveml sp@+,#0x7FFF | restore user registers
movl sp@,sp | and our SP
- rte | and do real RTE
-Lchksir:
- tstb _ssir | SIR pending?
- jeq Ldorte | no, all done
- movl d0,sp@- | need a scratch register
- movw sp@(4),d0 | get SR
- andw #PSL_IPL7,d0 | mask all but IPL
- jne Lnosir | came from interrupt, no can do
- movl sp@+,d0 | restore scratch register
-Lgotsir:
- movw #SPL1,sr | prevent others from servicing int
- tstb _ssir | too late?
- jeq Ldorte | yes, oh well...
- clrl sp@- | stack adjust
- moveml #0xFFFF,sp@- | save all registers
- movl usp,a1 | including
- movl a1,sp@(FR_SP) | the users SP
-Lsir1:
- clrl sp@- | VA == none
- clrl sp@- | code == none
- movl #T_SSIR,sp@- | type == software interrupt
- jbsr _trap | go handle it
- lea sp@(12),sp | pop value args
- movl sp@(FR_SP),a0 | restore
- movl a0,usp | user SP
- moveml sp@+,#0x7FFF | and all remaining registers
- addql #8,sp | pop SP and stack adjust
- rte
-Lnosir:
- movl sp@+,d0 | restore scratch register
-Ldorte:
- rte | real return
+ jra rei | all done
+
+/*
+ * FP exceptions.
+ */
+_fpfline: /* XXXthorpej - candidate for vector patch */
+#if defined(M68040)
+ cmpl #FPU_68040,_fputype | 68040 FPU?
+ jne Lfp_unimp | no, skip FPSP
+ cmpw #0x202c,sp@(6) | format type 2?
+ jne _illinst | no, not an FP emulation
+Ldofp_unimp:
+#ifdef FPSP
+ .globl fpsp_unimp
+ jmp fpsp_unimp | yes, go handle it
+#endif
+Lfp_unimp:
+#endif /* M68040 */
+#ifdef FPU_EMULATE
+ clrl sp@- | stack adjust count
+ moveml #0xFFFF,sp@- | save registers
+ moveq #T_FPEMULI,d0 | denote as FP emulation trap
+ jra fault | do it
+#else
+ jra _illinst
+#endif
+
+_fpunsupp: /* XXXthorpej - candidate for vector patch */
+#if defined(M68040)
+ cmpl #FPU_68040,_fputype | 68040 FPU?
+ jne _illinst | no, treat as illinst
+#ifdef FPSP
+ .globl fpsp_unsupp
+ jmp fpsp_unsupp | yes, go handle it
+#endif
+Lfp_unsupp:
+#endif /* M68040 */
+#ifdef FPU_EMULATE
+ clrl sp@- | stack adjust count
+ moveml #0xFFFF,sp@- | save registers
+ moveq #T_FPEMULD,d0 | denote as FP emulation trap
+ jra fault | do it
+#else
+ jra _illinst
+#endif
/*
- * Macro to relocate a symbol, used before MMU is enabled.
+ * Handles all other FP coprocessor exceptions.
+ * Note that since some FP exceptions generate mid-instruction frames
+ * and may cause signal delivery, we need to test for stack adjustment
+ * after the trap call.
*/
-#define RELOC(var, ar) \
- lea var,ar; \
- addl a5,ar
+ .globl _fpfault
+_fpfault:
+ clrl sp@- | stack adjust count
+ moveml #0xFFFF,sp@- | save user registers
+ movl usp,a0 | and save
+ movl a0,sp@(FR_SP) | the user stack pointer
+ clrl sp@- | no VA arg
+ movl _curpcb,a0 | current pcb
+ lea a0@(PCB_FPCTX),a0 | address of FP savearea
+ fsave a0@ | save state
+#if defined(M68040) || defined(M68060)
+ /* always null state frame on 68040, 68060 */
+ cmpl #CPU_68040,_cputype
+ jle Lfptnull
+#endif
+ tstb a0@ | null state frame?
+ jeq Lfptnull | yes, safe
+ clrw d0 | no, need to tweak BIU
+ movb a0@(1),d0 | get frame size
+ bset #3,a0@(0,d0:w) | set exc_pend bit of BIU
+Lfptnull:
+ fmovem fpsr,sp@- | push fpsr as code argument
+ frestore a0@ | restore state
+ movl #T_FPERR,sp@- | push type arg
+ jra Ltrapnstkadj | call trap and deal with stack cleanup
/*
- * Initialization
- *
- * A4 contains the address of the end of the symtab
- * A5 contains physical load point from boot
- * VBR contains zero from ROM. Exceptions will continue to vector
- * through ROM until MMU is turned on at which time they will vector
- * through our table (vectors.s).
+ * Coprocessor and format errors can generate mid-instruction stack
+ * frames and cause signal delivery hence we need to check for potential
+ * stack adjustment.
*/
- .comm _lowram,4
- .comm _esym,4
+_coperr:
+ clrl sp@- | stack adjust count
+ moveml #0xFFFF,sp@-
+ movl usp,a0 | get and save
+ movl a0,sp@(FR_SP) | the user stack pointer
+ clrl sp@- | no VA arg
+ clrl sp@- | or code arg
+ movl #T_COPERR,sp@- | push trap type
+ jra Ltrapnstkadj | call trap and deal with stack adjustments
- .text
- .globl _edata
- .globl _etext,_end
- .globl start
-start:
- movw #PSL_HIGHIPL,sr | no interrupts
- RELOC(tmpstk, a0)
- movl a0,sp | give ourselves a temporary stack
- RELOC(_esym, a0)
-#if 1
- movl a4,a0@ | store end of symbol table
-#else
- clrl a0@ | no symbol table, yet
-#endif
- RELOC(_lowram, a0)
- movl a5,a0@ | store start of physical memory
- movl #CACHE_OFF,d0
- movc d0,cacr | clear and disable on-chip cache(s)
+_fmterr:
+ clrl sp@- | stack adjust count
+ moveml #0xFFFF,sp@-
+ movl usp,a0 | get and save
+ movl a0,sp@(FR_SP) | the user stack pointer
+ clrl sp@- | no VA arg
+ clrl sp@- | or code arg
+ movl #T_FMTERR,sp@- | push trap type
+ jra Ltrapnstkadj | call trap and deal with stack adjustments
-/* check for internal HP-IB in SYSFLAG */
- btst #5,0xfffffed2 | internal HP-IB?
- jeq Lhaveihpib | yes, have HP-IB just continue
- RELOC(_internalhpib, a0)
- movl #0,a0@ | no, clear associated address
-Lhaveihpib:
+/*
+ * Other exceptions only cause four and six word stack frame and require
+ * no post-trap stack adjustment.
+ */
+_illinst:
+ clrl sp@-
+ moveml #0xFFFF,sp@-
+ moveq #T_ILLINST,d0
+ jra fault
- RELOC(_boothowto, a0) | save reboot flags
- movl d7,a0@
- RELOC(_bootdev, a0) | and boot device
- movl d6,a0@
+_zerodiv:
+ clrl sp@-
+ moveml #0xFFFF,sp@-
+ moveq #T_ZERODIV,d0
+ jra fault
- /*
- * All data registers are now free. All address registers
- * except a5 are free. a5 is used by the RELOC() macro,
- * and cannot be used until after the MMU is enabled.
- */
+_chkinst:
+ clrl sp@-
+ moveml #0xFFFF,sp@-
+ moveq #T_CHKINST,d0
+ jra fault
-/* determine our CPU/MMU combo - check for all regardless of kernel config */
- movl #INTIOBASE+MMUBASE,a1
- movl #0x200,d0 | data freeze bit
- movc d0,cacr | only exists on 68030
- movc cacr,d0 | read it back
- tstl d0 | zero?
- jeq Lnot68030 | yes, we have 68020/68040
- RELOC(_mmutype, a0) | no, we have 68030
- movl #MMU_68030,a0@ | set to reflect 68030 PMMU
- RELOC(_cputype, a0)
- movl #CPU_68030,a0@ | and 68030 CPU
- RELOC(_machineid, a0)
- movl #0x80,a1@(MMUCMD) | set magic cookie
- movl a1@(MMUCMD),d0 | read it back
- btst #7,d0 | cookie still on?
- jeq Lnot370 | no, 360 or 375
- movl #0,a1@(MMUCMD) | clear magic cookie
- movl a1@(MMUCMD),d0 | read it back
- btst #7,d0 | still on?
- jeq Lisa370 | no, must be a 370
- movl #HP_340,a0@ | yes, must be a 340
- jra Lstart1
-Lnot370:
- movl #HP_360,a0@ | type is at least a 360
- movl #0,a1@(MMUCMD) | clear magic cookie2
- movl a1@(MMUCMD),d0 | read it back
- btst #16,d0 | still on?
- jeq Lstart1 | no, must be a 360
- movl #HP_375,a0@ | yes, must be a 345/375
- jra Lhaspac
-Lisa370:
- movl #HP_370,a0@ | set to 370
-Lhaspac:
- RELOC(_ectype, a0)
- movl #EC_PHYS,a0@ | also has a physical address cache
- jra Lstart1
-Lnot68030:
- bset #31,d0 | data cache enable bit
- movc d0,cacr | only exists on 68040
- movc cacr,d0 | read it back
- tstl d0 | zero?
- beq Lis68020 | yes, we have 68020
- moveq #0,d0 | now turn it back off
- movec d0,cacr | before we access any data
- RELOC(_mmutype, a0)
- movl #MMU_68040,a0@ | with a 68040 MMU
- RELOC(_cputype, a0)
- movl #CPU_68040,a0@ | and a 68040 CPU
- RELOC(_ectype, a0)
- movl #EC_NONE,a0@ | and no cache (for now XXX)
- RELOC(_machineid, a0)
- movl a1@(MMUCMD),d0 | read MMU register
- lsrl #8,d0 | get apparent ID
- cmpb #6,d0 | id == 6?
- jeq Lis33mhz | yes, we have a 433s
- movl #HP_380,a0@ | no, we have a 380/425t
- jra Lstart1
-Lis33mhz:
- movl #HP_433,a0@ | 433s (XXX 425s returns same ID, ugh!)
- jra Lstart1
-Lis68020:
- movl #1,a1@(MMUCMD) | a 68020, write HP MMU location
- movl a1@(MMUCMD),d0 | read it back
- btst #0,d0 | non-zero?
- jne Lishpmmu | yes, we have HP MMU
- RELOC(_mmutype, a0)
- movl #MMU_68851,a0@ | no, we have PMMU
- RELOC(_machineid, a0)
- movl #HP_330,a0@ | and 330 CPU
- jra Lstart1
-Lishpmmu:
- RELOC(_ectype, a0) | 320 or 350
- movl #EC_VIRT,a0@ | both have a virtual address cache
- movl #0x80,a1@(MMUCMD) | set magic cookie
- movl a1@(MMUCMD),d0 | read it back
- btst #7,d0 | cookie still on?
- jeq Lis320 | no, just a 320
- RELOC(_machineid, a0)
- movl #HP_350,a0@ | yes, a 350
- jra Lstart1
-Lis320:
- RELOC(_machineid, a0)
- movl #HP_320,a0@
+_trapvinst:
+ clrl sp@-
+ moveml #0xFFFF,sp@-
+ moveq #T_TRAPVINST,d0
+ jra fault
-Lstart1:
- movl #0,a1@(MMUCMD) | clear out MMU again
-/* initialize source/destination control registers for movs */
- moveq #FC_USERD,d0 | user space
- movc d0,sfc | as source
- movc d0,dfc | and destination of transfers
-/* initialize memory sizes (for pmap_bootstrap) */
- movl #MAXADDR,d1 | last page
- moveq #PGSHIFT,d2
- lsrl d2,d1 | convert to page (click) number
- RELOC(_maxmem, a0)
- movl d1,a0@ | save as maxmem
- movl a5,d0 | lowram value from ROM via boot
- lsrl d2,d0 | convert to page number
- subl d0,d1 | compute amount of RAM present
- RELOC(_physmem, a0)
- movl d1,a0@ | and physmem
-/* configure kernel and proc0 VA space so we can get going */
- .globl _Sysseg, _pmap_bootstrap, _avail_start
-#ifdef DDB
- RELOC(_esym,a0) | end of static kernel test/data/syms
- movl a0@,d5
- jne Lstart2
-#endif
- movl #_end,d5 | end of static kernel text/data
-Lstart2:
- addl #NBPG-1,d5
- andl #PG_FRAME,d5 | round to a page
- movl d5,a4
- addl a5,a4 | convert to PA
- pea a5@ | firstpa
- pea a4@ | nextpa
- RELOC(_pmap_bootstrap,a0)
- jbsr a0@ | pmap_bootstrap(firstpa, nextpa)
- addql #8,sp
+_privinst:
+ clrl sp@-
+ moveml #0xFFFF,sp@-
+ moveq #T_PRIVINST,d0
+ jra fault
+
+ .globl fault
+fault:
+ movl usp,a0 | get and save
+ movl a0,sp@(FR_SP) | the user stack pointer
+ clrl sp@- | no VA arg
+ clrl sp@- | or code arg
+ movl d0,sp@- | push trap type
+ jbsr _trap | handle trap
+ lea sp@(12),sp | pop value args
+ movl sp@(FR_SP),a0 | restore
+ movl a0,usp | user SP
+ moveml sp@+,#0x7FFF | restore most user regs
+ addql #8,sp | pop SP and stack adjust
+ jra rei | all done
+
+ .globl _straytrap
+_badtrap:
+ moveml #0xC0C0,sp@- | save scratch regs
+ movw sp@(22),sp@- | push exception vector info
+ clrw sp@-
+ movl sp@(22),sp@- | and PC
+ jbsr _straytrap | report
+ addql #8,sp | pop args
+ moveml sp@+,#0x0303 | restore regs
+ jra rei | all done
+
+ .globl _syscall
+_trap0:
+ clrl sp@- | stack adjust count
+ moveml #0xFFFF,sp@- | save user registers
+ movl usp,a0 | save the user SP
+ movl a0,sp@(FR_SP) | in the savearea
+ movl d0,sp@- | push syscall number
+ jbsr _syscall | handle it
+ addql #4,sp | pop syscall arg
+ tstl _astpending
+ jne Lrei2
+ tstb _ssir
+ jeq Ltrap1
+ movw #SPL1,sr
+ tstb _ssir
+ jne Lsir1
+Ltrap1:
+ movl sp@(FR_SP),a0 | grab and restore
+ movl a0,usp | user SP
+ moveml sp@+,#0x7FFF | restore most registers
+ addql #8,sp | pop SP and stack adjust
+ rte
/*
- * Prepare to enable MMU.
- * Since the kernel is not mapped logical == physical we must insure
- * that when the MMU is turned on, all prefetched addresses (including
- * the PC) are valid. In order guarentee that, we use the last physical
- * page (which is conveniently mapped == VA) and load it up with enough
- * code to defeat the prefetch, then we execute the jump back to here.
- *
- * Is this all really necessary, or am I paranoid??
+ * Trap 1 - sigreturn
*/
- RELOC(_Sysseg, a0) | system segment table addr
- movl a0@,d1 | read value (a KVA)
- addl a5,d1 | convert to PA
- RELOC(_mmutype, a0)
- tstl a0@ | HP MMU?
- jeq Lhpmmu2 | yes, skip
- cmpl #MMU_68040,a0@ | 68040?
- jne Lmotommu1 | no, skip
- .long 0x4e7b1807 | movc d1,srp
- jra Lstploaddone
-Lmotommu1:
- RELOC(_protorp, a0)
- movl #0x80000202,a0@ | nolimit + share global + 4 byte PTEs
- movl d1,a0@(4) | + segtable address
- pmove a0@,srp | load the supervisor root pointer
- movl #0x80000002,a0@ | reinit upper half for CRP loads
- jra Lstploaddone | done
-Lhpmmu2:
- moveq #PGSHIFT,d2
- lsrl d2,d1 | convert to page frame
- movl d1,INTIOBASE+MMUBASE+MMUSSTP | load in sysseg table register
-Lstploaddone:
- lea MAXADDR,a2 | PA of last RAM page
- RELOC(Lhighcode, a1) | addr of high code
- RELOC(Lehighcode, a3) | end addr
-Lcodecopy:
- movw a1@+,a2@+ | copy a word
- cmpl a3,a1 | done yet?
- jcs Lcodecopy | no, keep going
- jmp MAXADDR | go for it!
-
- /*
- * BEGIN MMU TRAMPOLINE. This section of code is not
- * executed in-place. It's copied to the last page
- * of RAM (mapped va == pa) and executed there.
- */
+_trap1:
+ jra sigreturn
-Lhighcode:
- /*
- * Set up the vector table, and race to get the MMU
- * enabled.
- */
- movl #_vectab,d0 | set Vector Base Register
- movc d0,vbr
+/*
+ * Trap 2 - trace trap
+ */
+_trap2:
+ jra _trace
- RELOC(_mmutype, a0)
- tstl a0@ | HP MMU?
- jeq Lhpmmu3 | yes, skip
- cmpl #MMU_68040,a0@ | 68040?
- jne Lmotommu2 | no, skip
- movw #0,INTIOBASE+MMUBASE+MMUCMD+2
- movw #MMU_IEN+MMU_CEN+MMU_FPE,INTIOBASE+MMUBASE+MMUCMD+2
- | enable FPU and caches
- moveq #0,d0 | ensure TT regs are disabled
- .long 0x4e7b0004 | movc d0,itt0
- .long 0x4e7b0005 | movc d0,itt1
- .long 0x4e7b0006 | movc d0,dtt0
- .long 0x4e7b0007 | movc d0,dtt1
- .word 0xf4d8 | cinva bc
- .word 0xf518 | pflusha
- movl #0x8000,d0
- .long 0x4e7b0003 | movc d0,tc
- movl #0x80008000,d0
- movc d0,cacr | turn on both caches
- jmp Lenab1
-Lmotommu2:
- movl #MMU_IEN+MMU_FPE,INTIOBASE+MMUBASE+MMUCMD
- | enable 68881 and i-cache
- RELOC(_prototc, a2)
- movl #0x82c0aa00,a2@ | value to load TC with
- pmove a2@,tc | load it
- jmp Lenab1
-Lhpmmu3:
- movl #0,INTIOBASE+MMUBASE+MMUCMD | clear external cache
- movl #MMU_ENAB,INTIOBASE+MMUBASE+MMUCMD | turn on MMU
- jmp Lenab1 | jmp to mapped code
-Lehighcode:
+/*
+ * Trap 12 is the entry point for the cachectl "syscall" (both HPUX & BSD)
+ * cachectl(command, addr, length)
+ * command in d0, addr in a1, length in d1
+ */
+ .globl _cachectl
+_trap12:
+ movl d1,sp@- | push length
+ movl a1,sp@- | push addr
+ movl d0,sp@- | push command
+ jbsr _cachectl | do it
+ lea sp@(12),sp | pop args
+ jra rei | all done
- /*
- * END MMU TRAMPOLINE. Address register a5 is now free.
- */
+/*
+ * Trace (single-step) trap. Kernel-mode is special.
+ * User mode traps are simply passed on to trap().
+ */
+_trace:
+ clrl sp@- | stack adjust count
+ moveml #0xFFFF,sp@-
+ moveq #T_TRACE,d0
+ movw sp@(FR_HW),d1 | get PSW
+ andw #PSL_S,d1 | from system mode?
+ jne kbrkpt | yes, kernel breakpoint
+ jra fault | no, user-mode fault
/*
- * Should be running mapped from this point on
+ * Trap 15 is used for:
+ * - GDB breakpoints (in user programs)
+ * - KGDB breakpoints (in the kernel)
+ * - trace traps for SUN binaries (not fully supported yet)
+ * User mode traps are simply passed to trap().
*/
-Lenab1:
-/* select the software page size now */
- lea tmpstk,sp | temporary stack
- jbsr _vm_set_page_size | select software page size
-/* set kernel stack, user SP, and initial pcb */
- movl _proc0paddr,a1 | get proc0 pcb addr
- lea a1@(USPACE-4),sp | set kernel stack to end of area
- lea _proc0,a2 | initialize proc0.p_addr so that
- movl a1,a2@(P_ADDR) | we don't deref NULL in trap()
- movl #USRSTACK-4,a2
- movl a2,usp | init user SP
- movl a1,_curpcb | proc0 is running
-#ifdef FPCOPROC
- clrl a1@(PCB_FPCTX) | ensure null FP context
- movl a1,sp@-
- jbsr _m68881_restore | restore it (does not kill a1)
- addql #4,sp
+_trap15:
+ clrl sp@- | stack adjust count
+ moveml #0xFFFF,sp@-
+ moveq #T_TRAP15,d0
+ movw sp@(FR_HW),d1 | get PSW
+ andw #PSL_S,d1 | from system mode?
+ jne kbrkpt | yes, kernel breakpoint
+ jra fault | no, user-mode fault
+
+kbrkpt: | Kernel-mode breakpoint or trace trap. (d0=trap_type)
+ | Save the system sp rather than the user sp.
+ movw #PSL_HIGHIPL,sr | lock out interrupts
+ lea sp@(FR_SIZE),a6 | Save stack pointer
+ movl a6,sp@(FR_SP) | from before trap
+
+ | If were are not on tmpstk switch to it.
+ | (so debugger can change the stack pointer)
+ movl a6,d1
+ cmpl #tmpstk,d1
+ jls Lbrkpt2 | already on tmpstk
+ | Copy frame to the temporary stack
+ movl sp,a0 | a0=src
+ lea tmpstk-96,a1 | a1=dst
+ movl a1,sp | sp=new frame
+ moveq #FR_SIZE,d1
+Lbrkpt1:
+ movl a0@+,a1@+
+ subql #4,d1
+ bgt Lbrkpt1
+
+Lbrkpt2:
+ | Call the trap handler for the kernel debugger.
+ | Do not call trap() to do it, so that we can
+ | set breakpoints in trap() if we want. We know
+ | the trap type is either T_TRACE or T_BREAKPOINT.
+ | If we have both DDB and KGDB, let KGDB see it first,
+ | because KGDB will just return 0 if not connected.
+ | Save args in d2, a2
+ movl d0,d2 | trap type
+ movl sp,a2 | frame ptr
+#ifdef KGDB
+ | Let KGDB handle it (if connected)
+ movl a2,sp@- | push frame ptr
+ movl d2,sp@- | push trap type
+ jbsr _kgdb_trap | handle the trap
+ addql #8,sp | pop args
+ cmpl #0,d0 | did kgdb handle it?
+ jne Lbrkpt3 | yes, done
#endif
-/* flush TLB and turn on caches */
- jbsr _TBIA | invalidate TLB
- cmpl #MMU_68040,_mmutype | 68040?
- jeq Lnocache0 | yes, cache already on
- movl #CACHE_ON,d0
- movc d0,cacr | clear cache(s)
- tstl _ectype
- jeq Lnocache0
- MMUADDR(a0)
- orl #MMU_CEN,a0@(MMUCMD) | turn on external cache
-Lnocache0:
-/* Final setup for call to main(). */
- jbsr _isrinit | initialize interrupt handlers
- jbsr _hp300_calibrate_delay | calibrate delay() loop
+#ifdef DDB
+ | Let DDB handle it
+ movl a2,sp@- | push frame ptr
+ movl d2,sp@- | push trap type
+ jbsr _kdb_trap | handle the trap
+ addql #8,sp | pop args
+#if 0 /* not needed on hp300 */
+ cmpl #0,d0 | did ddb handle it?
+ jne Lbrkpt3 | yes, done
+#endif
+#endif
+ /* Sun 3 drops into PROM here. */
+Lbrkpt3:
+ | The stack pointer may have been modified, or
+ | data below it modified (by kgdb push call),
+ | so push the hardware frame at the current sp
+ | before restoring registers and returning.
+
+ movl sp@(FR_SP),a0 | modified sp
+ lea sp@(FR_SIZE),a1 | end of our frame
+ movl a1@-,a0@- | copy 2 longs with
+ movl a1@-,a0@- | ... predecrement
+ movl a0,sp@(FR_SP) | sp = h/w frame
+ moveml sp@+,#0x7FFF | restore all but sp
+ movl sp@,sp | ... and sp
+ rte | all done
+
+/* Use common m68k sigreturn */
+#include <m68k/m68k/sigreturn.s>
/*
- * Create a fake exception frame so that cpu_fork() can copy it.
- * main() nevers returns; we exit to user mode from a forked process
- * later on.
+ * Interrupt handlers.
+ * All device interrupts are auto-vectored. The CPU provides
+ * the vector 0x18+level. Note we count spurious interrupts, but
+ * we don't do anything else with them.
*/
- clrw sp@- | vector offset/frame type
- clrl sp@- | PC - filled in by "execve"
- movw #PSL_USER,sp@- | in user mode
- clrl sp@- | stack adjust count and padding
- lea sp@(-64),sp | construct space for D0-D7/A0-A7
- lea _proc0,a0 | save pointer to frame
- movl sp,a0@(P_MD_REGS) | in proc0.p_md.md_regs
- jra _main | main()
+#define INTERRUPT_SAVEREG moveml #0xC0C0,sp@-
+#define INTERRUPT_RESTOREREG moveml sp@+,#0x0303
- pea Lmainreturned | Yow! Main returned!
- jbsr _panic
- /* NOTREACHED */
-Lmainreturned:
- .asciz "main() returned"
- .even
+ /* Externs. */
+ .globl _hilint, _isrdispatch, _nmihand
+ .globl _hardclock, _statintr
- .globl _proc_trampoline
-_proc_trampoline:
- movl a3,sp@-
- jbsr a2@
+_spurintr: /* Level 0 */
+ addql #1,_intrcnt+0
+ addql #1,_cnt+V_INTR
+ jra rei
+
+_lev1intr: /* Level 1: HIL XXX this needs to go away */
+ INTERRUPT_SAVEREG
+ jbsr _hilint
+ INTERRUPT_RESTOREREG
+ addql #1,_intrcnt+4
+ addql #1,_cnt+V_INTR
+ jra rei
+
+_intrhand: /* Levels 2 through 5 */
+ INTERRUPT_SAVEREG
+ movw sp@(22),sp@- | push exception vector info
+ clrw sp@-
+ jbsr _isrdispatch | call dispatch routine
addql #4,sp
- movl sp@(FR_SP),a0 | grab and load
+ INTERRUPT_RESTOREREG
+ jra rei | all done
+
+_lev6intr: /* Level 6: clock */
+ INTERRUPT_SAVEREG
+ CLKADDR(a0)
+ movb a0@(CLKSR),d0 | read clock status
+Lclkagain:
+ btst #0,d0 | clear timer1 int immediately to
+ jeq Lnotim1 | minimize chance of losing another
+ movpw a0@(CLKMSB1),d1 | due to statintr processing delay
+Lnotim1:
+ btst #2,d0 | timer3 interrupt?
+ jeq Lnotim3 | no, skip statclock
+ movpw a0@(CLKMSB3),d1 | clear timer3 interrupt
+ addql #1,_intrcnt+28 | count clock interrupts
+ lea sp@(16),a1 | a1 = &clockframe
+ movl d0,sp@- | save status
+ movl a1,sp@-
+ jbsr _statintr | statintr(&frame)
+ addql #4,sp
+ movl sp@+,d0 | restore pre-statintr status
+ CLKADDR(a0)
+Lnotim3:
+ btst #0,d0 | timer1 interrupt?
+ jeq Lrecheck | no, skip hardclock
+ addql #1,_intrcnt+24 | count hardclock interrupts
+ lea sp@(16),a1 | a1 = &clockframe
+ movl a1,sp@-
+#ifdef USELEDS
+ .globl _ledaddr, _inledcontrol, _ledcontrol, _hz
+ tstl _ledaddr | using LEDs?
+ jeq Lnoled0 | no, skip this code
+ movl heartbeat,d0 | get tick count
+ addql #1,d0 | increment
+ movl _hz,d1
+ addl #50,d1 | get the timing a little closer
+ cmpl #0,beatstatus | time to slow down?
+ jeq SlowThrob
+ lsrl #3,d1 | fast throb
+SlowThrob:
+ lsrl #1,d1 | slow throb
+ cmpl d0,d1 | are we there yet?
+ jne Lnoled1 | no, nothing to do
+ tstl _inledcontrol | already updating LEDs?
+ jne Lnoled2 | yes, skip it
+ addl #1,beatstatus | incr beat status
+ cmpl #3,beatstatus | time to reset?
+ ble SkipReset
+ movl #0,beatstatus | reset the status indicator
+SkipReset:
+ movl #LED_PULSE,sp@-
+ movl #LED_DISK+LED_LANRCV+LED_LANXMT,sp@-
+ clrl sp@-
+ jbsr _ledcontrol | toggle pulse, turn all others off
+ lea sp@(12),sp
+Lnoled2:
+ movql #0,d0
+Lnoled1:
+ movl d0,heartbeat
+Lnoled0:
+#endif
+ jbsr _hardclock | hardclock(&frame)
+ addql #4,sp
+ CLKADDR(a0)
+Lrecheck:
+ addql #1,_cnt+V_INTR | chalk up another interrupt
+ movb a0@(CLKSR),d0 | see if anything happened
+ jmi Lclkagain | while we were in hardclock/statintr
+ INTERRUPT_RESTOREREG
+ jra rei | all done
+
+_lev7intr: /* Level 7: Parity errors, reset key */
+ addql #1,_intrcnt+32
+ clrl sp@-
+ moveml #0xFFFF,sp@- | save registers
+ movl usp,a0 | and save
+ movl a0,sp@(FR_SP) | the user stack pointer
+ jbsr _nmihand | call handler
+ movl sp@(FR_SP),a0 | restore
movl a0,usp | user SP
- moveml sp@+,#0x7FFF | restore most user regs
+ moveml sp@+,#0x7FFF | and remaining registers
+ addql #8,sp | pop SP and stack adjust
+ jra rei | all done
+
+/*
+ * Emulation of VAX REI instruction.
+ *
+ * This code deals with checking for and servicing ASTs
+ * (profiling, scheduling) and software interrupts (network, softclock).
+ * We check for ASTs first, just like the VAX. To avoid excess overhead
+ * the T_ASTFLT handling code will also check for software interrupts so we
+ * do not have to do it here. After identifing that we need an AST we
+ * drop the IPL to allow device interrupts.
+ *
+ * This code is complicated by the fact that sendsig may have been called
+ * necessitating a stack cleanup.
+ */
+ .comm _ssir,1
+ .globl _astpending
+ .globl rei
+rei:
+ tstl _astpending | AST pending?
+ jeq Lchksir | no, go check for SIR
+Lrei1:
+ btst #5,sp@ | yes, are we returning to user mode?
+ jne Lchksir | no, go check for SIR
+ movw #PSL_LOWIPL,sr | lower SPL
+ clrl sp@- | stack adjust
+ moveml #0xFFFF,sp@- | save all registers
+ movl usp,a1 | including
+ movl a1,sp@(FR_SP) | the users SP
+Lrei2:
+ clrl sp@- | VA == none
+ clrl sp@- | code == none
+ movl #T_ASTFLT,sp@- | type == async system trap
+ jbsr _trap | go handle it
+ lea sp@(12),sp | pop value args
+ movl sp@(FR_SP),a0 | restore user SP
+ movl a0,usp | from save area
+ movw sp@(FR_ADJ),d0 | need to adjust stack?
+ jne Laststkadj | yes, go to it
+ moveml sp@+,#0x7FFF | no, restore most user regs
addql #8,sp | toss SP and stack adjust
- jra rei | and return
+ rte | and do real RTE
+Laststkadj:
+ lea sp@(FR_HW),a1 | pointer to HW frame
+ addql #8,a1 | source pointer
+ movl a1,a0 | source
+ addw d0,a0 | + hole size = dest pointer
+ movl a1@-,a0@- | copy
+ movl a1@-,a0@- | 8 bytes
+ movl a0,sp@(FR_SP) | new SSP
+ moveml sp@+,#0x7FFF | restore user registers
+ movl sp@,sp | and our SP
+ rte | and do real RTE
+Lchksir:
+ tstb _ssir | SIR pending?
+ jeq Ldorte | no, all done
+ movl d0,sp@- | need a scratch register
+ movw sp@(4),d0 | get SR
+ andw #PSL_IPL7,d0 | mask all but IPL
+ jne Lnosir | came from interrupt, no can do
+ movl sp@+,d0 | restore scratch register
+Lgotsir:
+ movw #SPL1,sr | prevent others from servicing int
+ tstb _ssir | too late?
+ jeq Ldorte | yes, oh well...
+ clrl sp@- | stack adjust
+ moveml #0xFFFF,sp@- | save all registers
+ movl usp,a1 | including
+ movl a1,sp@(FR_SP) | the users SP
+Lsir1:
+ clrl sp@- | VA == none
+ clrl sp@- | code == none
+ movl #T_SSIR,sp@- | type == software interrupt
+ jbsr _trap | go handle it
+ lea sp@(12),sp | pop value args
+ movl sp@(FR_SP),a0 | restore
+ movl a0,usp | user SP
+ moveml sp@+,#0x7FFF | and all remaining registers
+ addql #8,sp | pop SP and stack adjust
+ rte
+Lnosir:
+ movl sp@+,d0 | restore scratch register
+Ldorte:
+ rte | real return
/*
* Signal "trampoline" code (18 bytes). Invoked from RTE setup by sendsig().
.align 2
_esigcode:
-/*
- * ..And HPUX versions of the above. Hardcoded to use trap 2.
- */
- .globl _hpux_sigcode, _hpux_esigcode
- .data
-_hpux_sigcode:
- movl sp@(12),a0 | signal handler addr (4 bytes)
- jsr a0@ | call signal handler (2 bytes)
- addql #4,sp | pop signo (2 bytes)
- trap #2 | special syscall entry (2 bytes)
- movl d0,sp@(4) | save errno (4 bytes)
- moveq #1,d0 | syscall == exit (2 bytes)
- trap #0 | exit(errno) (2 bytes)
- .align 2
-_hpux_esigcode:
-
/*
* Primitives
*/
#include <machine/asm.h>
/*
- * non-local gotos
+ * Use common m68k support routines.
*/
-ENTRY(setjmp)
- movl sp@(4),a0 | savearea pointer
- moveml #0xFCFC,a0@ | save d2-d7/a2-a7
- movl sp@,a0@(48) | and return address
- moveq #0,d0 | return 0
- rts
-
-ENTRY(longjmp)
- movl sp@(4),a0
- moveml a0@+,#0xFCFC
- movl a0@,sp@
- moveq #1,d0
- rts
+#include <m68k/m68k/support.s>
/*
* The following primitives manipulate the run queues. _whichqs tells which
moveml #0xFCFC,a1@(PCB_REGS) | save non-scratch registers
movl usp,a2 | grab USP (a2 has been saved)
movl a2,a1@(PCB_USP) | and save it
-#ifdef FPCOPROC
+
+ tstl _fputype | Do we have an FPU?
+ jeq Lswnofpsave | No Then don't attempt save.
lea a1@(PCB_FPCTX),a2 | pointer to FP save area
fsave a2@ | save FP state
tstb a2@ | null state frame?
fmovem fp0-fp7,a2@(216) | save FP general registers
fmovem fpcr/fpsr/fpi,a2@(312) | save FP control registers
Lswnofpsave:
-#endif
#ifdef DIAGNOSTIC
tstl a0@(P_WCHAN)
moveml a1@(PCB_REGS),#0xFCFC | and registers
movl a1@(PCB_USP),a0
movl a0,usp | and USP
-#ifdef FPCOPROC
+
+ tstl _fputype | If we don't have an FPU,
+ jeq Lnofprest | don't try to restore it.
lea a1@(PCB_FPCTX),a0 | pointer to FP save area
tstb a0@ | null state frame?
jeq Lresfprest | yes, easy
fmovem a0@(216),fp0-fp7 | restore FP general registers
Lresfprest:
frestore a0@ | restore state
-#endif
+
+Lnofprest:
movw a1@(PCB_PS),sr | no, restore PS
moveq #1,d0 | return 1 (for alternate returns)
rts
movl usp,a0 | grab USP
movl a0,a1@(PCB_USP) | and save it
moveml #0xFCFC,a1@(PCB_REGS) | save non-scratch registers
-#ifdef FPCOPROC
+
+ tstl _fputype | Do we have FPU?
+ jeq Lsvnofpsave | No? Then don't save state.
lea a1@(PCB_FPCTX),a0 | pointer to FP save area
fsave a0@ | save FP state
tstb a0@ | null state frame?
fmovem fp0-fp7,a0@(216) | save FP general registers
fmovem fpcr/fpsr/fpi,a0@(312) | save FP control registers
Lsvnofpsave:
-#endif
moveq #0,d0 | return 0
rts
Lspldone:
rts
-ENTRY(_insque)
- movw sr,d0
- movw #PSL_HIGHIPL,sr | atomic
- movl sp@(8),a0 | where to insert (after)
- movl sp@(4),a1 | element to insert (e)
- movl a0@,a1@ | e->next = after->next
- movl a0,a1@(4) | e->prev = after
- movl a1,a0@ | after->next = e
- movl a1@,a0
- movl a1,a0@(4) | e->next->prev = e
- movw d0,sr
- rts
-
-ENTRY(_remque)
- movw sr,d0
- movw #PSL_HIGHIPL,sr | atomic
- movl sp@(4),a0 | element to remove (e)
- movl a0@,a1
- movl a0@(4),a0
- movl a0,a1@(4) | e->next->prev = e->prev
- movl a1,a0@ | e->prev->next = e->next
- movw d0,sr
- rts
-
/*
* _delay(u_int N)
*
jgt L_delay
rts
-#ifdef FPCOPROC
/*
* Save and restore 68881 state.
* Pretty awful looking since our assembler does not
Lm68881rdone:
frestore a0@ | restore state
rts
-#endif
/*
* Handle the nitty-gritty of rebooting the machine.
#undef DOREBOOT
.data
- .globl _machineid,_mmutype,_cputype,_ectype,_protorp,_prototc
+ .globl _machineid,_mmutype,_cputype,_ectype,_fputype
+ .globl _protorp,_prototc
_machineid:
.long HP_320 | default to 320
_mmutype:
.long CPU_68020 | default to 68020 CPU
_ectype:
.long EC_NONE | external cache type, default to none
+_fputype:
+ .long FPU_68881 | default to 68881 FPU
_protorp:
.long 0,0 | prototype root pointer
_prototc:
-/* $OpenBSD: machdep.c,v 1.20 1997/02/24 01:16:09 downsj Exp $ */
-/* $NetBSD: machdep.c,v 1.80 1997/02/02 07:58:49 thorpej Exp $ */
+/* $OpenBSD: machdep.c,v 1.21 1997/03/26 08:32:43 downsj Exp $ */
+/* $NetBSD: machdep.c,v 1.83 1997/03/16 09:12:13 thorpej Exp $ */
/*
- * Copyright (c) 1997 Theo de Raadt
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed under OpenBSD by
- * Theo de Raadt.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
* Copyright (c) 1988 University of Utah.
* Copyright (c) 1982, 1986, 1990, 1993
* The Regents of the University of California. All rights reserved.
frame->f_pc = pack->ep_entry & ~1;
frame->f_regs[SP] = stack;
frame->f_regs[A2] = (int)PS_STRINGS;
-#ifdef FPCOPROC
+
/* restore a null state frame */
p->p_addr->u_pcb.pcb_fpregs.fpf_null = 0;
- m68881_restore(&p->p_addr->u_pcb.pcb_fpregs);
-#endif
+ if (fputype)
+ m68881_restore(&p->p_addr->u_pcb.pcb_fpregs);
+
#ifdef COMPAT_SUNOS
/*
* SunOS' ld.so does self-modifying code without knowing
else
p->p_md.md_flags &= ~MDP_UNCACHE_WX;
#endif
-#ifdef COMPAT_HPUX
- p->p_md.md_flags &= ~MDP_HPUXMMAP;
- if (p->p_emul == &emul_hpux) {
- frame->f_regs[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
-
- /* Make sure the trace bit is correct. Doesn't belong here. */
- if (p->p_flag & P_TRACED)
- p->p_md.md_flags |= MDP_HPUXTRACE;
- else
- p->p_md.md_flags &= ~MDP_HPUXTRACE;
- }
-#endif
}
/*
}
#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 */
- siginfo_t *sf_sip; /* pointer to siginfo_t */
- 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 */
- siginfo_t sf_si;
-};
-
-#ifdef COMPAT_HPUX
-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;
- struct sigcontext *hsf_scp;
- int hsf_nothing;
- 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.
- */
-void
-sendsig(catcher, sig, mask, code, type, val)
- sig_t catcher;
- int sig, mask;
- u_long code;
- int type;
- union sigval val;
-{
- register struct proc *p = curproc;
- register struct sigframe *fp, *kfp;
- register struct frame *frame;
- register struct sigacts *psp = p->p_sigacts;
- register short ft;
- int oonstack, fsize;
- extern char sigcode[], esigcode[];
-#ifdef COMPAT_HPUX
- extern char hpux_sigcode[], hpux_esigcode[];
-#endif
-
- frame = (struct frame *)p->p_md.md_regs;
- ft = frame->f_format;
- oonstack = psp->ps_sigstk.ss_flags & SS_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 COMPAT_HPUX
- if (p->p_emul == &emul_hpux)
- fsize = sizeof(struct sigframe) + sizeof(struct hpuxsigframe);
- else
-#endif
- fsize = sizeof(struct sigframe);
- if ((psp->ps_flags & SAS_ALTSTACK) && !oonstack &&
- (psp->ps_sigonstack & sigmask(sig))) {
- fp = (struct sigframe *)(psp->ps_sigstk.ss_sp +
- psp->ps_sigstk.ss_size - fsize);
- psp->ps_sigstk.ss_flags |= SS_ONSTACK;
- } else
- fp = (struct sigframe *)(frame->f_regs[SP] - fsize);
- if ((unsigned)fp <= USRSTACK - ctob(p->p_vmspace->vm_ssize))
- (void)grow(p, (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_sip = NULL;
- 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 >= FMT7) {
-#ifdef DEBUG
- if (ft > 15 || exframesize[ft] < 0)
- 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, exframesize[ft]);
- /*
- * 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 to the amount the stack must be
- * adjusted by.
- *
- * N.B. we increment rather than just set f_stackadj in
- * case we are called from syscall when processing a
- * sigreturn. In that case, f_stackadj may be non-zero.
- */
- frame->f_stackadj += exframesize[ft];
- frame->f_format = frame->f_vector = 0;
-#ifdef DEBUG
- if (sigdebug & SDB_FOLLOW)
- printf("sendsig(%d): copy out %d of frame %d\n",
- p->p_pid, exframesize[ft], 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;
-
- if (psp->ps_siginfo & sigmask(sig)) {
- kfp->sf_sip = &fp->sf_si;
- initsiginfo(&kfp->sf_si, sig, code, type, val);
- }
-
-#ifdef COMPAT_HPUX
- /*
- * Create an HP-UX style sigcontext structure and associated goo
- */
- if (p->p_emul == &emul_hpux) {
- register struct hpuxsigframe *hkfp;
-
- hkfp = (struct hpuxsigframe *)&kfp[1];
- hkfp->hsf_signum = bsdtohpuxsig(kfp->sf_signum);
- 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
- /* XXX do not copy out siginfo if not needed */
- (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.
- */
-#ifdef COMPAT_HPUX
- if (p->p_emul == &emul_hpux)
- frame->f_pc = (int)PS_STRINGS - (hpux_esigcode - hpux_sigcode);
- else
-#endif
- frame->f_pc = (int)PS_STRINGS - (esigcode - sigcode);
-#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 */
-int
-sys_sigreturn(p, v, retval)
- struct proc *p;
- void *v;
- register_t *retval;
-{
- struct sys_sigreturn_args /* {
- syscallarg(struct sigcontext *) sigcntxp;
- } */ *uap = v;
- register struct sigcontext *scp;
- register struct frame *frame;
- register int rf;
- struct sigcontext tsigc;
- struct sigstate tstate;
- int flags;
-
- scp = SCARG(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 COMPAT_HPUX
- /*
- * Grab context as an HP-UX style context and determine if it
- * was one that we contructed in sendsig.
- */
- if (p->p_emul == &emul_hpux) {
- 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)) {
- if (hscp->hsc_onstack & 01)
- p->p_sigacts->ps_sigstk.ss_flags |= SS_ONSTACK;
- else
- p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK;
- p->p_sigmask = hscp->hsc_mask &~ sigcantmask;
- frame = (struct frame *) p->p_md.md_regs;
- 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
- */
- if (scp->sc_onstack & 01)
- p->p_sigacts->ps_sigstk.ss_flags |= SS_ONSTACK;
- else
- p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK;
- p->p_sigmask = scp->sc_mask &~ sigcantmask;
- frame = (struct frame *) p->p_md.md_regs;
- 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
- /*
- * fuword failed (bogus sc_ap value).
- */
- if (flags == -1)
- return (EINVAL);
- 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, SCARG(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 > 15 || (sz = exframesize[sz]) < 0)
- return (EINVAL);
- frame->f_stackadj -= sz;
- 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;
void