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