qemu/bsd-user/freebsd/os-syscall.c
<<
>>
Prefs
   1/*
   2 *  BSD syscalls
   3 *
   4 *  Copyright (c) 2003-2008 Fabrice Bellard
   5 *  Copyright (c) 2013-2014 Stacey D. Son
   6 *
   7 *  This program is free software; you can redistribute it and/or modify
   8 *  it under the terms of the GNU General Public License as published by
   9 *  the Free Software Foundation; either version 2 of the License, or
  10 *  (at your option) any later version.
  11 *
  12 *  This program is distributed in the hope that it will be useful,
  13 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 *  GNU General Public License for more details.
  16 *
  17 *  You should have received a copy of the GNU General Public License
  18 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  19 */
  20
  21/*
  22 * We need the FreeBSD "legacy" definitions. Rust needs the FreeBSD 11 system
  23 * calls since it doesn't use libc at all, so we have to emulate that despite
  24 * FreeBSD 11 being EOL'd.
  25 */
  26#define _WANT_FREEBSD11_STAT
  27#define _WANT_FREEBSD11_STATFS
  28#define _WANT_FREEBSD11_DIRENT
  29#define _WANT_KERNEL_ERRNO
  30#define _WANT_SEMUN
  31#include "qemu/osdep.h"
  32#include "qemu/cutils.h"
  33#include "qemu/path.h"
  34#include <sys/syscall.h>
  35#include <sys/cdefs.h>
  36#include <sys/param.h>
  37#include <sys/mount.h>
  38#include <sys/sysctl.h>
  39#include <utime.h>
  40
  41#include "qemu.h"
  42#include "signal-common.h"
  43#include "user/syscall-trace.h"
  44
  45#include "bsd-file.h"
  46#include "bsd-proc.h"
  47
  48/* I/O */
  49safe_syscall3(int, open, const char *, path, int, flags, mode_t, mode);
  50safe_syscall4(int, openat, int, fd, const char *, path, int, flags, mode_t,
  51    mode);
  52
  53safe_syscall3(ssize_t, read, int, fd, void *, buf, size_t, nbytes);
  54safe_syscall4(ssize_t, pread, int, fd, void *, buf, size_t, nbytes, off_t,
  55    offset);
  56safe_syscall3(ssize_t, readv, int, fd, const struct iovec *, iov, int, iovcnt);
  57safe_syscall4(ssize_t, preadv, int, fd, const struct iovec *, iov, int, iovcnt,
  58    off_t, offset);
  59
  60safe_syscall3(ssize_t, write, int, fd, void *, buf, size_t, nbytes);
  61safe_syscall4(ssize_t, pwrite, int, fd, void *, buf, size_t, nbytes, off_t,
  62    offset);
  63safe_syscall3(ssize_t, writev, int, fd, const struct iovec *, iov, int, iovcnt);
  64safe_syscall4(ssize_t, pwritev, int, fd, const struct iovec *, iov, int, iovcnt,
  65    off_t, offset);
  66
  67void target_set_brk(abi_ulong new_brk)
  68{
  69}
  70
  71/*
  72 * errno conversion.
  73 */
  74abi_long get_errno(abi_long ret)
  75{
  76    if (ret == -1) {
  77        return -host_to_target_errno(errno);
  78    } else {
  79        return ret;
  80    }
  81}
  82
  83int host_to_target_errno(int err)
  84{
  85    /*
  86     * All the BSDs have the property that the error numbers are uniform across
  87     * all architectures for a given BSD, though they may vary between different
  88     * BSDs.
  89     */
  90    return err;
  91}
  92
  93bool is_error(abi_long ret)
  94{
  95    return (abi_ulong)ret >= (abi_ulong)(-4096);
  96}
  97
  98/*
  99 * Unlocks a iovec. Unlike unlock_iovec, it assumes the tvec array itself is
 100 * already locked from target_addr. It will be unlocked as well as all the iovec
 101 * elements.
 102 */
 103static void helper_unlock_iovec(struct target_iovec *target_vec,
 104                                abi_ulong target_addr, struct iovec *vec,
 105                                int count, int copy)
 106{
 107    for (int i = 0; i < count; i++) {
 108        abi_ulong base = tswapal(target_vec[i].iov_base);
 109
 110        if (vec[i].iov_base) {
 111            unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
 112        }
 113    }
 114    unlock_user(target_vec, target_addr, 0);
 115}
 116
 117struct iovec *lock_iovec(int type, abi_ulong target_addr,
 118        int count, int copy)
 119{
 120    struct target_iovec *target_vec;
 121    struct iovec *vec;
 122    abi_ulong total_len, max_len;
 123    int i;
 124    int err = 0;
 125
 126    if (count == 0) {
 127        errno = 0;
 128        return NULL;
 129    }
 130    if (count < 0 || count > IOV_MAX) {
 131        errno = EINVAL;
 132        return NULL;
 133    }
 134
 135    vec = g_try_new0(struct iovec, count);
 136    if (vec == NULL) {
 137        errno = ENOMEM;
 138        return NULL;
 139    }
 140
 141    target_vec = lock_user(VERIFY_READ, target_addr,
 142                           count * sizeof(struct target_iovec), 1);
 143    if (target_vec == NULL) {
 144        err = EFAULT;
 145        goto fail2;
 146    }
 147
 148    max_len = 0x7fffffff & MIN(TARGET_PAGE_MASK, PAGE_MASK);
 149    total_len = 0;
 150
 151    for (i = 0; i < count; i++) {
 152        abi_ulong base = tswapal(target_vec[i].iov_base);
 153        abi_long len = tswapal(target_vec[i].iov_len);
 154
 155        if (len < 0) {
 156            err = EINVAL;
 157            goto fail;
 158        } else if (len == 0) {
 159            /* Zero length pointer is ignored. */
 160            vec[i].iov_base = 0;
 161        } else {
 162            vec[i].iov_base = lock_user(type, base, len, copy);
 163            /*
 164             * If the first buffer pointer is bad, this is a fault.  But
 165             * subsequent bad buffers will result in a partial write; this is
 166             * realized by filling the vector with null pointers and zero
 167             * lengths.
 168             */
 169            if (!vec[i].iov_base) {
 170                if (i == 0) {
 171                    err = EFAULT;
 172                    goto fail;
 173                } else {
 174                    /*
 175                     * Fail all the subsequent addresses, they are already
 176                     * zero'd.
 177                     */
 178                    goto out;
 179                }
 180            }
 181            if (len > max_len - total_len) {
 182                len = max_len - total_len;
 183            }
 184        }
 185        vec[i].iov_len = len;
 186        total_len += len;
 187    }
 188out:
 189    unlock_user(target_vec, target_addr, 0);
 190    return vec;
 191
 192fail:
 193    helper_unlock_iovec(target_vec, target_addr, vec, i, copy);
 194fail2:
 195    g_free(vec);
 196    errno = err;
 197    return NULL;
 198}
 199
 200void unlock_iovec(struct iovec *vec, abi_ulong target_addr,
 201        int count, int copy)
 202{
 203    struct target_iovec *target_vec;
 204
 205    target_vec = lock_user(VERIFY_READ, target_addr,
 206                           count * sizeof(struct target_iovec), 1);
 207    if (target_vec) {
 208        helper_unlock_iovec(target_vec, target_addr, vec, count, copy);
 209    }
 210
 211    g_free(vec);
 212}
 213
 214/*
 215 * All errnos that freebsd_syscall() returns must be -TARGET_<errcode>.
 216 */
 217static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1,
 218                                abi_long arg2, abi_long arg3, abi_long arg4,
 219                                abi_long arg5, abi_long arg6, abi_long arg7,
 220                                abi_long arg8)
 221{
 222    abi_long ret;
 223
 224    switch (num) {
 225        /*
 226         * process system calls
 227         */
 228    case TARGET_FREEBSD_NR_exit: /* exit(2) */
 229        ret = do_bsd_exit(cpu_env, arg1);
 230        break;
 231
 232        /*
 233         * File system calls.
 234         */
 235    case TARGET_FREEBSD_NR_read: /* read(2) */
 236        ret = do_bsd_read(arg1, arg2, arg3);
 237        break;
 238
 239    case TARGET_FREEBSD_NR_pread: /* pread(2) */
 240        ret = do_bsd_pread(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
 241        break;
 242
 243    case TARGET_FREEBSD_NR_readv: /* readv(2) */
 244        ret = do_bsd_readv(arg1, arg2, arg3);
 245        break;
 246
 247    case TARGET_FREEBSD_NR_preadv: /* preadv(2) */
 248        ret = do_bsd_preadv(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
 249
 250    case TARGET_FREEBSD_NR_write: /* write(2) */
 251        ret = do_bsd_write(arg1, arg2, arg3);
 252        break;
 253
 254    case TARGET_FREEBSD_NR_pwrite: /* pwrite(2) */
 255        ret = do_bsd_pwrite(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
 256        break;
 257
 258    case TARGET_FREEBSD_NR_writev: /* writev(2) */
 259        ret = do_bsd_writev(arg1, arg2, arg3);
 260        break;
 261
 262    case TARGET_FREEBSD_NR_pwritev: /* pwritev(2) */
 263        ret = do_bsd_pwritev(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
 264        break;
 265
 266    case TARGET_FREEBSD_NR_open: /* open(2) */
 267        ret = do_bsd_open(arg1, arg2, arg3);
 268        break;
 269
 270    case TARGET_FREEBSD_NR_openat: /* openat(2) */
 271        ret = do_bsd_openat(arg1, arg2, arg3, arg4);
 272        break;
 273
 274    case TARGET_FREEBSD_NR_close: /* close(2) */
 275        ret = do_bsd_close(arg1);
 276        break;
 277
 278    case TARGET_FREEBSD_NR_fdatasync: /* fdatasync(2) */
 279        ret = do_bsd_fdatasync(arg1);
 280        break;
 281
 282    case TARGET_FREEBSD_NR_fsync: /* fsync(2) */
 283        ret = do_bsd_fsync(arg1);
 284        break;
 285
 286    case TARGET_FREEBSD_NR_freebsd12_closefrom: /* closefrom(2) */
 287        ret = do_bsd_closefrom(arg1);
 288        break;
 289
 290    case TARGET_FREEBSD_NR_revoke: /* revoke(2) */
 291        ret = do_bsd_revoke(arg1);
 292        break;
 293
 294    case TARGET_FREEBSD_NR_access: /* access(2) */
 295        ret = do_bsd_access(arg1, arg2);
 296        break;
 297
 298    case TARGET_FREEBSD_NR_eaccess: /* eaccess(2) */
 299        ret = do_bsd_eaccess(arg1, arg2);
 300        break;
 301
 302    case TARGET_FREEBSD_NR_faccessat: /* faccessat(2) */
 303        ret = do_bsd_faccessat(arg1, arg2, arg3, arg4);
 304        break;
 305
 306    case TARGET_FREEBSD_NR_chdir: /* chdir(2) */
 307        ret = do_bsd_chdir(arg1);
 308        break;
 309
 310    case TARGET_FREEBSD_NR_fchdir: /* fchdir(2) */
 311        ret = do_bsd_fchdir(arg1);
 312        break;
 313
 314    case TARGET_FREEBSD_NR_rename: /* rename(2) */
 315        ret = do_bsd_rename(arg1, arg2);
 316        break;
 317
 318    case TARGET_FREEBSD_NR_renameat: /* renameat(2) */
 319        ret = do_bsd_renameat(arg1, arg2, arg3, arg4);
 320        break;
 321
 322    case TARGET_FREEBSD_NR_link: /* link(2) */
 323        ret = do_bsd_link(arg1, arg2);
 324        break;
 325
 326    case TARGET_FREEBSD_NR_linkat: /* linkat(2) */
 327        ret = do_bsd_linkat(arg1, arg2, arg3, arg4, arg5);
 328        break;
 329
 330    case TARGET_FREEBSD_NR_unlink: /* unlink(2) */
 331        ret = do_bsd_unlink(arg1);
 332        break;
 333
 334    case TARGET_FREEBSD_NR_unlinkat: /* unlinkat(2) */
 335        ret = do_bsd_unlinkat(arg1, arg2, arg3);
 336        break;
 337
 338    case TARGET_FREEBSD_NR_mkdir: /* mkdir(2) */
 339        ret = do_bsd_mkdir(arg1, arg2);
 340        break;
 341
 342    case TARGET_FREEBSD_NR_mkdirat: /* mkdirat(2) */
 343        ret = do_bsd_mkdirat(arg1, arg2, arg3);
 344        break;
 345
 346    case TARGET_FREEBSD_NR_rmdir: /* rmdir(2) (XXX no rmdirat()?) */
 347        ret = do_bsd_rmdir(arg1);
 348        break;
 349
 350    case TARGET_FREEBSD_NR___getcwd: /* undocumented __getcwd() */
 351        ret = do_bsd___getcwd(arg1, arg2);
 352        break;
 353
 354    case TARGET_FREEBSD_NR_dup: /* dup(2) */
 355        ret = do_bsd_dup(arg1);
 356        break;
 357
 358    case TARGET_FREEBSD_NR_dup2: /* dup2(2) */
 359        ret = do_bsd_dup2(arg1, arg2);
 360        break;
 361
 362    case TARGET_FREEBSD_NR_truncate: /* truncate(2) */
 363        ret = do_bsd_truncate(cpu_env, arg1, arg2, arg3, arg4);
 364        break;
 365
 366    case TARGET_FREEBSD_NR_ftruncate: /* ftruncate(2) */
 367        ret = do_bsd_ftruncate(cpu_env, arg1, arg2, arg3, arg4);
 368        break;
 369
 370    case TARGET_FREEBSD_NR_acct: /* acct(2) */
 371        ret = do_bsd_acct(arg1);
 372        break;
 373
 374    case TARGET_FREEBSD_NR_sync: /* sync(2) */
 375        ret = do_bsd_sync();
 376        break;
 377
 378    case TARGET_FREEBSD_NR_mount: /* mount(2) */
 379        ret = do_bsd_mount(arg1, arg2, arg3, arg4);
 380        break;
 381
 382    case TARGET_FREEBSD_NR_unmount: /* unmount(2) */
 383        ret = do_bsd_unmount(arg1, arg2);
 384        break;
 385
 386    case TARGET_FREEBSD_NR_nmount: /* nmount(2) */
 387        ret = do_bsd_nmount(arg1, arg2, arg3);
 388        break;
 389
 390    case TARGET_FREEBSD_NR_symlink: /* symlink(2) */
 391        ret = do_bsd_symlink(arg1, arg2);
 392        break;
 393
 394    case TARGET_FREEBSD_NR_symlinkat: /* symlinkat(2) */
 395        ret = do_bsd_symlinkat(arg1, arg2, arg3);
 396        break;
 397
 398    case TARGET_FREEBSD_NR_readlink: /* readlink(2) */
 399        ret = do_bsd_readlink(cpu_env, arg1, arg2, arg3);
 400        break;
 401
 402    case TARGET_FREEBSD_NR_readlinkat: /* readlinkat(2) */
 403        ret = do_bsd_readlinkat(arg1, arg2, arg3, arg4);
 404        break;
 405
 406    case TARGET_FREEBSD_NR_chmod: /* chmod(2) */
 407        ret = do_bsd_chmod(arg1, arg2);
 408        break;
 409
 410    case TARGET_FREEBSD_NR_fchmod: /* fchmod(2) */
 411        ret = do_bsd_fchmod(arg1, arg2);
 412        break;
 413
 414    case TARGET_FREEBSD_NR_lchmod: /* lchmod(2) */
 415        ret = do_bsd_lchmod(arg1, arg2);
 416        break;
 417
 418    case TARGET_FREEBSD_NR_fchmodat: /* fchmodat(2) */
 419        ret = do_bsd_fchmodat(arg1, arg2, arg3, arg4);
 420        break;
 421
 422    case TARGET_FREEBSD_NR_freebsd11_mknod: /* mknod(2) */
 423        ret = do_bsd_freebsd11_mknod(arg1, arg2, arg3);
 424        break;
 425
 426    case TARGET_FREEBSD_NR_freebsd11_mknodat: /* mknodat(2) */
 427        ret = do_bsd_freebsd11_mknodat(arg1, arg2, arg3, arg4);
 428        break;
 429
 430    case TARGET_FREEBSD_NR_mknodat: /* mknodat(2) */
 431        ret = do_bsd_mknodat(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
 432        break;
 433
 434    case TARGET_FREEBSD_NR_chown: /* chown(2) */
 435        ret = do_bsd_chown(arg1, arg2, arg3);
 436        break;
 437
 438    case TARGET_FREEBSD_NR_fchown: /* fchown(2) */
 439        ret = do_bsd_fchown(arg1, arg2, arg3);
 440        break;
 441
 442    case TARGET_FREEBSD_NR_lchown: /* lchown(2) */
 443        ret = do_bsd_lchown(arg1, arg2, arg3);
 444        break;
 445
 446    case TARGET_FREEBSD_NR_fchownat: /* fchownat(2) */
 447        ret = do_bsd_fchownat(arg1, arg2, arg3, arg4, arg5);
 448        break;
 449
 450    case TARGET_FREEBSD_NR_chflags: /* chflags(2) */
 451        ret = do_bsd_chflags(arg1, arg2);
 452        break;
 453
 454    case TARGET_FREEBSD_NR_lchflags: /* lchflags(2) */
 455        ret = do_bsd_lchflags(arg1, arg2);
 456        break;
 457
 458    case TARGET_FREEBSD_NR_fchflags: /* fchflags(2) */
 459        ret = do_bsd_fchflags(arg1, arg2);
 460        break;
 461
 462    case TARGET_FREEBSD_NR_chroot: /* chroot(2) */
 463        ret = do_bsd_chroot(arg1);
 464        break;
 465
 466    case TARGET_FREEBSD_NR_flock: /* flock(2) */
 467        ret = do_bsd_flock(arg1, arg2);
 468        break;
 469
 470    case TARGET_FREEBSD_NR_mkfifo: /* mkfifo(2) */
 471        ret = do_bsd_mkfifo(arg1, arg2);
 472        break;
 473
 474    case TARGET_FREEBSD_NR_mkfifoat: /* mkfifoat(2) */
 475        ret = do_bsd_mkfifoat(arg1, arg2, arg3);
 476        break;
 477
 478    case TARGET_FREEBSD_NR_pathconf: /* pathconf(2) */
 479        ret = do_bsd_pathconf(arg1, arg2);
 480        break;
 481
 482    case TARGET_FREEBSD_NR_lpathconf: /* lpathconf(2) */
 483        ret = do_bsd_lpathconf(arg1, arg2);
 484        break;
 485
 486    case TARGET_FREEBSD_NR_fpathconf: /* fpathconf(2) */
 487        ret = do_bsd_fpathconf(arg1, arg2);
 488        break;
 489
 490    case TARGET_FREEBSD_NR_undelete: /* undelete(2) */
 491        ret = do_bsd_undelete(arg1);
 492        break;
 493
 494    default:
 495        qemu_log_mask(LOG_UNIMP, "Unsupported syscall: %d\n", num);
 496        ret = -TARGET_ENOSYS;
 497        break;
 498    }
 499
 500    return ret;
 501}
 502
 503/*
 504 * do_freebsd_syscall() should always have a single exit point at the end so
 505 * that actions, such as logging of syscall results, can be performed. This
 506 * as a wrapper around freebsd_syscall() so that actually happens. Since
 507 * that is a singleton, modern compilers will inline it anyway...
 508 */
 509abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
 510                            abi_long arg2, abi_long arg3, abi_long arg4,
 511                            abi_long arg5, abi_long arg6, abi_long arg7,
 512                            abi_long arg8)
 513{
 514    CPUState *cpu = env_cpu(cpu_env);
 515    int ret;
 516
 517    trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
 518    if (do_strace) {
 519        print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
 520    }
 521
 522    ret = freebsd_syscall(cpu_env, num, arg1, arg2, arg3, arg4, arg5, arg6,
 523                          arg7, arg8);
 524    if (do_strace) {
 525        print_freebsd_syscall_ret(num, ret);
 526    }
 527    trace_guest_user_syscall_ret(cpu, num, ret);
 528
 529    return ret;
 530}
 531
 532void syscall_init(void)
 533{
 534}
 535