2LS handles pending preemptions
[akaros.git] / tests / syscall.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <parlib.h>
4 #include <event.h>
5 #include <vcore.h>
6 #include <rassert.h>
7 #include <ros/bcq.h>
8
9 static void handle_syscall(struct event_msg *ev_msg, bool overflow);
10 struct syscall sysc = {0};
11 struct event_queue *ev_q;
12 void *core0_tls = 0;
13
14 int main(int argc, char** argv)
15 {
16         int num_started, retval;
17         unsigned int ev_type;
18
19         /* register our syscall handler (2LS does this) */
20         ev_handlers[EV_SYSCALL] = handle_syscall;
21
22         printf("Trying to block\n");
23         /* Not doing anything else to it: no EVENT_IPI yet, etc. */
24         ev_q = get_big_event_q();
25         /* issue the diagnostic block syscall */
26         sysc.num = SYS_block;
27         sysc.ev_q = ev_q;
28         /* Trap */
29         num_started = __ros_arch_syscall((long)&sysc, 1);
30         if (!(sysc.flags & SC_DONE))
31                 printf("Not done, looping!\n");
32         #if 0
33         /* You could poll on this */
34         while (!(sysc.flags & SC_DONE))
35                 cpu_relax();
36         #endif
37         /* But let's check on events...  Handle event_q returns how many events it
38          * handled.  Want to spin in this testing code. */
39         while(!handle_event_q(ev_q))
40                 cpu_relax();
41         /* by now, we should have run our handler */
42         /********************************************************/
43         /* Start MCP / IPI test */
44         printf("Switching to _M mode and testing an IPI-d ev_q\n");
45         printf("Our indirect ev_q is %08p\n", ev_q);
46
47 /* begin: stuff userspace needs to do before switching to multi-mode */
48         /* Note we don't need to set up event reception for any particular kevent.
49          * The ev_q in the syscall said to send an IPI to vcore 0 which means an
50          * EV_EVENT will be sent straight to vcore0. */
51         /* Need to save this somewhere that you can find it again when restarting
52          * core0 */
53         core0_tls = get_tls_desc(0);
54         /* Need to save our floating point state somewhere (like in the
55          * user_thread_tcb so it can be restarted too */
56         enable_notifs(0);
57 /* end: stuff userspace needs to do before switching to multi-mode */
58
59         retval = vcore_request(1);
60         if (retval < 0)
61                 printf("No cores granted, Rut Ro Raggy!\n");
62         /* now we're back in thread 0 on vcore 0 */
63         ev_q->ev_flags = EVENT_IPI;
64         ev_q->ev_vcore = 0;
65         sysc.u_data = (void*)1; /* using this to loop on */
66         /* issue the diagnostic blocking syscall */
67         sysc.num = SYS_block;
68         sysc.ev_q = ev_q;
69         num_started = __ros_arch_syscall((long)&sysc, 1);
70         /* have this thread "wait" */
71         if (!(sysc.flags & SC_DONE))
72                 printf("Not done, looping on a local variable!\n");
73         while (sysc.u_data)
74                 cpu_relax();
75         assert((sysc.flags & SC_DONE));
76         printf("Syscall unblocked, IPI broke me out of the loop.\n");
77
78         /* done */
79         put_big_event_q(ev_q);
80         printf("Syscall test exiting\n");
81         return 0;
82 }
83
84 static void handle_syscall(struct event_msg *ev_msg, bool overflow)
85 {
86         struct syscall *my_sysc;
87         my_sysc = ev_msg->ev_arg3;
88         printf("Handling syscall event for sysc %08p (%08p)\n",
89                my_sysc, &sysc);
90         /* our syscall should be done (we ought to check the msg pointer) */
91         if (sysc.flags & SC_DONE) 
92                 printf("Syscall is done, retval: %d\n", sysc.retval);
93         else
94                 printf("BUG! Syscall wasn't done!\n");
95         /* signal to thread 0 that the sysc is done, just to show this
96          * is getting done in vcore context. */
97         my_sysc->u_data = 0;
98 }
99
100 void vcore_entry(void)
101 {
102         uint32_t vcoreid = vcore_id();
103         static bool first_time = TRUE;
104
105 /* begin: stuff userspace needs to do to handle notifications */
106
107         struct preempt_data *vcpd;
108         vcpd = &__procdata.vcore_preempt_data[vcoreid];
109         
110         /* checks if a preempt is pending, yields if so */
111         check_preempt_pending(vcoreid);
112                 
113         /* here is how you receive an event (remember to register the syscall
114          * handler, and whatever other handlers you want). */
115         handle_events(vcoreid);
116
117         /* Restart vcore0's context. */
118         if (vcoreid == 0) {
119                 vcpd->notif_pending = 0;
120                 /* TODO: Do one last check for notifs after clearing pending */
121                 set_tls_desc(core0_tls, 0);
122                 /* Load silly state (Floating point) too */
123                 pop_ros_tf(&vcpd->notif_tf, vcoreid);
124                 panic("should never see me!");
125         }       
126         /* unmask notifications once you can let go of the notif_tf and it is okay
127          * to clobber the transition stack.
128          * Check Documentation/processes.txt: 4.2.4.  In real code, you should be
129          * popping the tf of whatever user process you want (get off the x-stack) */
130         vcpd->notif_enabled = TRUE;
131         
132 /* end: stuff userspace needs to do to handle notifications */
133         /* if you have other vcores, they'll just chill here */
134         while(1);
135 }