Add a helper for async syscalls
[akaros.git] / user / parlib / syscall.c
1 // System call stubs.
2
3 #include <parlib/parlib.h>
4 #include <parlib/vcore.h>
5 #include <parlib/serialize.h>
6
7 int sys_proc_destroy(int pid, int exitcode)
8 {
9         return ros_syscall(SYS_proc_destroy, pid, exitcode, 0, 0, 0, 0);
10 }
11
12 size_t sys_getpcoreid(void)
13 {
14          return ros_syscall(SYS_getpcoreid, 0, 0, 0, 0, 0, 0);
15 }
16
17 int sys_null(void)
18 {
19     return ros_syscall(SYS_null, 0, 0, 0, 0, 0, 0);
20 }
21
22 ssize_t sys_shared_page_alloc(void** addr, pid_t p2, 
23                               int p1_flags, int p2_flags
24                              ) 
25 {
26         return ros_syscall(SYS_shared_page_alloc, addr, 
27                        p2, p1_flags, p2_flags, 0, 0);
28 }
29
30 ssize_t sys_shared_page_free(void* addr, pid_t p2) 
31 {
32         return ros_syscall(SYS_shared_page_free, addr, p2, 0, 0, 0, 0);
33 }
34
35 void sys_reboot(void)
36 {
37         ros_syscall(SYS_reboot, 0, 0, 0, 0, 0, 0);
38 }
39
40 void sys_yield(bool being_nice)
41 {
42         ros_syscall(SYS_yield, being_nice, 0, 0, 0, 0, 0);
43 }
44
45 int sys_proc_create(const char *path, size_t path_l, char *const argv[],
46                     char *const envp[], int flags)
47 {
48         struct serialized_data *sd = serialize_argv_envp(argv, envp);
49         if (!sd) {
50                 errno = ENOMEM;
51                 return -1;
52         }
53         int ret = ros_syscall(SYS_proc_create, path, path_l,
54                               sd->buf, sd->len, flags, 0);
55         free_serialized_data(sd);
56         return ret;
57 }
58
59 int sys_proc_run(int pid)
60 {
61         return ros_syscall(SYS_proc_run, pid, 0, 0, 0, 0, 0);
62 }
63
64 void *sys_mmap(void *addr, size_t length, int prot, int flags,
65                int fd, size_t offset)
66 {
67         return (void*)ros_syscall(SYS_mmap, addr, length, prot, flags, fd, offset);
68 }
69
70 int sys_provision(int pid, unsigned int res_type, long res_val)
71 {
72         return ros_syscall(SYS_provision, pid, res_type, res_val, 0, 0, 0);
73 }
74
75 int sys_notify(int pid, unsigned int ev_type, struct event_msg *u_msg)
76 {
77         return ros_syscall(SYS_notify, pid, ev_type, u_msg, 0, 0, 0);
78 }
79
80 int sys_self_notify(uint32_t vcoreid, unsigned int ev_type,
81                     struct event_msg *u_msg, bool priv)
82 {
83         return ros_syscall(SYS_self_notify, vcoreid, ev_type, u_msg, priv, 0, 0);
84 }
85
86 int sys_halt_core(unsigned int usec)
87 {
88         return ros_syscall(SYS_halt_core, usec, 0, 0, 0, 0, 0);
89 }
90
91 void* sys_init_arsc()
92 {
93         return (void*)ros_syscall(SYS_init_arsc, 0, 0, 0, 0, 0, 0);
94 }
95
96 int sys_block(unsigned int usec)
97 {
98         return ros_syscall(SYS_block, usec, 0, 0, 0, 0, 0);
99 }
100
101 /* enable_my_notif tells the kernel whether or not it is okay to turn on notifs
102  * when our calling vcore 'yields'.  This controls whether or not the vcore will
103  * get started from vcore_entry() or not, and whether or not remote cores need
104  * to sys_change_vcore to preempt-recover the calling vcore.  Only set this to
105  * FALSE if you are unable to handle starting fresh at vcore_entry().  One
106  * example of this is in mcs_pdr_locks.
107  *
108  * Will return:
109  *              0 if we successfully changed to the target vcore.
110  *              -EBUSY if the target vcore is already mapped (a good kind of failure)
111  *              -EAGAIN if we failed for some other reason and need to try again.  For
112  *              example, the caller could be preempted, and we never even attempted to
113  *              change.
114  *              -EINVAL some userspace bug */
115 int sys_change_vcore(uint32_t vcoreid, bool enable_my_notif)
116 {
117         /* Since we might be asking to start up on a fresh stack (if
118          * enable_my_notif), we need to use some non-stack memory for the struct
119          * sysc.  Our vcore could get restarted before the syscall finishes (after
120          * unlocking the proc, before finish_sysc()), and the act of finishing would
121          * write onto our stack.  Thus we use the per-vcore struct. */
122         int flags;
123         /* Need to wait while a previous syscall is not done or locked.  Since this
124          * should only be called from VC ctx, we'll just spin.  Should be extremely
125          * rare.  Note flags is initialized to SC_DONE. */
126         do {
127                 cpu_relax();
128                 flags = atomic_read(&__vcore_one_sysc.flags);
129         } while (!(flags & SC_DONE) || flags & SC_K_LOCK);
130         __vcore_one_sysc.num = SYS_change_vcore;
131         __vcore_one_sysc.arg0 = vcoreid;
132         __vcore_one_sysc.arg1 = enable_my_notif;
133         /* keep in sync with glibc sysdeps/ros/syscall.c */
134         __ros_arch_syscall((long)&__vcore_one_sysc, 1);
135         /* If we returned, either we wanted to (!enable_my_notif) or we failed.
136          * Need to wait til the sysc is finished to find out why.  Again, its okay
137          * to just spin. */
138         do {
139                 cpu_relax();
140                 flags = atomic_read(&__vcore_one_sysc.flags);
141         } while (!(flags & SC_DONE) || flags & SC_K_LOCK);
142         return __vcore_one_sysc.retval;
143 }
144
145 int sys_change_to_m(void)
146 {
147         return ros_syscall(SYS_change_to_m, 0, 0, 0, 0, 0, 0);
148 }
149
150 int sys_poke_ksched(int pid, unsigned int res_type)
151 {
152         return ros_syscall(SYS_poke_ksched, pid, res_type, 0, 0, 0, 0);
153 }
154
155 int sys_abort_sysc(struct syscall *sysc)
156 {
157         return ros_syscall(SYS_abort_sysc, sysc, 0, 0, 0, 0, 0);
158 }
159
160 int sys_abort_sysc_fd(int fd)
161 {
162         return ros_syscall(SYS_abort_sysc_fd, fd, 0, 0, 0, 0, 0);
163 }
164
165 int sys_tap_fds(struct fd_tap_req *tap_reqs, size_t nr_reqs)
166 {
167         return ros_syscall(SYS_tap_fds, tap_reqs, nr_reqs, 0, 0, 0, 0);
168 }
169
170 void syscall_async(struct syscall *sysc, unsigned long num, ...)
171 {
172         va_list args;
173
174         sysc->num = num;
175         sysc->flags = 0;
176         sysc->ev_q = 0;         /* not necessary, but good for debugging */
177         /* This is a little dangerous, since we'll usually pull more args than were
178          * passed in, ultimately reading gibberish off the stack. */
179         va_start(args, num);
180         sysc->arg0 = va_arg(args, long);
181         sysc->arg1 = va_arg(args, long);
182         sysc->arg2 = va_arg(args, long);
183         sysc->arg3 = va_arg(args, long);
184         sysc->arg4 = va_arg(args, long);
185         sysc->arg5 = va_arg(args, long);
186         va_end(args);
187         __ros_arch_syscall((long)sysc, 1);
188 }
189
190 void syscall_async_evq(struct syscall *sysc, struct event_queue *evq,
191                        unsigned long num, ...)
192 {
193         va_list args;
194
195         sysc->num = num;
196         atomic_set(&sysc->flags, SC_UEVENT);
197         sysc->ev_q = evq;
198         /* This is a little dangerous, since we'll usually pull more args than were
199          * passed in, ultimately reading gibberish off the stack. */
200         va_start(args, num);
201         sysc->arg0 = va_arg(args, long);
202         sysc->arg1 = va_arg(args, long);
203         sysc->arg2 = va_arg(args, long);
204         sysc->arg3 = va_arg(args, long);
205         sysc->arg4 = va_arg(args, long);
206         sysc->arg5 = va_arg(args, long);
207         va_end(args);
208         __ros_arch_syscall((long)sysc, 1);
209 }