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