Stop using snprintf in write_hex_to_fd (XCC)
[akaros.git] / tools / compilers / gcc-glibc / glibc-2.19-akaros / sysdeps / akaros / syscall.c
1 /* Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, write to the Free
16    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17    02111-1307 USA.  */
18
19 #include <sysdep.h>
20 #include <errno.h>
21 #include <unistd.h>
22 #include <stdarg.h>
23 #include <sys/syscall.h>
24 #include <parlib/arch/atomic.h>
25 #include <ros/procdata.h>
26
27 /* This is a simple ev_q that routes notifs to vcore0's public mbox.  This
28  * should work for any bit messages, even if the process hasn't done any set up
29  * yet, since the memory for the mbox is allocted by the kernel (procdata).
30  * Don't send full messages to it, since the UCQ won't be initialized. */
31 struct event_mbox __simple_evbitmap = { .type = EV_MBOX_BITMAP, };
32 struct event_queue __ros_scp_simple_evq =
33                   { .ev_mbox = &__simple_evbitmap,
34                     .ev_flags = EVENT_WAKEUP,
35                     .ev_alert_pending = FALSE,
36                     .ev_vcore = 0,
37                     .ev_handler = 0 };
38
39 /* Helper, from u/p/event.c.  Keep it in sync.  (don't want to move this into
40  * glibc yet). */
41 static bool register_evq(struct syscall *sysc, struct event_queue *ev_q)
42 {
43         int old_flags;
44         sysc->ev_q = ev_q;
45         wrmb(); /* don't let that write pass any future reads (flags) */
46         /* Try and set the SC_UEVENT flag (so the kernel knows to look at ev_q) */
47         do {
48                 /* no cmb() needed, the atomic_read will reread flags */
49                 old_flags = atomic_read(&sysc->flags);
50                 /* Spin if the kernel is mucking with syscall flags */
51                 while (old_flags & SC_K_LOCK)
52                         old_flags = atomic_read(&sysc->flags);
53                 /* If the kernel finishes while we are trying to sign up for an event,
54                  * we need to bail out */
55                 if (old_flags & (SC_DONE | SC_PROGRESS)) {
56                         sysc->ev_q = 0;         /* not necessary, but might help with bugs */
57                         return FALSE;
58                 }
59         } while (!atomic_cas(&sysc->flags, old_flags, old_flags | SC_UEVENT));
60         return TRUE;
61 }
62
63 /* Glibc initial blockon, usable before parlib code can init things (or if it
64  * never can, like for RTLD).  As processes initialize further, they will use
65  * different functions.
66  *
67  * In essence, we're in vcore context already.  For one, this function could be
68  * called from a full SCP in vcore context.  For early processes, we are not
69  * vcctx_ready.  Either way, we don't need to worry about the kernel forcing us
70  * into vcore context and otherwise clearing notif_pending.  For those curious,
71  * the old race was that the kernel sets notif pending after we register, then
72  * we drop into VC ctx, clear notif pending, and yield. */
73 void __ros_early_syscall_blockon(struct syscall *sysc)
74 {
75         /* For early SCPs, notif_pending will probably be false anyways.  For SCPs
76          * in VC ctx, it might be set.  Regardless, when we pop back up,
77          * notif_pending will be set (for a full SCP in VC ctx). */
78         __procdata.vcore_preempt_data[0].notif_pending = FALSE;
79         /* order register after clearing notif_pending, handled by register_evq */
80         /* Ask for a SYSCALL event when the sysc is done.  We don't need a handler,
81          * we just need the kernel to restart us from proc_yield.  If register
82          * fails, we're already done. */
83         if (register_evq(sysc, &__ros_scp_simple_evq)) {
84                 /* Sending false for now - we want to signal proc code that we want to
85                  * wait (piggybacking on the MCP meaning of this variable).  If
86                  * notif_pending is set, the kernel will immediately return us. */
87                 __ros_syscall_noerrno(SYS_yield, FALSE, 0, 0, 0, 0, 0);
88         }
89         /* For early SCPs, the kernel turns off notif_pending for us.  For SCPs in
90          * vcore context that blocked (should be rare!), it'll still be set.  Other
91          * VC ctx code must handle it later. (could have coalesced notifs) */
92 }
93
94 /* Function pointer for the blockon function.  MCPs need to switch to the parlib
95  * blockon before becoming an MCP.  Default is the glibc SCP handler */
96 void (*ros_syscall_blockon)(struct syscall *sysc) = __ros_early_syscall_blockon;
97
98 /* Issue a single syscall and block into the 2LS until it completes */
99 static inline void __ros_syscall_sync(struct syscall *sysc)
100 {
101         /* There is only one syscall in the syscall array when we want to do it
102         * synchronously */
103         __ros_arch_syscall((long)sysc, 1);
104         /* Don't proceed til we are done */
105         while (!(atomic_read(&sysc->flags) & SC_DONE))
106                 ros_syscall_blockon(sysc);
107         /* Need to wait til it is unlocked.  It's not really done until SC_DONE &
108          * !SC_K_LOCK. */
109         while (atomic_read(&sysc->flags) & SC_K_LOCK)
110                 cpu_relax();
111 }
112 void ros_syscall_sync(struct syscall *sysc) {
113         __ros_syscall_sync(sysc);
114 }
115 libc_hidden_def(ros_syscall_sync)
116
117 /* TODO: make variants of __ros_syscall() based on the number of args (0 - 6) */
118 /* These are simple synchronous system calls, built on top of the kernel's async
119  * interface.  This version makes no assumptions about errno.  You usually don't
120  * want this. */
121 static inline struct syscall
122 __ros_syscall_inline(unsigned int _num, long _a0, long _a1, long _a2, long _a3,
123                      long _a4, long _a5)
124 {
125         struct syscall sysc = {0};
126         sysc.num = _num;
127         sysc.ev_q = 0;
128         sysc.arg0 = _a0;
129         sysc.arg1 = _a1;
130         sysc.arg2 = _a2;
131         sysc.arg3 = _a3;
132         sysc.arg4 = _a4;
133         sysc.arg5 = _a5;
134     __ros_syscall_sync(&sysc);
135         return sysc;
136 }
137
138 long __ros_syscall_noerrno(unsigned int _num, long _a0, long _a1, long _a2,
139                            long _a3, long _a4, long _a5)
140 {
141         struct syscall sysc = __ros_syscall_inline(_num, _a0, _a1, _a2, _a3,
142                                                    _a4, _a5);
143         return sysc.retval;
144 }
145 libc_hidden_def(__ros_syscall_noerrno)
146
147 /* This version knows about errno and will handle it. */
148 long __ros_syscall_errno(unsigned int _num, long _a0, long _a1, long _a2,
149                          long _a3, long _a4, long _a5)
150 {
151         struct syscall sysc = __ros_syscall_inline(_num, _a0, _a1, _a2, _a3,
152                                                    _a4, _a5);
153         if (__builtin_expect(sysc.err, 0)) {
154                 errno = sysc.err;
155                 memcpy(errstr(), sysc.errstr, MAX_ERRSTR_LEN);
156         }
157         return sysc.retval;
158 }
159 libc_hidden_def(__ros_syscall_errno)
160
161 long int syscall(long int num, ...)
162 {
163         va_list vl;
164         va_start(vl, num);
165         long int a0 = va_arg(vl, long int);
166         long int a1 = va_arg(vl, long int);
167         long int a2 = va_arg(vl, long int);
168         long int a3 = va_arg(vl, long int);
169         long int a4 = va_arg(vl, long int);
170         long int a5 = va_arg(vl, long int);
171         va_end(vl);
172         
173         return ros_syscall(num, a0, a1, a2, a3, a4, a5);
174 }
175