void signal_frame(uint8_t *trapframe, uint32_t d0, uint32_t d1, uint32_t a0, uint32_t a1) { 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); set_usp(usp); if (err) { kprintf("%d: stack fault\n", udata.u_ptab->p_pid); doexit(dump_core(SIGKILL)); } /* 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; }
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, SIGFPE }; proc = udata.u_ptab; if (sysinfo.cpu[0] == 10) { /* Long or short frame: the CPU tells us the frame format */ if (framedata->exception[3] & 0x8000) { fsize = 29; frame = FRAME_C; } else { fsize = 4; frame = FRAME_D; } } else { frame = FRAME_B; fsize = 3; } if (trap == 0) { sig = udata.u_cursig; udata.u_cursig = 0; } else if (trap < 12) { if (trap < 4) { /* 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 */ if (sysinfo.cpu[0] == 0) { frame = FRAME_A; fsize = 7; } } sig = trap_to_sig[trap]; } else if (trap >= 32 && trap < 48) sig = SIGTRAP; /* 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 */ /* Now update the user stack */ /* - Push the recovery PC */ /* - Patch the kernel exception frame */ if (sysinfo.cpu[0]) { /* FIXME */ err |= pushw(&usp, sp[34]); err |= pushw(&usp, sp[33]); *(uint32_t *)(&sp[33]) = (uint32_t)udata.u_sigvec[sig]; } else { err |= pushw(&usp, sp[31 + fsize]); err |= pushw(&usp, sp[30 + fsize]); *(uint32_t *)(&sp[30 + fsize]) = (uint32_t)udata.u_sigvec[sig]; } /* 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 = 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) { doexit(dump_core(SIGSTKFLT)); panic("exret2"); } /* Once built clear the restart state */ udata.u_sigvec[sig] = SIG_DFL; /* Return, RTE and end up on the signal frame */ return 1; }