Patchwork [11/23] bsd-user: add shims for file related system calls

login
register
mail settings
Submitter Stacey Son
Date June 24, 2013, 2:03 a.m.
Message ID <1372039435-41921-12-git-send-email-sson@FreeBSD.org>
Download mbox | patch
Permalink /patch/253914/
State New
Headers show

Comments

Stacey Son - June 24, 2013, 2:03 a.m.
This changes adds support for file and file system related system calls that
are largely BSD OS independent. Also includes some more clean up of syscall.c.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/bsd-file.h                    | 1095 ++++++++++++++++++++++++++++++++
 bsd-user/i386/target_arch_vmparam.h    |    5 +
 bsd-user/mips/target_arch_vmparam.h    |    5 +
 bsd-user/mips64/target_arch_vmparam.h  |    5 +
 bsd-user/qemu.h                        |   36 +
 bsd-user/sparc/target_arch_vmparam.h   |    5 +
 bsd-user/sparc64/target_arch_vmparam.h |    5 +
 bsd-user/syscall.c                     |  384 +++++++++---
 bsd-user/x86_64/target_arch_vmparam.h  |    5 +
 9 files changed, 1467 insertions(+), 78 deletions(-)
 create mode 100644 bsd-user/bsd-file.h

Patch

diff --git a/bsd-user/bsd-file.h b/bsd-user/bsd-file.h
new file mode 100644
index 0000000..f2c0fc7
--- /dev/null
+++ b/bsd-user/bsd-file.h
@@ -0,0 +1,1095 @@ 
+/*
+ *  file related system call shims and definitions
+ *
+ *  Copyright (c) 2013 Stacey D. Son
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __BSD_FILE_H_
+#define __BSD_FILE_H_
+
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <sys/uio.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define target_to_host_bitmask(x, tbl) (x)
+
+#define LOCK_PATH(p, arg)  do {             \
+    (p) =  lock_user_string(arg);           \
+    if ((p) == NULL) {                      \
+        return -TARGET_EFAULT;              \
+    }                                       \
+} while (0)
+
+#define UNLOCK_PATH(p, arg)   unlock_user((p), (arg), 0)
+
+struct target_pollfd {
+    int32_t fd;         /* file descriptor */
+    int16_t events;     /* requested events */
+    int16_t revents;    /* returned events */
+};
+
+static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr,
+        int count, int copy);
+static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
+        int count, int copy);
+extern int __getcwd(char *path, size_t len);
+
+/* read(2) */
+static inline abi_long do_bsd_read(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(read(arg1, p, arg3));
+    unlock_user(p, arg2, ret);
+
+    return ret;
+}
+
+/* pread(2) */
+static inline abi_long do_bsd_pread(abi_long arg1, abi_long arg2, abi_long arg3,
+        abi_long arg4, abi_long arg5)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user(VERIFY_WRITE, arg2, arg3, 0);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(pread(arg1, p, arg3, target_offset64(arg4, arg5)));
+    unlock_user(p, arg2, ret);
+
+    return ret;
+}
+
+/* readv(2) */
+static inline abi_long do_bsd_readv(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    int count = arg3;
+    struct iovec *vec;
+
+    vec = alloca(count * sizeof(struct iovec));
+    if (vec == NULL) {
+        return -TARGET_ENOMEM;
+    }
+    if (lock_iovec(VERIFY_WRITE, vec, arg2, count, 0) < 0) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(readv(arg1, vec, count));
+    unlock_iovec(vec, arg2, count, 1);
+
+    return ret;
+}
+
+/* write(2) */
+static inline abi_long do_bsd_write(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user(VERIFY_READ, arg2, arg3, 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(write(arg1, p, arg3));
+    unlock_user(p, arg2, 0);
+
+    return ret;
+}
+
+/* pwrite(2) */
+static inline abi_long do_bsd_pwrite(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user(VERIFY_READ, arg2, arg3, 1);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(pwrite(arg1, p, arg3, target_offset64(arg4, arg5)));
+    unlock_user(p, arg2, 0);
+
+    return ret;
+}
+
+/* writev(2) */
+static inline abi_long do_bsd_writev(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    int count = arg3;
+    struct iovec *vec;
+
+    vec = alloca(count * sizeof(struct iovec));
+    if (vec == NULL) {
+        return -TARGET_ENOMEM;
+    }
+    if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(writev(arg1, vec, count));
+    unlock_iovec(vec, arg2, count, 0);
+
+    return ret;
+}
+
+/* pwritev(2) */
+static inline abi_long do_bsd_pwritev(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    abi_long ret;
+    int count = arg3;
+    struct iovec *vec;
+
+    vec = alloca(count * sizeof(struct iovec));
+    if (vec == NULL) {
+        return -TARGET_ENOMEM;
+    }
+    if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(pwritev(arg1, vec, count, target_offset64(arg4, arg5)));
+    unlock_iovec(vec, arg2, count, 0);
+
+    return ret;
+}
+
+/* open(2) */
+static inline abi_long do_bsd_open(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(open(path(p), target_to_host_bitmask(arg2, fcntl_flags_tbl),
+                arg3));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* openat(2) */
+static inline abi_long do_bsd_openat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(openat(arg1, path(p),
+                target_to_host_bitmask(arg3, fcntl_flags_tbl), arg4));
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+/* close(2) */
+static inline abi_long do_bsd_close(abi_long arg1)
+{
+
+    return get_errno(close(arg1));
+}
+
+/* closefrom(2) */
+static inline abi_long do_bsd_closefrom(abi_long arg1)
+{
+
+    closefrom(arg1);  /* returns void */
+    return get_errno(0);
+}
+
+/* revoke(2) */
+static inline abi_long do_bsd_revoke(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(revoke(p)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* creat(2) (obsolete) */
+static inline abi_long do_bsd_creat(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(open(path(p), O_CREAT | O_TRUNC | O_WRONLY, arg2));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+
+/* access(2) */
+static inline abi_long do_bsd_access(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(access(path(p), arg2));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* eaccess(2) */
+static inline abi_long do_bsd_eaccess(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(eaccess(path(p), arg2));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* faccessat(2) */
+static inline abi_long do_bsd_faccessat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(faccessat(arg1, p, arg3, arg4)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+/* chdir(2) */
+static inline abi_long do_bsd_chdir(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(chdir(p)); /* XXX  path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* fchdir(2) */
+static inline abi_long do_bsd_fchdir(abi_long arg1)
+{
+
+    return get_errno(fchdir(arg1));
+}
+
+/* rename(2) */
+static inline abi_long do_bsd_rename(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg1);
+    LOCK_PATH(p2, arg2);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(rename(p1, p2)); /* XXX path(p1), path(p2) */
+    }
+    UNLOCK_PATH(p2, arg2);
+    UNLOCK_PATH(p1, arg1);
+
+    return ret;
+}
+
+/* renameat(2) */
+static inline abi_long do_bsd_renameat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg1);
+    LOCK_PATH(p2, arg2);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(renameat(arg1, p1, arg3, p2));
+    }
+    UNLOCK_PATH(p2, arg2);
+    UNLOCK_PATH(p1, arg1);
+
+    return ret;
+}
+
+/* link(2) */
+static inline abi_long do_bsd_link(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg1);
+    LOCK_PATH(p2, arg2);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(link(p1, p2)); /* XXX path(p1), path(p2) */
+    }
+    UNLOCK_PATH(p2, arg2);
+    UNLOCK_PATH(p1, arg1);
+
+    return ret;
+}
+
+/* linkat(2) */
+static inline abi_long do_bsd_linkat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg2);
+    LOCK_PATH(p2, arg4);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(linkat(arg1, p1, arg3, p2, arg5));
+    }
+    UNLOCK_PATH(p2, arg4);
+    UNLOCK_PATH(p1, arg2);
+
+    return ret;
+}
+
+/* unlink(2) */
+static inline abi_long do_bsd_unlink(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(unlink(p)); /* XXX path(p) */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* unlinkat(2) */
+static inline abi_long do_bsd_unlinkat(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(unlinkat(arg1, p, arg3)); /* XXX path(p) */
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+/* mkdir(2) */
+static inline abi_long do_bsd_mkdir(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(mkdir(p, arg2)); /* XXX path(p) */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+
+/* mkdirat(2) */
+static inline abi_long do_bsd_mkdirat(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(mkdirat(arg1, p, arg3));
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+
+/* rmdir(2) */
+static inline abi_long do_bsd_rmdir(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(rmdir(p)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* undocumented __getcwd(char *buf, size_t len)  system call */
+static inline abi_long do_bsd___getcwd(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    p = lock_user(VERIFY_WRITE, arg1, arg2, 0);
+    if (p == NULL) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(__getcwd(p, arg2));
+    unlock_user(p, arg1, ret);
+
+    return ret;
+}
+
+/* dup(2) */
+static inline abi_long do_bsd_dup(abi_long arg1)
+{
+
+    return get_errno(dup(arg1));
+}
+
+/* dup2(2) */
+static inline abi_long do_bsd_dup2(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(dup2(arg1, arg2));
+}
+
+/* truncate(2) */
+static inline abi_long do_bsd_truncate(void *cpu_env, abi_long arg1,
+        abi_long arg2, abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    if (regpairs_aligned(cpu_env) != 0) {
+        arg2 = arg3;
+        arg3 = arg4;
+    }
+    ret = get_errno(truncate(p, target_offset64(arg2, arg3)));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* ftruncate(2) */
+static inline abi_long do_bsd_ftruncate(void *cpu_env, abi_long arg1,
+        abi_long arg2, abi_long arg3, abi_long arg4)
+{
+
+    if (regpairs_aligned(cpu_env)) {
+        arg2 = arg3;
+        arg3 = arg4;
+    }
+    return get_errno(ftruncate(arg1, target_offset64(arg2, arg3)));
+}
+
+/* acct(2) */
+static inline abi_long do_bsd_acct(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    if (arg1 == 0) {
+        ret = get_errno(acct(NULL));
+    } else {
+        LOCK_PATH(p, arg1);
+        ret = get_errno(acct(path(p)));
+        UNLOCK_PATH(p, arg1);
+    }
+    return ret;
+}
+
+/* sync(2) */
+static inline abi_long do_bsd_sync(void)
+{
+
+    sync();
+    return 0;
+}
+
+/* mount(2) */
+static inline abi_long do_bsd_mount(abi_long arg1, abi_long arg2, abi_long arg3,
+        abi_long arg4)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg1);
+    LOCK_PATH(p2, arg2);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        /*
+         * XXX arg4 should be locked, but it isn't clear how to do that
+         * since it's it may be not be a NULL-terminated string.
+         */
+        if (arg4 == 0) {
+            ret = get_errno(mount(p1, p2, arg3, NULL)); /* XXX path(p2)? */
+        } else {
+            ret = get_errno(mount(p1, p2, arg3, g2h(arg4))); /* XXX path(p2)? */
+        }
+    }
+    UNLOCK_PATH(p2, arg2);
+    UNLOCK_PATH(p1, arg1);
+
+    return ret;
+}
+
+/* unmount(2) */
+static inline abi_long do_bsd_unmount(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(unmount(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* nmount(2) */
+static inline abi_long do_bsd_nmount(abi_long arg1, abi_long count,
+        abi_long flags)
+{
+    abi_long ret;
+    struct iovec *vec;
+
+    vec = alloca(count * sizeof(struct iovec));
+    if (lock_iovec(VERIFY_READ, vec, arg1, count, 1) < 0) {
+        return -TARGET_EFAULT;
+    }
+    ret = get_errno(nmount(vec, count, flags));
+    unlock_iovec(vec, arg1, count, 0);
+
+    return ret;
+}
+
+/* symlink(2) */
+static inline abi_long do_bsd_symlink(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg1);
+    LOCK_PATH(p2, arg2);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(symlink(p1, p2)); /* XXX path(p1), path(p2) */
+    }
+    UNLOCK_PATH(p2, arg2);
+    UNLOCK_PATH(p1, arg1);
+
+    return ret;
+}
+
+/* symlinkat(2) */
+static inline abi_long do_bsd_symlinkat(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg1);
+    LOCK_PATH(p2, arg3);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(symlinkat(p1, arg2, p2)); /* XXX path(p1), path(p2) */
+    }
+    UNLOCK_PATH(p2, arg3);
+    UNLOCK_PATH(p1, arg1);
+
+    return ret;
+}
+
+/* readlink(2) */
+static inline abi_long do_bsd_readlink(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg1);
+    p2 = lock_user(VERIFY_WRITE, arg2, arg3, 0);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(readlink(path(p1), p2, arg3));
+    }
+    unlock_user(p2, arg2, ret);
+    UNLOCK_PATH(p1, arg1);
+
+    return ret;
+}
+
+/* readlinkat(2) */
+static inline abi_long do_bsd_readlinkat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p1, *p2;
+
+    LOCK_PATH(p1, arg2);
+    p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
+    if (!p1 || !p2) {
+        ret = -TARGET_EFAULT;
+    } else {
+        ret = get_errno(readlinkat(arg1, p1, p2, arg4));
+    }
+    unlock_user(p2, arg3, ret);
+    UNLOCK_PATH(p1, arg2);
+
+    return ret;
+}
+
+/* chmod(2) */
+static inline abi_long do_bsd_chmod(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(chmod(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* fchmod(2) */
+static inline abi_long do_bsd_fchmod(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(fchmod(arg1, arg2));
+}
+
+/* lchmod(2) */
+static inline abi_long do_bsd_lchmod(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(lchmod(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* fchmodat(2) */
+static inline abi_long do_bsd_fchmodat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(fchmodat(arg1, p, arg3, arg4));
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+/* mknod(2) */
+static inline abi_long do_bsd_mknod(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(mknod(p, arg2, arg3)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* mknodat(2) */
+static inline abi_long do_bsd_mknodat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(mknodat(arg1, p, arg3, arg4));
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+/* chown(2) */
+static inline abi_long do_bsd_chown(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(chown(p, arg2, arg3)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* fchown(2) */
+static inline abi_long do_bsd_fchown(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    return get_errno(fchown(arg1, arg2, arg3));
+}
+
+/* lchown(2) */
+static inline abi_long do_bsd_lchown(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(lchown(p, arg2, arg3)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* fchownat(2) */
+static inline abi_long do_bsd_fchownat(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(fchownat(arg1, p, arg3, arg4, arg5)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+/* chflags(2) */
+static inline abi_long do_bsd_chflags(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(chflags(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* lchflags(2) */
+static inline abi_long do_bsd_lchflags(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(lchflags(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* fchflags(2) */
+static inline abi_long do_bsd_fchflags(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(fchflags(arg1, arg2));
+}
+
+/* chroot(2) */
+static inline abi_long do_bsd_chroot(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(chroot(p)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* flock(2) */
+static abi_long do_bsd_flock(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(flock(arg1, arg2));
+}
+
+/* mkfifo(2) */
+static inline abi_long do_bsd_mkfifo(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(mkfifo(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* mkfifoat(2) */
+static inline abi_long do_bsd_mkfifoat(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg2);
+    ret = get_errno(mkfifoat(arg1, p, arg3));
+    UNLOCK_PATH(p, arg2);
+
+    return ret;
+}
+
+/* pathconf(2) */
+static inline abi_long do_bsd_pathconf(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(pathconf(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* lpathconf(2) */
+static inline abi_long do_bsd_lpathconf(abi_long arg1, abi_long arg2)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(lpathconf(p, arg2)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* fpathconf(2) */
+static inline abi_long do_bsd_fpathconf(abi_long arg1, abi_long arg2)
+{
+
+    return get_errno(fpathconf(arg1, arg2));
+}
+
+/* undelete(2) */
+static inline abi_long do_bsd_undelete(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(undelete(p)); /* XXX path(p)? */
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* poll(2) */
+static abi_long do_bsd_poll(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+    abi_long ret;
+    nfds_t i, nfds = arg2;
+    int timeout = arg3;
+    struct pollfd *pfd;
+    struct target_pollfd *target_pfd;
+
+    target_pfd = lock_user(VERIFY_WRITE, arg1,
+            sizeof(struct target_pollfd) * nfds, 1);
+    if (!target_pfd) {
+        return -TARGET_EFAULT;
+    }
+    pfd = alloca(sizeof(struct pollfd) * nfds);
+    for (i = 0; i < nfds; i++) {
+        pfd[i].fd = tswap32(target_pfd[i].fd);
+        pfd[i].events = tswap16(target_pfd[i].events);
+    } ret = get_errno(poll(pfd, nfds, timeout));
+    if (!is_error(ret)) {
+        for (i = 0; i < nfds; i++) {
+            target_pfd[i].revents = tswap16(pfd[i].revents);
+        }
+    }
+    unlock_user(target_pfd, arg1, sizeof(struct target_pollfd) * nfds);
+
+    return ret;
+}
+
+/*
+ * undocumented openbsd_poll(struct pollfd *fds, u_int nfds, int
+ * timeout) system call.
+ */
+static abi_long do_bsd_openbsd_poll(abi_long arg1, abi_long arg2, abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall openbsd_poll()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* lseek(2) */
+static abi_long do_bsd_lseek(void *cpu_env, abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+    abi_long ret;
+
+#if TARGET_ABI_BITS == 32
+    /* 32-bit arch's use two 32 registers for 64 bit return value */
+    int64_t res = lseek(arg1, target_offset64(arg2, arg3), arg4);
+
+    if (res == -1) {
+        ret = get_errno(res);
+    } else {
+        ret = res & 0xFFFFFFFF;
+        set_second_rval(cpu_env, (res >> 32) & 0xFFFFFFFF);
+    }
+#else
+    ret = get_errno(lseek(arg1, arg2, arg3));
+#endif
+    return ret;
+}
+
+/* pipe(2) */
+static abi_long do_bsd_pipe(void *cpu_env, abi_long arg1)
+{
+    abi_long ret;
+    int host_pipe[2];
+    int host_ret = pipe(host_pipe);
+
+    if (host_ret != -1) {
+        set_second_rval(cpu_env, host_pipe[1]);
+        ret = host_pipe[0];
+    } else {
+        ret = get_errno(host_ret);
+    }
+    return ret;
+}
+
+/* swapon(2) */
+static abi_long do_bsd_swapon(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(swapon(path(p)));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/* swapoff(2) */
+static abi_long do_bsd_swapoff(abi_long arg1)
+{
+    abi_long ret;
+    void *p;
+
+    LOCK_PATH(p, arg1);
+    ret = get_errno(swapoff(path(p)));
+    UNLOCK_PATH(p, arg1);
+
+    return ret;
+}
+
+/*
+ * undocumented freebsd6_pread(int fd, void *buf, size_t nbyte, int pad,
+ * off_t offset) system call.
+ */
+static abi_long do_bsd_freebsd6_pread(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall freebsd6_pread()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * undocumented freebsd6_pwrite(int fd, void *buf, size_t nbyte, int pad,
+ * off_t offset) system call.
+ */
+static abi_long do_bsd_freebsd6_pwrite(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4, abi_long arg5)
+{
+
+    qemu_log("qemu: Unsupported syscall freebsd6_pwrite()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * undocumented freebsd6_lseek(int fd, int pad, off_t offset, int whence)
+ * system call.
+ */
+static abi_long do_bsd_freebsd6_lseek(abi_long arg1, abi_long arg2,
+        abi_long arg3, abi_long arg4)
+{
+
+    qemu_log("qemu: Unsupported syscall freebsd6_lseek()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * undocumented freebsd6_truncate(char *path, int pad, off_t offset) system
+ * call.
+ */
+static abi_long do_bsd_freebsd6_truncate(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall freebsd6_truncate()\n");
+    return -TARGET_ENOSYS;
+}
+
+/*
+ * undocumented freebsd6_ftruncate(int fd, int pad, off_t offset) system
+ * call.
+ */
+static abi_long do_bsd_freebsd6_ftruncate(abi_long arg1, abi_long arg2,
+        abi_long arg3)
+{
+
+    qemu_log("qemu: Unsupported syscall freebsd6_ftruncate()\n");
+    return -TARGET_ENOSYS;
+}
+
+#endif /* !__BSD_FILE_H_ */
diff --git a/bsd-user/i386/target_arch_vmparam.h b/bsd-user/i386/target_arch_vmparam.h
index 6d3cf4f..654400a 100644
--- a/bsd-user/i386/target_arch_vmparam.h
+++ b/bsd-user/i386/target_arch_vmparam.h
@@ -18,4 +18,9 @@  static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
     return state->regs[R_ESP];
 }
 
+static inline void set_second_rval(CPUX86State *state, abi_ulong retval2)
+{
+    state->regs[R_EDX] = retval2;
+}
+
 #endif /* !_TARGET_ARCH_VMPARAM_H_ */
diff --git a/bsd-user/mips/target_arch_vmparam.h b/bsd-user/mips/target_arch_vmparam.h
index 8f8bc9e..f9e54ce 100644
--- a/bsd-user/mips/target_arch_vmparam.h
+++ b/bsd-user/mips/target_arch_vmparam.h
@@ -39,4 +39,9 @@  static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state)
     return state->active_tc.gpr[29];
 }
 
+static inline void set_second_rval(CPUMIPSState *state, abi_ulong retval2)
+{
+    state->active_tc.gpr[3] = retval2;
+}
+
 #endif  /* ! _TARGET_ARCH_VMPARAM_H_ */
diff --git a/bsd-user/mips64/target_arch_vmparam.h b/bsd-user/mips64/target_arch_vmparam.h
index 0480035..1ba09e0 100644
--- a/bsd-user/mips64/target_arch_vmparam.h
+++ b/bsd-user/mips64/target_arch_vmparam.h
@@ -39,4 +39,9 @@  static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state)
     return state->active_tc.gpr[29];
 }
 
+static inline void set_second_rval(CPUMIPSState *state, abi_ulong retval2)
+{
+    state->active_tc.gpr[3] = retval2;
+}
+
 #endif  /* ! _TARGET_ARCH_VMPARAM_H_ */
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index 02a05bb..da69073 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -422,6 +422,42 @@  static inline void *lock_user_string(abi_ulong guest_addr)
 #define unlock_user_struct(host_ptr, guest_addr, copy)          \
     unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0)
 
+#if TARGET_ABI_BITS == 32
+static inline uint64_t
+target_offset64(uint32_t word0, uint32_t word1)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+    return ((uint64_t)word0 << 32) | word1;
+#else
+    return ((uint64_t)word1 << 32) | word0;
+#endif
+}
+#else /* TARGET_ABI_BITS != 32 */
+static inline uint64_t
+target_offset64(uint64_t word0, uint64_t word1)
+{
+    return word0;
+}
+#endif /* TARGET_ABI_BITS != 32 */
+
+/* ARM EABI and MIPS expect 64bit types aligned even on pairs of registers */
+#ifdef TARGET_ARM
+static inline int
+regpairs_aligned(void *cpu_env) {
+    return ((((CPUARMState *)cpu_env)->eabi) == 1);
+}
+#elif defined(TARGET_MIPS) && TARGET_ABI_BITS == 32
+static inline int regpairs_aligned(void *cpu_env)
+{
+    return 1;
+}
+#else
+static inline int regpairs_aligned(void *cpu_env)
+{
+    return 0;
+}
+#endif
+
 #if defined(CONFIG_USE_NPTL)
 #include <pthread.h>
 #endif
diff --git a/bsd-user/sparc/target_arch_vmparam.h b/bsd-user/sparc/target_arch_vmparam.h
index 4bda417..75bbeeb 100644
--- a/bsd-user/sparc/target_arch_vmparam.h
+++ b/bsd-user/sparc/target_arch_vmparam.h
@@ -26,5 +26,10 @@  static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
     return state->regwptr[UREG_FP];
 }
 
+static inline void set_second_rval(CPUSPARCState *state, abi_ulong retval2)
+{
+    state->regwptr[1] = retval2;
+}
+
 #endif /* !_TARGET_ARCH_VMPARAM_H_ */
 
diff --git a/bsd-user/sparc64/target_arch_vmparam.h b/bsd-user/sparc64/target_arch_vmparam.h
index 87548da..2c2323b 100644
--- a/bsd-user/sparc64/target_arch_vmparam.h
+++ b/bsd-user/sparc64/target_arch_vmparam.h
@@ -28,5 +28,10 @@  static inline abi_ulong get_sp_from_cpustate(CPUSPARCState *state)
     return state->regwptr[UREG_FP];
 }
 
+static inline void set_second_rval(CPUSPARCState *state, abi_ulong retval2)
+{
+    state->regwptr[1] = retval2;
+}
+
 #endif /* !_TARGET_ARCH_VMPARAM_H_ */
 
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index b64c0b0..2efa772 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -16,21 +16,16 @@ 
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
-#include <stdlib.h>
 #include <stdio.h>
 #include <stdint.h>
 #include <stdarg.h>
 #include <string.h>
 #include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
 #include <time.h>
-#include <limits.h>
 #include <sys/types.h>
 #include <sys/syscall.h>
 #include <sys/param.h>
 #include <sys/sysctl.h>
-#include <utime.h>
 
 #include "qemu.h"
 #include "qemu-common.h"
@@ -38,6 +33,7 @@ 
 #define target_to_host_bitmask(x, tbl) (x)
 
 #include "bsd-errno.h"
+#include "bsd-file.h"
 #include "bsd-mem.h"
 
 /* #define DEBUG */
@@ -282,7 +278,6 @@  abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
                             abi_long arg8)
 {
     abi_long ret;
-    void *p;
 
 #ifdef DEBUG
     gemu_log("freebsd syscall %d\n", num);
@@ -300,39 +295,305 @@  abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         _exit(arg1);
         ret = 0; /* avoid warning */
         break;
-    case TARGET_FREEBSD_NR_read:
-        if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
-            goto efault;
-        ret = get_errno(read(arg1, p, arg3));
-        unlock_user(p, arg2, ret);
-        break;
-    case TARGET_FREEBSD_NR_write:
-        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
-            goto efault;
-        ret = get_errno(write(arg1, p, arg3));
-        unlock_user(p, arg2, 0);
-        break;
-    case TARGET_FREEBSD_NR_writev:
-        {
-            int count = arg3;
-            struct iovec *vec;
-
-            vec = alloca(count * sizeof(struct iovec));
-            if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0)
-                goto efault;
-            ret = get_errno(writev(arg1, vec, count));
-            unlock_iovec(vec, arg2, count, 0);
-        }
+
+        /*
+         * File system calls.
+         */
+    case TARGET_FREEBSD_NR_read: /* read(2) */
+        ret = do_bsd_read(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_pread: /* pread(2) */
+        ret = do_bsd_pread(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_readv: /* readv(2) */
+        ret = do_bsd_read(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_write: /* write(2) */
+        ret = do_bsd_write(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_pwrite: /* pwrite(2) */
+        ret = do_bsd_pwrite(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_writev: /* writev(2) */
+        ret = do_bsd_writev(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_pwritev: /* pwritev(2) */
+        ret = do_bsd_pwritev(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_open: /* open(2) */
+        ret = do_bsd_open(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_openat: /* openat(2) */
+        ret = do_bsd_openat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_close: /* close(2) */
+        ret = do_bsd_close(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_closefrom: /* closefrom(2) */
+        ret = do_bsd_closefrom(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_revoke: /* revoke(2) */
+        ret = do_bsd_revoke(arg1);
+        break;
+
+#ifdef TARGET_FREEBSD_NR_creat
+    case TARGET_FREEBSD_NR_creat: /* creat(2) (obsolete) */
+        ret = do_bsd_creat(arg1);
+        break;
+#endif
+
+    case TARGET_FREEBSD_NR_access: /* access(2) */
+        ret = do_bsd_access(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_eaccess: /* eaccess(2) */
+        ret = do_bsd_eaccess(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_faccessat: /* faccessat(2) */
+        ret = do_bsd_faccessat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_chdir: /* chdir(2) */
+        ret = do_bsd_chdir(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_fchdir: /* fchdir(2) */
+        ret = do_bsd_fchdir(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_rename: /* rename(2) */
+        ret = do_bsd_rename(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_renameat: /* renameat(2) */
+        ret = do_bsd_renameat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_link: /* link(2) */
+        ret = do_bsd_link(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_linkat: /* linkat(2) */
+        ret = do_bsd_linkat(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_unlink: /* unlink(2) */
+        ret = do_bsd_unlink(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_unlinkat: /* unlinkat(2) */
+        ret = do_bsd_unlinkat(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_mkdir: /* mkdir(2) */
+        ret = do_bsd_mkdir(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_mkdirat: /* mkdirat(2) */
+        ret = do_bsd_mkdirat(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_rmdir: /* rmdir(2) (XXX no rmdirat()?) */
+        ret = do_bsd_rmdir(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR___getcwd: /* undocumented __getcwd() */
+        ret = do_bsd___getcwd(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_dup: /* dup(2) */
+        ret = do_bsd_dup(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_dup2: /* dup2(2) */
+        ret = do_bsd_dup2(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_truncate: /* truncate(2) */
+        ret = do_bsd_truncate(cpu_env, arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_ftruncate: /* ftruncate(2) */
+        ret = do_bsd_ftruncate(cpu_env, arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_acct: /* acct(2) */
+        ret = do_bsd_acct(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_sync: /* sync(2) */
+        ret = do_bsd_sync();
+        break;
+
+    case TARGET_FREEBSD_NR_mount: /* mount(2) */
+        ret = do_bsd_mount(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_unmount: /* unmount(2) */
+        ret = do_bsd_unmount(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_nmount: /* nmount(2) */
+        ret = do_bsd_nmount(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_symlink: /* symlink(2) */
+        ret = do_bsd_symlink(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_symlinkat: /* symlinkat(2) */
+        ret = do_bsd_symlinkat(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_readlink: /* readlink(2) */
+        ret = do_bsd_readlink(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_readlinkat: /* readlinkat(2) */
+        ret = do_bsd_readlinkat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_chmod: /* chmod(2) */
+        ret = do_bsd_chmod(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fchmod: /* fchmod(2) */
+        ret = do_bsd_fchmod(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_lchmod: /* lchmod(2) */
+        ret = do_bsd_lchmod(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fchmodat: /* fchmodat(2) */
+        ret = do_bsd_fchmodat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_mknod: /* mknod(2) */
+        ret = do_bsd_mknod(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_mknodat: /* mknodat(2) */
+        ret = do_bsd_mknodat(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_chown: /* chown(2) */
+        ret = do_bsd_chown(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_fchown: /* fchown(2) */
+        ret = do_bsd_fchown(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_lchown: /* lchown(2) */
+        ret = do_bsd_lchown(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_fchownat: /* fchownat(2) */
+        ret = do_bsd_fchownat(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_chflags: /* chflags(2) */
+        ret = do_bsd_chflags(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_lchflags: /* lchflags(2) */
+        ret = do_bsd_lchflags(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fchflags: /* fchflags(2) */
+        ret = do_bsd_fchflags(arg2, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_chroot: /* chroot(2) */
+        ret = do_bsd_chroot(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_flock: /* flock(2) */
+        ret = do_bsd_flock(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_mkfifo: /* mkfifo(2) */
+        ret = do_bsd_mkfifo(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_mkfifoat: /* mkfifoat(2) */
+        ret = do_bsd_mkfifoat(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_pathconf: /* pathconf(2) */
+        ret = do_bsd_pathconf(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_lpathconf: /* lpathconf(2) */
+        ret = do_bsd_lpathconf(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_fpathconf: /* fpathconf(2) */
+        ret = do_bsd_fpathconf(arg1, arg2);
+        break;
+
+    case TARGET_FREEBSD_NR_undelete: /* undelete(2) */
+        ret = do_bsd_undelete(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_poll: /* poll(2) */
+        ret = do_bsd_poll(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_openbsd_poll:  /* undocumented openbsd_poll() */
+        ret = do_bsd_openbsd_poll(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_lseek: /* lseek(2) */
+        ret = do_bsd_lseek(cpu_env, arg1, arg2, arg3, arg4);
         break;
-    case TARGET_FREEBSD_NR_open:
-        if (!(p = lock_user_string(arg1)))
-            goto efault;
-        ret = get_errno(open(path(p),
-                             target_to_host_bitmask(arg2, fcntl_flags_tbl),
-                             arg3));
-        unlock_user(p, arg1, 0);
+
+    case TARGET_FREEBSD_NR_pipe: /* pipe(2) */
+        ret = do_bsd_pipe(cpu_env, arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_swapon: /* swapon(2) */
+        ret = do_bsd_swapon(arg1);
+        break;
+
+    case TARGET_FREEBSD_NR_swapoff: /* swapoff(2) */
+        ret = do_bsd_swapoff(arg1);
         break;
 
+    case TARGET_FREEBSD_NR_freebsd6_pread: /* undocumented freebsd6_pread() */
+        ret = do_bsd_freebsd6_pread(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd6_pwrite: /* undocumented freebsd6_pwrite() */
+        ret = do_bsd_freebsd6_pwrite(arg1, arg2, arg3, arg4, arg5);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd6_lseek: /* undocumented freebsd6_lseek() */
+        ret = do_bsd_freebsd6_lseek(arg1, arg2, arg3, arg4);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd6_truncate: /* undocumented */
+        ret = do_bsd_freebsd6_truncate(arg1, arg2, arg3);
+        break;
+
+    case TARGET_FREEBSD_NR_freebsd6_ftruncate: /* undocumented */
+        ret = do_bsd_freebsd6_ftruncate(arg1, arg2, arg3);
+        break;
+
+
         /*
          * Memory management system calls.
          */
@@ -440,16 +701,13 @@  abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8));
         break;
     }
- fail:
+
 #ifdef DEBUG
     gemu_log(" = %ld\n", ret);
 #endif
     if (do_strace)
         print_freebsd_syscall_ret(num, ret);
     return ret;
- efault:
-    ret = -TARGET_EFAULT;
-    goto fail;
 }
 
 abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
@@ -457,7 +715,6 @@  abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
                            abi_long arg5, abi_long arg6)
 {
     abi_long ret;
-    void *p;
 
 #ifdef DEBUG
     gemu_log("netbsd syscall %d\n", num);
@@ -475,25 +732,15 @@  abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
         _exit(arg1);
         ret = 0; /* avoid warning */
         break;
+
     case TARGET_NETBSD_NR_read:
-        if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
-            goto efault;
-        ret = get_errno(read(arg1, p, arg3));
-        unlock_user(p, arg2, ret);
+        ret = do_bsd_read(arg1, arg2, arg3);
         break;
     case TARGET_NETBSD_NR_write:
-        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
-            goto efault;
-        ret = get_errno(write(arg1, p, arg3));
-        unlock_user(p, arg2, 0);
+        ret = do_bsd_write(arg1, arg2, arg3);
         break;
     case TARGET_NETBSD_NR_open:
-        if (!(p = lock_user_string(arg1)))
-            goto efault;
-        ret = get_errno(open(path(p),
-                             target_to_host_bitmask(arg2, fcntl_flags_tbl),
-                             arg3));
-        unlock_user(p, arg1, 0);
+        ret = do_bsd_open(arg1, arg2, arg3);
         break;
 
     case TARGET_NETBSD_NR_mmap:
@@ -511,16 +758,12 @@  abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
         ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
         break;
     }
- fail:
 #ifdef DEBUG
     gemu_log(" = %ld\n", ret);
 #endif
     if (do_strace)
         print_netbsd_syscall_ret(num, ret);
     return ret;
- efault:
-    ret = -TARGET_EFAULT;
-    goto fail;
 }
 
 abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
@@ -528,7 +771,6 @@  abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
                             abi_long arg5, abi_long arg6)
 {
     abi_long ret;
-    void *p;
 
 #ifdef DEBUG
     gemu_log("openbsd syscall %d\n", num);
@@ -546,25 +788,15 @@  abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
         _exit(arg1);
         ret = 0; /* avoid warning */
         break;
+
     case TARGET_OPENBSD_NR_read:
-        if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
-            goto efault;
-        ret = get_errno(read(arg1, p, arg3));
-        unlock_user(p, arg2, ret);
+        ret = do_bsd_read(arg1, arg2, arg3);
         break;
     case TARGET_OPENBSD_NR_write:
-        if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
-            goto efault;
-        ret = get_errno(write(arg1, p, arg3));
-        unlock_user(p, arg2, 0);
+        ret = do_bsd_write(arg1, arg2, arg3);
         break;
     case TARGET_OPENBSD_NR_open:
-        if (!(p = lock_user_string(arg1)))
-            goto efault;
-        ret = get_errno(open(path(p),
-                             target_to_host_bitmask(arg2, fcntl_flags_tbl),
-                             arg3));
-        unlock_user(p, arg1, 0);
+        ret = do_bsd_open(arg1, arg2, arg3);
         break;
 
     case TARGET_OPENBSD_NR_mmap:
@@ -582,16 +814,12 @@  abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
         ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
         break;
     }
- fail:
 #ifdef DEBUG
     gemu_log(" = %ld\n", ret);
 #endif
     if (do_strace)
         print_openbsd_syscall_ret(num, ret);
     return ret;
- efault:
-    ret = -TARGET_EFAULT;
-    goto fail;
 }
 
 void syscall_init(void)
diff --git a/bsd-user/x86_64/target_arch_vmparam.h b/bsd-user/x86_64/target_arch_vmparam.h
index 8acf7a5..5e13076 100644
--- a/bsd-user/x86_64/target_arch_vmparam.h
+++ b/bsd-user/x86_64/target_arch_vmparam.h
@@ -20,4 +20,9 @@  static inline abi_ulong get_sp_from_cpustate(CPUX86State *state)
     return state->regs[R_ESP];
 }
 
+static inline void set_second_rval(CPUX86State *state, abi_ulong retval2)
+{
+    state->regs[R_EDX] = retval2;
+}
+
 #endif /* !_TARGET_ARCH_VMPARAM_H_ */