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