From: Alan Cox Date: Sun, 20 Jan 2019 23:31:16 +0000 (+0000) Subject: tiny68k: adapt C code to proposed new exception logic X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=de671013e170b9c1f29508cc23b3c2be70ebdbe0;p=FUZIX.git tiny68k: adapt C code to proposed new exception logic --- diff --git a/Kernel/platform-tiny68k/main.c b/Kernel/platform-tiny68k/main.c index e91de50c..2aec656c 100644 --- a/Kernel/platform-tiny68k/main.c +++ b/Kernel/platform-tiny68k/main.c @@ -98,43 +98,200 @@ void install_vdso(void) 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; }