Kernel reflects unhandled faults to SCPs
[akaros.git] / user / parlib / thread0_sched.c
1 /* Copyright (c) 2015 Google, Inc.
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * thread0_sched: a basic scheduler for thread0, used by SCPs without a
6  * multithreaded 2LS linked in.
7  *
8  * This is closely coupled with uthread.c */
9
10 #include <ros/arch/membar.h>
11 #include <parlib/arch/atomic.h>
12 #include <parlib/parlib.h>
13 #include <parlib/vcore.h>
14 #include <parlib/uthread.h>
15 #include <parlib/event.h>
16 #include <stdlib.h>
17
18 static void thread0_sched_entry(void);
19 static void thread0_thread_blockon_sysc(struct uthread *uthread, void *sysc);
20 static void thread0_thread_refl_fault(struct uthread *uthread,
21                                       unsigned int trap_nr, unsigned int err,
22                                       unsigned long aux);
23
24 /* externed into uthread.c */
25 struct schedule_ops thread0_2ls_ops = {
26         .sched_entry = thread0_sched_entry,
27         .thread_blockon_sysc = thread0_thread_blockon_sysc,
28         .thread_refl_fault = thread0_thread_refl_fault,
29 };
30
31 /* externed into uthread.c */
32 struct uthread *thread0_uth;
33
34 /* Thread0 scheduler ops (for processes that haven't linked in a full 2LS) */
35 static void thread0_sched_entry(void)
36 {
37         if (current_uthread)
38                 run_current_uthread();
39         else
40                 run_uthread(thread0_uth);
41 }
42
43 static void thread0_thread_blockon_sysc(struct uthread *uthread, void *arg)
44 {
45         struct syscall *sysc = (struct syscall*)arg;
46         /* We're in vcore context.  Regardless of what we do here, we'll pop back in
47          * to vcore entry, just like with any uthread_yield.  We don't have a 2LS,
48          * but we always have one uthread: the SCP's thread0.  Note that at this
49          * point, current_uthread is still set, but will be cleared as soon as the
50          * callback returns (and before we start over in vcore_entry).
51          *
52          * If notif_pending is already set (due to a concurrent signal), we'll fail
53          * to yield.  Once in VC ctx, we'll handle any other signals/events that
54          * arrived, then restart the uthread that issued the syscall, which if the
55          * syscall isn't done yet, will just blockon again.
56          *
57          * The one trick is that we don't want to register the evq twice.  The way
58          * register_evq currently works, if a SC completed (SC_DONE) while we were
59          * registering, we could end up clearing sysc->ev_q before the kernel sees
60          * it.  We'll use u_data to track whether we registered or not. */
61         #define U_DATA_BLOB ((void*)0x55555555)
62         if ((sysc->u_data == U_DATA_BLOB)
63             || register_evq(sysc, &__ros_scp_simple_evq)) {
64                 sysc->u_data = U_DATA_BLOB;
65                 /* Sending false for now - we want to signal proc code that we want to
66                  * wait (piggybacking on the MCP meaning of this variable).  If
67                  * notif_pending is set, the kernel will immediately return us. */
68                 __ros_syscall_noerrno(SYS_yield, FALSE, 0, 0, 0, 0, 0);
69         }
70 }
71
72 static void thread0_thread_refl_fault(struct uthread *uthread,
73                                       unsigned int trap_nr, unsigned int err,
74                                       unsigned long aux)
75 {
76         printf("SCP has unhandled fault: %d, err: %d, aux: %p\n", trap_nr, err,
77                aux);
78         print_user_context(&uthread->u_ctx);
79         printf("Turn on printx to spew unhandled, malignant trap info\n");
80         exit(-1);
81 }