These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / bsd-user / syscall.c
1 /*
2  *  BSD syscalls
3  *
4  *  Copyright (c) 2003 - 2008 Fabrice Bellard
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19 #include "qemu/osdep.h"
20 #include "qemu/cutils.h"
21 #include "qemu/path.h"
22 #include <sys/mman.h>
23 #include <sys/syscall.h>
24 #include <sys/param.h>
25 #include <sys/sysctl.h>
26 #include <utime.h>
27
28 #include "qemu.h"
29 #include "qemu-common.h"
30
31 //#define DEBUG
32
33 static abi_ulong target_brk;
34 static abi_ulong target_original_brk;
35
36 static inline abi_long get_errno(abi_long ret)
37 {
38     if (ret == -1)
39         /* XXX need to translate host -> target errnos here */
40         return -(errno);
41     else
42         return ret;
43 }
44
45 #define target_to_host_bitmask(x, tbl) (x)
46
47 static inline int is_error(abi_long ret)
48 {
49     return (abi_ulong)ret >= (abi_ulong)(-4096);
50 }
51
52 void target_set_brk(abi_ulong new_brk)
53 {
54     target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
55 }
56
57 /* do_obreak() must return target errnos. */
58 static abi_long do_obreak(abi_ulong new_brk)
59 {
60     abi_ulong brk_page;
61     abi_long mapped_addr;
62     int new_alloc_size;
63
64     if (!new_brk)
65         return 0;
66     if (new_brk < target_original_brk)
67         return -TARGET_EINVAL;
68
69     brk_page = HOST_PAGE_ALIGN(target_brk);
70
71     /* If the new brk is less than this, set it and we're done... */
72     if (new_brk < brk_page) {
73         target_brk = new_brk;
74         return 0;
75     }
76
77     /* We need to allocate more memory after the brk... */
78     new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1);
79     mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
80                                         PROT_READ|PROT_WRITE,
81                                         MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0));
82
83     if (!is_error(mapped_addr))
84         target_brk = new_brk;
85     else
86         return mapped_addr;
87
88     return 0;
89 }
90
91 #if defined(TARGET_I386)
92 static abi_long do_freebsd_sysarch(CPUX86State *env, int op, abi_ulong parms)
93 {
94     abi_long ret = 0;
95     abi_ulong val;
96     int idx;
97
98     switch(op) {
99 #ifdef TARGET_ABI32
100     case TARGET_FREEBSD_I386_SET_GSBASE:
101     case TARGET_FREEBSD_I386_SET_FSBASE:
102         if (op == TARGET_FREEBSD_I386_SET_GSBASE)
103 #else
104     case TARGET_FREEBSD_AMD64_SET_GSBASE:
105     case TARGET_FREEBSD_AMD64_SET_FSBASE:
106         if (op == TARGET_FREEBSD_AMD64_SET_GSBASE)
107 #endif
108             idx = R_GS;
109         else
110             idx = R_FS;
111         if (get_user(val, parms, abi_ulong))
112             return -TARGET_EFAULT;
113         cpu_x86_load_seg(env, idx, 0);
114         env->segs[idx].base = val;
115         break;
116 #ifdef TARGET_ABI32
117     case TARGET_FREEBSD_I386_GET_GSBASE:
118     case TARGET_FREEBSD_I386_GET_FSBASE:
119         if (op == TARGET_FREEBSD_I386_GET_GSBASE)
120 #else
121     case TARGET_FREEBSD_AMD64_GET_GSBASE:
122     case TARGET_FREEBSD_AMD64_GET_FSBASE:
123         if (op == TARGET_FREEBSD_AMD64_GET_GSBASE)
124 #endif
125             idx = R_GS;
126         else
127             idx = R_FS;
128         val = env->segs[idx].base;
129         if (put_user(val, parms, abi_ulong))
130             return -TARGET_EFAULT;
131         break;
132     /* XXX handle the others... */
133     default:
134         ret = -TARGET_EINVAL;
135         break;
136     }
137     return ret;
138 }
139 #endif
140
141 #ifdef TARGET_SPARC
142 static abi_long do_freebsd_sysarch(void *env, int op, abi_ulong parms)
143 {
144     /* XXX handle
145      * TARGET_FREEBSD_SPARC_UTRAP_INSTALL,
146      * TARGET_FREEBSD_SPARC_SIGTRAMP_INSTALL
147      */
148     return -TARGET_EINVAL;
149 }
150 #endif
151
152 #ifdef __FreeBSD__
153 /*
154  * XXX this uses the undocumented oidfmt interface to find the kind of
155  * a requested sysctl, see /sys/kern/kern_sysctl.c:sysctl_sysctl_oidfmt()
156  * (this is mostly copied from src/sbin/sysctl/sysctl.c)
157  */
158 static int
159 oidfmt(int *oid, int len, char *fmt, uint32_t *kind)
160 {
161     int qoid[CTL_MAXNAME+2];
162     uint8_t buf[BUFSIZ];
163     int i;
164     size_t j;
165
166     qoid[0] = 0;
167     qoid[1] = 4;
168     memcpy(qoid + 2, oid, len * sizeof(int));
169
170     j = sizeof(buf);
171     i = sysctl(qoid, len + 2, buf, &j, 0, 0);
172     if (i)
173         return i;
174
175     if (kind)
176         *kind = *(uint32_t *)buf;
177
178     if (fmt)
179         strcpy(fmt, (char *)(buf + sizeof(uint32_t)));
180     return (0);
181 }
182
183 /*
184  * try and convert sysctl return data for the target.
185  * XXX doesn't handle CTLTYPE_OPAQUE and CTLTYPE_STRUCT.
186  */
187 static int sysctl_oldcvt(void *holdp, size_t holdlen, uint32_t kind)
188 {
189     switch (kind & CTLTYPE) {
190     case CTLTYPE_INT:
191     case CTLTYPE_UINT:
192         *(uint32_t *)holdp = tswap32(*(uint32_t *)holdp);
193         break;
194 #ifdef TARGET_ABI32
195     case CTLTYPE_LONG:
196     case CTLTYPE_ULONG:
197         *(uint32_t *)holdp = tswap32(*(long *)holdp);
198         break;
199 #else
200     case CTLTYPE_LONG:
201         *(uint64_t *)holdp = tswap64(*(long *)holdp);
202     case CTLTYPE_ULONG:
203         *(uint64_t *)holdp = tswap64(*(unsigned long *)holdp);
204         break;
205 #endif
206 #ifdef CTLTYPE_U64
207     case CTLTYPE_S64:
208     case CTLTYPE_U64:
209 #else
210     case CTLTYPE_QUAD:
211 #endif
212         *(uint64_t *)holdp = tswap64(*(uint64_t *)holdp);
213         break;
214     case CTLTYPE_STRING:
215         break;
216     default:
217         /* XXX unhandled */
218         return -1;
219     }
220     return 0;
221 }
222
223 /* XXX this needs to be emulated on non-FreeBSD hosts... */
224 static abi_long do_freebsd_sysctl(abi_ulong namep, int32_t namelen, abi_ulong oldp,
225                           abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen)
226 {
227     abi_long ret;
228     void *hnamep, *holdp, *hnewp = NULL;
229     size_t holdlen;
230     abi_ulong oldlen = 0;
231     int32_t *snamep = g_malloc(sizeof(int32_t) * namelen), *p, *q, i;
232     uint32_t kind = 0;
233
234     if (oldlenp)
235         get_user_ual(oldlen, oldlenp);
236     if (!(hnamep = lock_user(VERIFY_READ, namep, namelen, 1)))
237         return -TARGET_EFAULT;
238     if (newp && !(hnewp = lock_user(VERIFY_READ, newp, newlen, 1)))
239         return -TARGET_EFAULT;
240     if (!(holdp = lock_user(VERIFY_WRITE, oldp, oldlen, 0)))
241         return -TARGET_EFAULT;
242     holdlen = oldlen;
243     for (p = hnamep, q = snamep, i = 0; i < namelen; p++, i++)
244        *q++ = tswap32(*p);
245     oidfmt(snamep, namelen, NULL, &kind);
246     /* XXX swap hnewp */
247     ret = get_errno(sysctl(snamep, namelen, holdp, &holdlen, hnewp, newlen));
248     if (!ret)
249         sysctl_oldcvt(holdp, holdlen, kind);
250     put_user_ual(holdlen, oldlenp);
251     unlock_user(hnamep, namep, 0);
252     unlock_user(holdp, oldp, holdlen);
253     if (hnewp)
254         unlock_user(hnewp, newp, 0);
255     g_free(snamep);
256     return ret;
257 }
258 #endif
259
260 /* FIXME
261  * lock_iovec()/unlock_iovec() have a return code of 0 for success where
262  * other lock functions have a return code of 0 for failure.
263  */
264 static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr,
265                            int count, int copy)
266 {
267     struct target_iovec *target_vec;
268     abi_ulong base;
269     int i;
270
271     target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
272     if (!target_vec)
273         return -TARGET_EFAULT;
274     for(i = 0;i < count; i++) {
275         base = tswapl(target_vec[i].iov_base);
276         vec[i].iov_len = tswapl(target_vec[i].iov_len);
277         if (vec[i].iov_len != 0) {
278             vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy);
279             /* Don't check lock_user return value. We must call writev even
280                if a element has invalid base address. */
281         } else {
282             /* zero length pointer is ignored */
283             vec[i].iov_base = NULL;
284         }
285     }
286     unlock_user (target_vec, target_addr, 0);
287     return 0;
288 }
289
290 static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
291                              int count, int copy)
292 {
293     struct target_iovec *target_vec;
294     abi_ulong base;
295     int i;
296
297     target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
298     if (!target_vec)
299         return -TARGET_EFAULT;
300     for(i = 0;i < count; i++) {
301         if (target_vec[i].iov_base) {
302             base = tswapl(target_vec[i].iov_base);
303             unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
304         }
305     }
306     unlock_user (target_vec, target_addr, 0);
307
308     return 0;
309 }
310
311 /* do_syscall() should always have a single exit point at the end so
312    that actions, such as logging of syscall results, can be performed.
313    All errnos that do_syscall() returns must be -TARGET_<errcode>. */
314 abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
315                             abi_long arg2, abi_long arg3, abi_long arg4,
316                             abi_long arg5, abi_long arg6, abi_long arg7,
317                             abi_long arg8)
318 {
319     abi_long ret;
320     void *p;
321
322 #ifdef DEBUG
323     gemu_log("freebsd syscall %d\n", num);
324 #endif
325     if(do_strace)
326         print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
327
328     switch(num) {
329     case TARGET_FREEBSD_NR_exit:
330 #ifdef TARGET_GPROF
331         _mcleanup();
332 #endif
333         gdb_exit(cpu_env, arg1);
334         /* XXX: should free thread stack and CPU env */
335         _exit(arg1);
336         ret = 0; /* avoid warning */
337         break;
338     case TARGET_FREEBSD_NR_read:
339         if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
340             goto efault;
341         ret = get_errno(read(arg1, p, arg3));
342         unlock_user(p, arg2, ret);
343         break;
344     case TARGET_FREEBSD_NR_write:
345         if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
346             goto efault;
347         ret = get_errno(write(arg1, p, arg3));
348         unlock_user(p, arg2, 0);
349         break;
350     case TARGET_FREEBSD_NR_writev:
351         {
352             int count = arg3;
353             struct iovec *vec;
354
355             vec = alloca(count * sizeof(struct iovec));
356             if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
357                 goto efault;
358             ret = get_errno(writev(arg1, vec, count));
359             unlock_iovec(vec, arg2, count, 0);
360         }
361         break;
362     case TARGET_FREEBSD_NR_open:
363         if (!(p = lock_user_string(arg1)))
364             goto efault;
365         ret = get_errno(open(path(p),
366                              target_to_host_bitmask(arg2, fcntl_flags_tbl),
367                              arg3));
368         unlock_user(p, arg1, 0);
369         break;
370     case TARGET_FREEBSD_NR_mmap:
371         ret = get_errno(target_mmap(arg1, arg2, arg3,
372                                     target_to_host_bitmask(arg4, mmap_flags_tbl),
373                                     arg5,
374                                     arg6));
375         break;
376     case TARGET_FREEBSD_NR_mprotect:
377         ret = get_errno(target_mprotect(arg1, arg2, arg3));
378         break;
379     case TARGET_FREEBSD_NR_break:
380         ret = do_obreak(arg1);
381         break;
382 #ifdef __FreeBSD__
383     case TARGET_FREEBSD_NR___sysctl:
384         ret = do_freebsd_sysctl(arg1, arg2, arg3, arg4, arg5, arg6);
385         break;
386 #endif
387     case TARGET_FREEBSD_NR_sysarch:
388         ret = do_freebsd_sysarch(cpu_env, arg1, arg2);
389         break;
390     case TARGET_FREEBSD_NR_syscall:
391     case TARGET_FREEBSD_NR___syscall:
392         ret = do_freebsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,arg7,arg8,0);
393         break;
394     default:
395         ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8));
396         break;
397     }
398  fail:
399 #ifdef DEBUG
400     gemu_log(" = %ld\n", ret);
401 #endif
402     if (do_strace)
403         print_freebsd_syscall_ret(num, ret);
404     return ret;
405  efault:
406     ret = -TARGET_EFAULT;
407     goto fail;
408 }
409
410 abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
411                            abi_long arg2, abi_long arg3, abi_long arg4,
412                            abi_long arg5, abi_long arg6)
413 {
414     abi_long ret;
415     void *p;
416
417 #ifdef DEBUG
418     gemu_log("netbsd syscall %d\n", num);
419 #endif
420     if(do_strace)
421         print_netbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
422
423     switch(num) {
424     case TARGET_NETBSD_NR_exit:
425 #ifdef TARGET_GPROF
426         _mcleanup();
427 #endif
428         gdb_exit(cpu_env, arg1);
429         /* XXX: should free thread stack and CPU env */
430         _exit(arg1);
431         ret = 0; /* avoid warning */
432         break;
433     case TARGET_NETBSD_NR_read:
434         if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
435             goto efault;
436         ret = get_errno(read(arg1, p, arg3));
437         unlock_user(p, arg2, ret);
438         break;
439     case TARGET_NETBSD_NR_write:
440         if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
441             goto efault;
442         ret = get_errno(write(arg1, p, arg3));
443         unlock_user(p, arg2, 0);
444         break;
445     case TARGET_NETBSD_NR_open:
446         if (!(p = lock_user_string(arg1)))
447             goto efault;
448         ret = get_errno(open(path(p),
449                              target_to_host_bitmask(arg2, fcntl_flags_tbl),
450                              arg3));
451         unlock_user(p, arg1, 0);
452         break;
453     case TARGET_NETBSD_NR_mmap:
454         ret = get_errno(target_mmap(arg1, arg2, arg3,
455                                     target_to_host_bitmask(arg4, mmap_flags_tbl),
456                                     arg5,
457                                     arg6));
458         break;
459     case TARGET_NETBSD_NR_mprotect:
460         ret = get_errno(target_mprotect(arg1, arg2, arg3));
461         break;
462     case TARGET_NETBSD_NR_syscall:
463     case TARGET_NETBSD_NR___syscall:
464         ret = do_netbsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0);
465         break;
466     default:
467         ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
468         break;
469     }
470  fail:
471 #ifdef DEBUG
472     gemu_log(" = %ld\n", ret);
473 #endif
474     if (do_strace)
475         print_netbsd_syscall_ret(num, ret);
476     return ret;
477  efault:
478     ret = -TARGET_EFAULT;
479     goto fail;
480 }
481
482 abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
483                             abi_long arg2, abi_long arg3, abi_long arg4,
484                             abi_long arg5, abi_long arg6)
485 {
486     abi_long ret;
487     void *p;
488
489 #ifdef DEBUG
490     gemu_log("openbsd syscall %d\n", num);
491 #endif
492     if(do_strace)
493         print_openbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
494
495     switch(num) {
496     case TARGET_OPENBSD_NR_exit:
497 #ifdef TARGET_GPROF
498         _mcleanup();
499 #endif
500         gdb_exit(cpu_env, arg1);
501         /* XXX: should free thread stack and CPU env */
502         _exit(arg1);
503         ret = 0; /* avoid warning */
504         break;
505     case TARGET_OPENBSD_NR_read:
506         if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
507             goto efault;
508         ret = get_errno(read(arg1, p, arg3));
509         unlock_user(p, arg2, ret);
510         break;
511     case TARGET_OPENBSD_NR_write:
512         if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
513             goto efault;
514         ret = get_errno(write(arg1, p, arg3));
515         unlock_user(p, arg2, 0);
516         break;
517     case TARGET_OPENBSD_NR_open:
518         if (!(p = lock_user_string(arg1)))
519             goto efault;
520         ret = get_errno(open(path(p),
521                              target_to_host_bitmask(arg2, fcntl_flags_tbl),
522                              arg3));
523         unlock_user(p, arg1, 0);
524         break;
525     case TARGET_OPENBSD_NR_mmap:
526         ret = get_errno(target_mmap(arg1, arg2, arg3,
527                                     target_to_host_bitmask(arg4, mmap_flags_tbl),
528                                     arg5,
529                                     arg6));
530         break;
531     case TARGET_OPENBSD_NR_mprotect:
532         ret = get_errno(target_mprotect(arg1, arg2, arg3));
533         break;
534     case TARGET_OPENBSD_NR_syscall:
535     case TARGET_OPENBSD_NR___syscall:
536         ret = do_openbsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0);
537         break;
538     default:
539         ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
540         break;
541     }
542  fail:
543 #ifdef DEBUG
544     gemu_log(" = %ld\n", ret);
545 #endif
546     if (do_strace)
547         print_openbsd_syscall_ret(num, ret);
548     return ret;
549  efault:
550     ret = -TARGET_EFAULT;
551     goto fail;
552 }
553
554 void syscall_init(void)
555 {
556 }