File:  [Qemu by Fabrice Bellard] / qemu / bsd-user / syscall.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:42:40 2018 UTC (3 years, 3 months ago) by root
Branches: qemu, MAIN
CVS tags: qemu0150, qemu0141, qemu0140, qemu0130, qemu0125, qemu0124, qemu0123, qemu0122, qemu0121, qemu0120, HEAD
qemu 0.12.0

    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 <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>
   32: #include <sys/param.h>
   33: #include <sys/sysctl.h>
   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: 
   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: 
   54: #define target_to_host_bitmask(x, tbl) (x)
   55: 
   56: static inline int is_error(abi_long ret)
   57: {
   58:     return (abi_ulong)ret >= (abi_ulong)(-4096);
   59: }
   60: 
   61: void target_set_brk(abi_ulong new_brk)
   62: {
   63:     target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
   64: }
   65: 
   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: 
  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,
  320:                             abi_long arg5, abi_long arg6, abi_long arg7,
  321:                             abi_long arg8)
  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:
  334: #ifdef TARGET_GPROF
  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;
  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;
  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;
  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;
  394:     case TARGET_FREEBSD_NR_syscall:
  395:     case TARGET_FREEBSD_NR___syscall:
  396:         ret = do_freebsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,arg7,arg8,0);
  397:         break;
  398:     default:
  399:         ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8));
  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:
  429: #ifdef TARGET_GPROF
  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:
  501: #ifdef TARGET_GPROF
  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: }

unix.superglobalmegacorp.com