extern void *get_usp(void);
extern void set_usp(void *p);
-void signal_frame(uint8_t *trapframe, uint32_t d0, uint32_t d1, uint32_t a0,
- uint32_t a1)
+/* We do as much exception processing in software as we can. This code
+ is called from the asm trap hooks on the supervisor stack and expected
+ to sort the mess out */
+
+/* The stackframe we work with looks like this when exception is called */
+
+struct trapdata {
+ /* MOVEM.L with predecrement stores A7 to A0 then D7 to D0. In other
+ words viewed in memory order it is D0-D7 then A0-A7 (A6 for us
+ as we don't store A7) */
+ uint32_t d[8];
+ uint32_t a[7];
+ uint16_t trap; /* Pushed second */
+ uint16_t sr; /* Condition codes */
+ /* The CPU pushed the frame which sits above the MOVEM */
+ uint16_t exception[0]; /* CPU exception frame */
+};
+
+#define FRAME_A 1
+#define FRAME_B 2
+
+static void explode(struct trapdata *framedata, int type)
+{
+ uint16_t *excp = framedata->exception;
+ uint32_t *fv;
+ int i;
+
+ kprintf("Trap: %d\n", framedata->trap);
+ kprintf("Register Dump\nA: ");
+ for (i = 0; i < 8; i++)
+ kprintf("%p ", framedata->a[i]);
+ kprintf("\nD: ");
+ for (i = 0; i < 8; i++)
+ kprintf("%p ", framedata->d[i]);
+ kprintf("\nUSP: %p SR: %x\n", get_usp(), framedata->sr);
+
+ /* For now we only do 68000 */
+ if (type == FRAME_A) {
+ kputs((excp[0] & 0x10)?"R":"W");
+ kprintf(" FC %x\n", excp[0] & 7);
+ fv = (uint32_t *)(excp + 1);
+ kprintf(" Addr %p IR %x", *fv, excp[3]);
+ excp += 4;
+ }
+ if (type == FRAME_A || type == FRAME_B) {
+ fv = (uint32_t *)(excp + 1);
+ kprintf("PC %p SR %x\n", *fv, excp[1]);
+ }
+}
+
+/* Our caller did a movem of the registers to kstack then pushed an
+ exception and other info. This all sits on the kstack but pass
+ a pointer to it for flexibility.
+
+ On return it will pull the state back and rte. We can thus adjust
+ what happens according to need.
+
+ To keep common code we push the same frame for all cases */
+
+static uint8_t pushw(uint16_t **usp, uint16_t v)
{
- extern void *udata_shadow;
- uint8_t *usp = get_usp();
- udata_ptr = udata_shadow;
- uint16_t ccr = *(uint16_t *)trapframe;
- uint32_t addr = *(uint32_t *)(trapframe + 2);
- int err = 0;
-
- /* Build the user stack frame */
-
- /* FIXME: eventually we should put the trap frame details and trap
- info into the frame */
- usp -= 4;
- err |= uputl(addr, usp);
- usp -= 4;
- err |= uputw(ccr, usp);
- usp -= 2;
- err |=uputl(a1, usp);
- usp -= 4;
- err |= uputl(a0, usp);
- usp -= 4;
- err |= uputl(d1, usp);
- usp -= 4;
- err |= uputl(d0, usp);
- usp -= 4;
- err |= uputl(udata.u_codebase + 4, usp);
+ (*usp)--;
+ return uputw(v, *usp);
+}
+
+static uint8_t pushl(uint16_t **usp, uint32_t v)
+{
+ (*usp) -= 2;
+ return uputl(v, *usp);
+}
+
+extern uint8_t kernel_flag;
+
+int exception(struct trapdata *framedata)
+{
+ ptptr proc;
+ unsigned int frame, fsize;
+ uint8_t trap = framedata->trap;
+ unsigned int sig = 0;
+ uint16_t m;
+ uint16_t *sp = (uint16_t *)framedata;
+ uint16_t *usp = get_usp();
+ uint16_t *unwind, *context;
+ uint8_t err = 0;
+ int i;
+
+ /* We translate debug to SIGIOT and A and F line to SIGILL
+ We will need to fix up 68000 v 68010 move to/from SR */
+ static const uint8_t trap_to_sig[] = {
+ 0, 0, SIGSEGV, SIGBUS, SIGILL, SIGFPE,
+ SIGABRT/*CHK*/, SIGTRAP/*TRAPV */,
+ SIGILL, SIGIOT, SIGILL, SIGILL };
+
+ proc = udata.u_ptab;
+
+ /* Most synchronous exceptions are type B */
+ /* FIXME: sizes need to become chip aware */
+ frame = FRAME_B;
+ fsize = 3; /* Three words on 68000 */
+ /* TODO: On the 68010 there are at least 4 words as word 4 always holds
+ the vector and format */
+ if (trap < 4) {
+ /* TODO: On a 68010 this frame is 29 words and the event is
+ restartable (although not always usefully). We need to
+ decide whether to set the restart flag case by case */
+ frame = FRAME_A;
+ fsize = 7;
+ }
+ if (trap < 12)
+ sig = trap_to_sig[sig];
+ else if (trap >= 32 && trap < 48)
+ sig = SIGTRAP;
+ else if (trap == 0) {
+ sig = udata.u_cursig;
+ udata.u_cursig = 0;
+ }
+
+ /* This processing only applies to synchronous hardware exceptions */
+ if (trap) {
+ /* Went boom in kernel space or without a user recovery */
+ if (kernel_flag || sig == 0) {
+ explode(framedata, frame);
+ panic("trap");
+ }
+
+ /* Cheating here .. all our exceptions are low 16 signal */
+ m = 1 << sig;
+ /*
+ * The caller is ignoring our signal. In some cases this is fine
+ * but in others it's less clear (eg division by zero) and we
+ * may need to take different action.
+ */
+ if (proc->p_sig[0].s_ignored & m)
+ return 0;
+ /* Weird case - we took a sync signal and the caller wants us to
+ report it later. */
+ if (proc->p_sig[0].s_held & m) {
+ /* TODO: if it's not meaningfully restartable we should
+ probably treat this as a kill */
+ ssig(proc, sig);
+ return 0;
+ }
+ recalc_cursig(); /* Put any async signal back */
+ }
+ if (udata.u_sigvec[sig] == SIG_DFL) {
+ /* Default action for our signal ? */
+ doexit(dump_core(sig));
+ /* This will never return. We will go schedule new work */
+ panic("exret");
+ }
+ /* build signal frame
+
+ Our unwinder code does
+ move.l 8(sp),sp
+ movem.l a0-a1/d0-d1,(sp)+
+ move.w (sp)+,ccr
+ rts */
+
+ /* Push the recovery PC */
+ err |= pushw(&usp, sp[31 + fsize]);
+ err |= pushw(&usp, sp[30 + fsize]);
+ /* FIXME: when we do ptrace we will need to support adding the T
+ flag back here as the exception cleared it */
+ err |= pushw(&usp, framedata->sr);
+ /* Push A1 A0 D1 D0 to match MOVEM.L */
+ err |= pushl(&usp, framedata->a[1]);
+ err |= pushl(&usp, framedata->a[0]);
+ err |= pushl(&usp, framedata->d[1]);
+ err |= pushl(&usp, framedata->d[0]);
+
+ /* Remember the target for undoing the frame */
+ unwind = get_usp();
+
+ /* Copy in the signal context itself. 30 words of registers, 2 of
+ trap code and then the hardware exception */
+ for (i = 0; i < 30 + 2 + fsize; i++)
+ err |= pushw(&usp, *sp++);
+ context = usp;
+ err |= pushl(&usp, (uint32_t)unwind);
+ /* Signal context is a secret extra non portable argument */
+ err |= pushl(&usp, (uint32_t)context);
+ /* We end it with the call frame as seen from the signal handler, a
+ single argument and a return address */
+ err |= pushl(&usp, sig);
+ err |= pushl(&usp, udata.u_codebase + 0x04);
+
set_usp(usp);
if (err) {
- kprintf("%d: stack fault\n", udata.u_ptab->p_pid);
- doexit(SIGKILL/* FIXME dump_core(SIGKILL)*/);
+ doexit(dump_core(SIGSTKFLT));
+ panic("exret2");
}
- /* Now patch up the kernel frame */
- *(uint16_t *)trapframe = 0;
- *(uint32_t *)(trapframe + 2) = (uint32_t)udata.u_sigvec[udata.u_cursig];
- udata.u_sigvec[udata.u_cursig] = SIG_DFL;
- udata.u_cursig = 0;
+ /* Once built clear the restart state */
+ udata.u_sigvec[sig] = SIG_DFL;
+ /* Return, RTE and end up on the signal frame */
+ return 1;
}