Kernel reflects unhandled faults to SCPs
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 13 Jul 2015 22:10:28 +0000 (18:10 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 16 Jul 2015 20:07:53 +0000 (16:07 -0400)
The lack of verbosity from userspace can be a little difficult.  Just a
trapframe isn't always enough.  To fix this, you can turn on printx to
have the kernel spew whatever info it has for any malignant faults
(non-benign).  Benign faults are those that occur during normal
operation.

At this point, the kernel shouldn't care at all if an SCP uses a 2LS or
not.  Outside proc code, the major places that care about SCP vs MCP are
the scheduler, event code (just spam messages to VC 0), and the page
fault handler (helps out SCPs).

The latter point means that SCPs with 2LSs won't actually get their
VMR-backed page faults reflected - instead the kernel just blocks them.
Considering how there is no guarantee to SCPs that they retain their
core during blocking events, I'm okay with this for now.

The alternative is to have a more capable __scp_thread_refl_fault()
handler and slightly worse performance for all processes before they
turn into MCPs (more expensive PFs when they are initializing).

kern/include/process.h
kern/src/process.c
kern/src/trap.c
user/parlib/thread0_sched.c
user/pthread/pthread.c

index bf8e3d5..a6e345f 100644 (file)
@@ -86,6 +86,7 @@ void proc_yield(struct proc *p, bool being_nice);
 void proc_notify(struct proc *p, uint32_t vcoreid);
 void proc_wakeup(struct proc *p);
 bool __proc_is_mcp(struct proc *p);
+bool proc_is_vcctx_ready(struct proc *p);
 int proc_change_to_vcore(struct proc *p, uint32_t new_vcoreid,
                          bool enable_my_notif);
 
index 4465740..bbffe06 100644 (file)
@@ -1348,6 +1348,12 @@ bool __proc_is_mcp(struct proc *p)
        return p->procinfo->is_mcp;
 }
 
+bool proc_is_vcctx_ready(struct proc *p)
+{
+       struct preempt_data *vcpd = &p->procdata->vcore_preempt_data[0];
+       return scp_is_vcctx_ready(vcpd);
+}
+
 /************************  Preemption Functions  ******************************
  * Don't rely on these much - I'll be sure to change them up a bit.
  *
index 9e0f9b9..728dacd 100644 (file)
 #include <kdebug.h>
 #include <kmalloc.h>
 
+static void print_unhandled_trap(struct proc *p, struct user_context *ctx,
+                                 unsigned int trap_nr, unsigned int err,
+                                 unsigned long aux)
+{
+       print_user_ctx(ctx);
+       printk("err 0x%x (for PFs: User 4, Wr 2, Rd 1), aux %p\n", err, aux);
+       debug_addr_proc(p, get_user_ctx_pc(ctx));
+       print_vmrs(p);
+       backtrace_user_ctx(p, ctx);
+}
+
+/* Traps that are considered normal operations. */
+static bool benign_trap(unsigned int err)
+{
+       return err & PF_VMR_BACKED;
+}
+
+static void printx_unhandled_trap(struct proc *p, struct user_context *ctx,
+                                  unsigned int trap_nr, unsigned int err,
+                                  unsigned long aux)
+{
+       if (printx_on && !benign_trap(err))
+               print_unhandled_trap(p, ctx, trap_nr, err, aux);
+}
+
 void reflect_unhandled_trap(unsigned int trap_nr, unsigned int err,
                             unsigned long aux)
 {
@@ -24,14 +49,15 @@ void reflect_unhandled_trap(unsigned int trap_nr, unsigned int err,
        struct hw_trapframe *hw_tf = &pcpui->cur_ctx->tf.hw_tf;
        assert(p);
        assert(pcpui->cur_ctx && (pcpui->cur_ctx->type == ROS_HW_CTX));
-       if (!(p->procinfo->is_mcp)) {
-               printk("Unhandled SCP trap\n");
+       if (!proc_is_vcctx_ready(p)) {
+               printk("Unhandled user trap from early SCP\n");
                goto error_out;
        }
        if (vcpd->notif_disabled) {
-               printk("Unhandled MCP trap in vcore context\n");
+               printk("Unhandled user trap in vcore context\n");
                goto error_out;
        }
+       printx_unhandled_trap(p, pcpui->cur_ctx, trap_nr, err, aux);
        /* need to store trap_nr, err code, and aux into the tf so that it can get
         * extracted on the other end, and we need to flag the TF in some way so we
         * can tell it was reflected.  for example, on a PF, we need some number (14
@@ -46,11 +72,8 @@ void reflect_unhandled_trap(unsigned int trap_nr, unsigned int err,
                      vcpd->transition_stack, vcpd->vcore_tls_desc);
        return;
 error_out:
-       print_trapframe(hw_tf);
+       print_unhandled_trap(p, pcpui->cur_ctx, trap_nr, err, aux);
        enable_irq();
-       printk("err 0x%x (for PFs: User 4, Wr 2, Rd 1), aux %p\n", err, aux);
-       debug_addr_proc(p, get_hwtf_pc(hw_tf));
-       print_vmrs(p);
        proc_destroy(p);
 }
 
index 587b1e6..926d6e8 100644 (file)
 
 static void thread0_sched_entry(void);
 static void thread0_thread_blockon_sysc(struct uthread *uthread, void *sysc);
+static void thread0_thread_refl_fault(struct uthread *uthread,
+                                      unsigned int trap_nr, unsigned int err,
+                                      unsigned long aux);
 
 /* externed into uthread.c */
 struct schedule_ops thread0_2ls_ops = {
        .sched_entry = thread0_sched_entry,
        .thread_blockon_sysc = thread0_thread_blockon_sysc,
+       .thread_refl_fault = thread0_thread_refl_fault,
 };
 
 /* externed into uthread.c */
@@ -64,3 +68,14 @@ static void thread0_thread_blockon_sysc(struct uthread *uthread, void *arg)
                __ros_syscall_noerrno(SYS_yield, FALSE, 0, 0, 0, 0, 0);
        }
 }
+
+static void thread0_thread_refl_fault(struct uthread *uthread,
+                                      unsigned int trap_nr, unsigned int err,
+                                      unsigned long aux)
+{
+       printf("SCP has unhandled fault: %d, err: %d, aux: %p\n", trap_nr, err,
+              aux);
+       print_user_context(&uthread->u_ctx);
+       printf("Turn on printx to spew unhandled, malignant trap info\n");
+       exit(-1);
+}
index e488ec3..3b8d721 100644 (file)
@@ -463,9 +463,12 @@ void pth_thread_refl_fault(struct uthread *uthread, unsigned int trap_nr,
                        handle_page_fault(uthread, err, aux);
                        break;
                default:
-                       printf("Pthread has unhandled fault: %d\n", trap_nr);
-                       /* Note that uthread.c already copied out our ctx into the uth struct */
+                       printf("Pthread has unhandled fault: %d, err: %d, aux: %p\n",
+                              trap_nr, err, aux);
+                       /* Note that uthread.c already copied out our ctx into the uth
+                        * struct */
                        print_user_context(&uthread->u_ctx);
+                       printf("Turn on printx to spew unhandled, malignant trap info\n");
                        exit(-1);
        }
 #else