Only compile statically for c3po tests the same as other tests
[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 struct syscall sysc = {0};
10 struct event_queue *ev_q;
11 void *core0_tls = 0;
12
13 int main(int argc, char** argv)
14 {
15         int num_started, retval;
16         unsigned int ev_type;
17         printf("Trying to block\n");
18         /* Not doing anything else to it: no EVENT_IPI yet, etc. */
19         ev_q = get_big_event_q();
20         /* issue the diagnostic block syscall */
21         sysc.num = SYS_block;
22         sysc.ev_q = ev_q;
23         /* Trap */
24         num_started = __ros_arch_syscall((long)&sysc, 1);
25         if (!(sysc.flags & SC_DONE))
26                 printf("Not done, looping!\n");
27         #if 0
28         /* You could poll on this */
29         while (!(sysc.flags & SC_DONE))
30                 cpu_relax();
31         #endif
32         /* But let's check on events... */
33         while (!event_activity(ev_q->ev_mbox, ev_q->ev_flags))
34                 cpu_relax();
35         ev_type = get_event_type(ev_q->ev_mbox);
36         if (ev_type = EV_SYSCALL) {
37                 /* our syscall should be done (we ought to check the msg pointer) */
38                 if (sysc.flags & SC_DONE) 
39                         printf("Syscall is done, retval: %d\n", sysc.retval);
40                 else
41                         printf("BUG! Syscall wasn't done!\n");
42         } else {
43                 printf("Whoa, got an unexpected event type %d!\n", ev_type);
44         }
45
46         /* Start MCP / IPI test */
47         printf("Switching to _M mode and testing an IPI-d ev_q\n");
48 /* begin: stuff userspace needs to do before switching to multi-mode */
49         /* Need to save this somewhere that you can find it again when restarting
50          * core0 */
51         core0_tls = get_tls_desc(0);
52         /* Need to save our floating point state somewhere (like in the
53          * user_thread_tcb so it can be restarted too */
54         /* don't forget to enable notifs on vcore0 at some point */
55         struct preempt_data *vcpd;
56         vcpd = &__procdata.vcore_preempt_data[0];
57         vcpd->notif_enabled = TRUE;
58 /* end: stuff userspace needs to do before switching to multi-mode */
59
60         retval = vcore_request(1);
61         if (retval < 0)
62                 printf("No cores granted, Rut Ro Raggy!\n");
63         /* now we're back in thread 0 on vcore 0 */
64         ev_q->ev_flags = EVENT_IPI;
65         ev_q->ev_vcore = 0;
66         sysc.u_data = (void*)1; /* using this to loop on */
67         /* issue the diagnostic block syscall */
68         sysc.num = SYS_block;
69         sysc.ev_q = ev_q;
70         num_started = __ros_arch_syscall((long)&sysc, 1);
71         /* have this thread "wait" */
72         if (!(sysc.flags & SC_DONE))
73                 printf("Not done, looping on a local variable!\n");
74         while (sysc.u_data)
75                 cpu_relax();
76         assert((sysc.flags & SC_DONE));
77         printf("Syscall unblocked, IPI broke me out of the loop.\n");
78
79         /* done */
80         put_big_event_q(ev_q);
81         printf("Syscall test exiting\n");
82         return 0;
83 }
84
85 void vcore_entry(void)
86 {
87         uint32_t vcoreid = vcore_id();
88         static bool first_time = TRUE;
89
90 /* begin: stuff userspace needs to do to handle notifications */
91
92         struct vcore *vc = &__procinfo.vcoremap[vcoreid];
93         struct preempt_data *vcpd;
94         vcpd = &__procdata.vcore_preempt_data[vcoreid];
95         
96         /* here is how you receive an event */
97         struct event_msg ev_msg = {0};
98         struct event_queue_big *indir_q;
99         struct syscall *my_sysc;
100         if (event_activity(&vcpd->ev_mbox, 0)) {
101                 /* Ought to while loop/dequeue, processing as they come in. */
102                 bcq_dequeue(&vcpd->ev_mbox.ev_msgs, &ev_msg, NR_BCQ_EVENTS);
103                 if (vcpd->ev_mbox.ev_overflows)
104                         printf("Had an overflow...\n");
105                 /* should do generic handling.  this is customized for the syscalls */
106                 if (ev_msg.ev_type == EV_EVENT) {
107                         indir_q = ev_msg.ev_arg3;       /* convention */
108                         printf("Detected EV_EVENT, ev_q is %08p (%08p)\n", indir_q, ev_q);
109                         assert(indir_q);
110                         /* Ought to loop/dequeue, processing as they come in. */
111                         bcq_dequeue(&indir_q->ev_mbox->ev_msgs, &ev_msg, NR_BCQ_EVENTS);
112                         /* should have received a syscall off the indirect ev_q */
113                         if (ev_msg.ev_type == EV_SYSCALL) {
114                                 my_sysc = ev_msg.ev_arg3;
115                                 printf("Handling syscall event for sysc %08p (%08p)\n",
116                                        my_sysc, &sysc);
117                                 /* signal to thread 0 that the sysc is done, just to show this
118                                  * is getting done in vcore context. */
119                                 my_sysc->u_data = 0;
120                         } else {
121                                 printf("Got a different event, type %d\n", ev_msg.ev_type);
122                         }
123                 }
124         }
125
126         /* how we tell a preemption is pending (regardless of notif/events) */
127         if (vc->preempt_pending) {
128                 printf("Oh crap, vcore %d is being preempted!  Yielding\n", vcoreid);
129                 sys_yield(TRUE);
130                 printf("After yield on vcore %d. I wasn't being preempted.\n", vcoreid);
131         }
132                 
133         /* Restart vcore0's context. */
134         if (vcoreid == 0) {
135                 vcpd->notif_pending = 0;
136                 /* TODO: Do one last check for notifs after clearing pending */
137                 set_tls_desc(core0_tls, 0);
138                 /* Load silly state (Floating point) too */
139                 pop_ros_tf(&vcpd->notif_tf, vcoreid);
140                 panic("should never see me!");
141         }       
142         /* unmask notifications once you can let go of the notif_tf and it is okay
143          * to clobber the transition stack.
144          * Check Documentation/processes.txt: 4.2.4.  In real code, you should be
145          * popping the tf of whatever user process you want (get off the x-stack) */
146         vcpd->notif_enabled = TRUE;
147         
148 /* end: stuff userspace needs to do to handle notifications */
149         /* if you have other vcores, they'll just chill here */
150         while(1);
151 }