v68: first cut at backporting all the extra bits
authorAlan Cox <alan@linux.intel.com>
Mon, 21 Jan 2019 22:35:16 +0000 (22:35 +0000)
committerAlan Cox <alan@linux.intel.com>
Mon, 21 Jan 2019 22:35:16 +0000 (22:35 +0000)
Kernel/platform-v68/main.c
Kernel/platform-v68/p68000.S

index 000f3cc..b1ac02c 100644 (file)
@@ -72,43 +72,231 @@ 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;
+       unsigned int i = framedata->trap;
+       unsigned int j;
+
+       if (i > 12)
+               i = 12;
+
+       for (j = 0; j < i; j++)
+               kputs("   '* ");
+       kputchar('\n');
+       for (j = 0; j < i; j++)
+               kputs("  |   ");
+       kputchar('\n');
+       for (j = 0; j < i; j++)
+               kputs(".###. ");
+       kputchar('\n');
+       for (j = 0; j < i; j++)
+               kputs("##### ");
+       kputchar('\n');
+       for (j = 0; j < i; j++)
+               kputs("##### ");
+       kputchar('\n');
+       for (j = 0; j < i; j++)
+               kputs("`###' ");
+       kputchar('\n');
+
+       kprintf("Trap: %d\n", framedata->trap);
+       kprintf("Register Dump\nA: ");
+       for (i = 0; i < 7; i++)
+               kprintf("%p ", framedata->a[i]);
+       kprintf("%p\nD: ", get_usp());
+       for (i = 0; i < 8; i++)
+               kprintf("%p ", framedata->d[i]);
+       kprintf("\nSR: %x\n", framedata->sr);
+
+       kprintf("Exception frame:\n");
+       for (j = 0;j < 16; j++)
+               kprintf("%d: %x\n", j, excp[j]);
+
+       /* For now we only do 68000 */
+       if (type == FRAME_A) {
+               kputs((excp[0] & 0x10)?"R":"W");
+               kprintf(" FC %x", 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);
+       }
+}
+
+/* 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)
+{
+       (*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)
 {
-       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);
+       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;
+
+       /* 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 == 0) {
+               sig = udata.u_cursig;
+               udata.u_cursig = 0;
+       } else if (trap < 12) {
+               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;
+               }
+               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 */
+
+       /* Push the recovery PC */
+
+       /* Now update the user stack */
+       err |= pushw(&usp, sp[31 + fsize]);
+       err |= pushw(&usp, sp[30 + fsize]);
+
+       /* Patch the kernel exception frame */
+       *(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) {
-               kprintf("%d: stack fault\n", udata.u_ptab->p_pid);
-               doexit(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;
 }
index df93e9c..d0f81f6 100644 (file)
@@ -38,6 +38,7 @@ init_hardware:
            move.l #8,a0
            move.w #253,d0
            move.l #unexpected,d1
+
 init_trap_loop:
            move.l d1,(a0)+
            dbra d0,init_trap_loop
@@ -56,15 +57,26 @@ init_trap_loop:
            move.l #unimpa,(a0)+        ; A and F line traps
            move.l #unimpf,(a0)+
            move.w #$80,a0
-           move.w #13,d0
-trapset:
-           move.l #misctrap,(a0)+
-           dbra d0,trapset
+           move.l #trap0,(a0)+
+           move.l #trap1,(a0)+
+           move.l #trap2,(a0)+
+           move.l #trap3,(a0)+
+           move.l #trap4,(a0)+
+           move.l #trap5,(a0)+
+           move.l #trap6,(a0)+
+           move.l #trap7,(a0)+
+           move.l #trap8,(a0)+
+           move.l #trap9,(a0)+
+           move.l #trap10,(a0)+
+           move.l #trap11,(a0)+
+           move.l #trap12,(a0)+
+           move.l #trap13,(a0)+
            move.l #trap14,(a0)+
-           move.l #trap15,(a0)+
+           move.l #trap15,(a0)
            move.w #$0,a0
            move.l #uninit,$3c(a0)
            move.l #spurious,$60(a0)
+
            move.l #timer_irq,$78(a0)
            move.l #mmu_fault,$7C(a0)
 
@@ -84,20 +96,35 @@ timer_irq:
            tst.b U_DATA__U_INSYS(a5)
            bne no_preempt
            tst.b need_resched
-           bne no_preempt
+           beq no_preempt
            ;
            ;   Vanish into the scheduler. Some other task will pop back out
            ;   and eventually we'll re-appear here and continue.
            ;
            ;   FIXME: check IRQ masking
            ;
-           move.l U_DATA__U_PTAB(a5),a0
+           ; We might be in STOPPED state in which case do not go back
+           ; to ready !
+           cmp.b #P_RUNNING,P_TAB__P_STATUS_OFFSET(a0)
+           bne no_ready
            move.b #P_READY,P_TAB__P_STATUS_OFFSET(a0)
+no_ready:
+           move.l U_DATA__U_PTAB(a5),a0
            bsr switchout
 no_preempt:
            tst.b U_DATA__U_CURSIG(a5)
            beq no_signal
-           bra trap_via_signal         ; a0/a1/d0/d1 already stacked
+           ;   FIXME: this is ugly
+           movem.l (sp)+,a0-a1/a5/d0-d1
+           move.w sr,-(sp)
+           move.w #0,-(sp)
+           movem.l a0-a6/d0-d7,-(sp)
+           move.l (sp),-(sp)
+           bsr exception
+           addq #4,sp
+           movem.l (sp)+,a0-a6/d0-d7
+           addq #4,sp
+           rte
 
 no_signal:
            movem.l (sp)+,a0-a1/a5/d0-d1
@@ -161,14 +188,12 @@ devide_write_l:
 ;
 ;      'VDSO'
 ;
-vdso:  trap #14                ; syscall entry
+vdso:  trap #12                ; syscall entry
        rts
        ; signal unwind
+       move.l 8(sp),sp         ; blow away stack frame
        movem.l (sp)+,a0/a1/d0/d1
        move.w (sp)+,ccr
        rts
        ; rest is spare for now
 
-.section data
-
-kernel_flag: byte 1