Patchwork [19/23] bsd-user: add shims for sysarch() and sysctl() system calls

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

Comments

Stacey Son - June 24, 2013, 2:03 a.m.
This change adds support for sysarch() and sysctl() system call emulation.
sysarch() is both architecture and OS dependent.  Therefore this change
adds a handler for each architecture.  sysctl() has a lot special cases that
have to each decoded and handled individually.

Signed-off-by: Stacey Son <sson@FreeBSD.org>
---
 bsd-user/Makefile.objs                 |    3 +-
 bsd-user/freebsd/os-sys.c              |  268 ++++++++++++++++++++++++++++++++
 bsd-user/i386/syscall.h                |    2 +
 bsd-user/i386/target_arch_sysarch.h    |   69 ++++++++
 bsd-user/mips/syscall.h                |   12 ++-
 bsd-user/mips/target_arch_sysarch.h    |   50 ++++++
 bsd-user/mips64/syscall.h              |   11 ++
 bsd-user/mips64/target_arch_sysarch.h  |   50 ++++++
 bsd-user/netbsd/os-sys.c               |   46 ++++++
 bsd-user/openbsd/os-sys.c              |   46 ++++++
 bsd-user/qemu.h                        |    5 +
 bsd-user/sparc/syscall.h               |    7 +-
 bsd-user/sparc/target_arch_sysarch.h   |   43 +++++
 bsd-user/sparc64/syscall.h             |    7 +-
 bsd-user/sparc64/target_arch_sysarch.h |   43 +++++
 bsd-user/syscall.c                     |  209 +++----------------------
 bsd-user/x86_64/syscall.h              |    4 +-
 bsd-user/x86_64/target_arch_sysarch.h  |   67 ++++++++
 18 files changed, 747 insertions(+), 195 deletions(-)
 create mode 100644 bsd-user/freebsd/os-sys.c
 create mode 100644 bsd-user/i386/target_arch_sysarch.h
 create mode 100644 bsd-user/mips/target_arch_sysarch.h
 create mode 100644 bsd-user/mips64/target_arch_sysarch.h
 create mode 100644 bsd-user/netbsd/os-sys.c
 create mode 100644 bsd-user/openbsd/os-sys.c
 create mode 100644 bsd-user/sparc/target_arch_sysarch.h
 create mode 100644 bsd-user/sparc64/target_arch_sysarch.h
 create mode 100644 bsd-user/x86_64/target_arch_sysarch.h

Patch

diff --git a/bsd-user/Makefile.objs b/bsd-user/Makefile.objs
index fbb3e56..e392760 100644
--- a/bsd-user/Makefile.objs
+++ b/bsd-user/Makefile.objs
@@ -1,4 +1,5 @@ 
 obj-y = main.o bsdload.o elfload.o ioctl.o mmap.o signal.o strace.o syscall.o \
 	        uaccess.o bsd-mem.o bsd-proc.o $(TARGET_OS)/os-time.o \
 			$(TARGET_OS)/os-proc.o bsd-socket.o $(TARGET_OS)/os-socket.o \
-			$(TARGET_OS)/os-stat.o $(TARGET_OS)/os-thread.o
+			$(TARGET_OS)/os-stat.o $(TARGET_OS)/os-sys.o \
+			$(TARGET_OS)/os-thread.o
diff --git a/bsd-user/freebsd/os-sys.c b/bsd-user/freebsd/os-sys.c
new file mode 100644
index 0000000..86b2826
--- /dev/null
+++ b/bsd-user/freebsd/os-sys.c
@@ -0,0 +1,268 @@ 
+/*
+ *  FreeBSD sysctl() and sysarch() system call emulation
+ *
+ *  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/>.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <string.h>
+
+#include "qemu.h"
+
+#include "target_arch_sysarch.h"
+#include "target_os_vmparam.h"
+
+/*
+ * XXX this uses the undocumented oidfmt interface to find the kind of
+ * a requested sysctl, see /sys/kern/kern_sysctl.c:sysctl_sysctl_oidfmt()
+ * (compare to src/sbin/sysctl/sysctl.c)
+ */
+static int
+oidfmt(int *oid, int len, char *fmt, uint32_t *kind)
+{
+    int qoid[CTL_MAXNAME+2];
+    uint8_t buf[BUFSIZ];
+    int i;
+    size_t j;
+
+    qoid[0] = 0;
+    qoid[1] = 4;
+    memcpy(qoid + 2, oid, len * sizeof(int));
+
+    j = sizeof(buf);
+    i = sysctl(qoid, len + 2, buf, &j, 0, 0);
+    if (i) {
+        return i;
+    }
+
+    if (kind) {
+        *kind = *(uint32_t *)buf;
+    }
+
+    if (fmt) {
+        strcpy(fmt, (char *)(buf + sizeof(uint32_t)));
+    }
+    return 0;
+}
+
+/*
+ * try and convert sysctl return data for the target.
+ * XXX doesn't handle CTLTYPE_OPAQUE and CTLTYPE_STRUCT.
+ */
+static int sysctl_oldcvt(void *holdp, size_t holdlen, uint32_t kind)
+{
+    switch (kind & CTLTYPE) {
+    case CTLTYPE_INT:
+    case CTLTYPE_UINT:
+        *(uint32_t *)holdp = tswap32(*(uint32_t *)holdp);
+        break;
+
+#ifdef TARGET_ABI32
+    case CTLTYPE_LONG:
+    case CTLTYPE_ULONG:
+        *(uint32_t *)holdp = tswap32(*(long *)holdp);
+        break;
+#else
+    case CTLTYPE_LONG:
+        *(uint64_t *)holdp = tswap64(*(long *)holdp);
+    case CTLTYPE_ULONG:
+        *(uint64_t *)holdp = tswap64(*(unsigned long *)holdp);
+        break;
+#endif
+#if !defined(__FreeBSD_version) || __FreeBSD_version < 900031
+    case CTLTYPE_QUAD:
+#else
+    case CTLTYPE_U64:
+    case CTLTYPE_S64:
+#endif
+        *(uint64_t *)holdp = tswap64(*(uint64_t *)holdp);
+        break;
+
+    case CTLTYPE_STRING:
+        break;
+
+    default:
+        /* XXX unhandled */
+        return -1;
+    }
+    return 0;
+}
+
+/*
+ * Convert the undocmented name2oid sysctl data for the target.
+ */
+static inline void sysctl_name2oid(uint32_t *holdp, size_t holdlen)
+{
+    size_t i;
+
+    for (i = 0; i < holdlen; i++) {
+        holdp[i] = tswap32(holdp[i]);
+    }
+}
+
+static inline void sysctl_oidfmt(uint32_t *holdp)
+{
+    /* byte swap the kind */
+    holdp[0] = tswap32(holdp[0]);
+}
+
+abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
+        abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen)
+{
+    abi_long ret;
+    void *hnamep, *holdp = NULL, *hnewp = NULL;
+    size_t holdlen;
+    abi_ulong oldlen = 0;
+    int32_t *snamep = g_malloc(sizeof(int32_t) * namelen), *p, *q, i;
+    uint32_t kind = 0;
+    TaskState *ts = (TaskState *)env->opaque;
+
+    if (oldlenp) {
+        if (get_user_ual(oldlen, oldlenp)) {
+            return -TARGET_EFAULT;
+        }
+    }
+    hnamep = lock_user(VERIFY_READ, namep, namelen, 1);
+    if (hnamep == NULL) {
+        return -TARGET_EFAULT;
+    }
+    if (newp) {
+        hnewp = lock_user(VERIFY_READ, newp, newlen, 1);
+        if (hnewp == NULL) {
+            return -TARGET_EFAULT;
+        }
+    }
+    if (oldp) {
+        holdp = lock_user(VERIFY_WRITE, oldp, oldlen, 0);
+        if (holdp == NULL) {
+            return -TARGET_EFAULT;
+        }
+    }
+    holdlen = oldlen;
+    for (p = hnamep, q = snamep, i = 0; i < namelen; p++, i++) {
+        *q++ = tswap32(*p);
+    }
+    oidfmt(snamep, namelen, NULL, &kind);
+
+    /* Handle some arch/emulator dependent sysctl()'s here. */
+    switch (snamep[0]) {
+    case CTL_KERN:
+        switch (snamep[1]) {
+        case KERN_USRSTACK:
+#if TARGET_USRSTACK != 0
+            (*(abi_ulong *)holdp) = tswapal(TARGET_USRSTACK);
+            holdlen = sizeof(abi_ulong);
+            ret = 0;
+#else
+            ret = -TARGET_ENOENT;
+#endif
+            goto out;
+
+        case KERN_PS_STRINGS:
+#if defined(TARGET_PS_STRINGS)
+            (*(abi_ulong *)holdp) = tswapal(TARGET_PS_STRINGS);
+            holdlen = sizeof(abi_ulong);
+            ret = 0;
+#else
+            ret = -TARGET_ENOENT;
+#endif
+            goto out;
+
+        case KERN_PROC:
+            switch (snamep[2]) {
+            case KERN_PROC_PATHNAME:
+                holdlen = strlen(ts->bprm->fullpath) + 1;
+                if (holdp) {
+                    if (oldlen < holdlen) {
+                        ret = -TARGET_EINVAL;
+                        goto out;
+                    }
+                    strlcpy(holdp, ts->bprm->fullpath, oldlen);
+                }
+                ret = 0;
+                goto out;
+
+            default:
+                break;
+            }
+            break;
+
+        default:
+            break;
+        }
+        break;
+
+    case CTL_HW:
+        switch (snamep[1]) {
+        case HW_MACHINE:
+            strlcpy(holdp, TARGET_HW_MACHINE, oldlen);
+            ret = 0;
+            goto out;
+
+        case HW_MACHINE_ARCH:
+            strlcpy(holdp, TARGET_HW_MACHINE_ARCH, oldlen);
+            ret = 0;
+            goto out;
+
+        default:
+            break;
+        }
+    default:
+        break;
+    }
+
+    ret = get_errno(sysctl(snamep, namelen, holdp, &holdlen, hnewp, newlen));
+    if (!ret && (holdp != 0 && holdlen != 0)) {
+        if (0 == snamep[0] && (3 == snamep[1] || 4 == snamep[1])) {
+            if (3 == snamep[1]) {
+                /* Handle the undocumented name2oid special case. */
+                sysctl_name2oid(holdp, holdlen);
+            } else {
+                /* Handle oidfmt */
+                sysctl_oidfmt(holdp);
+            }
+        } else {
+            sysctl_oldcvt(holdp, holdlen, kind);
+        }
+    }
+#ifdef DEBUG
+    else {
+        printf("sysctl(mib[0]=%d, mib[1]=%d, mib[3]=%d...) returned %d\n",
+        snamep[0], snamep[1], snamep[2], (int)ret);
+    }
+#endif
+
+out:
+    if (oldlenp) {
+        put_user_ual(holdlen, oldlenp);
+    }
+    unlock_user(hnamep, namep, 0);
+    unlock_user(holdp, oldp, holdlen);
+    if (hnewp) {
+        unlock_user(hnewp, newp, 0);
+    }
+    g_free(snamep);
+    return ret;
+}
+
+/* sysarch() is architecture dependent. */
+abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2)
+{
+
+    return do_freebsd_arch_sysarch(cpu_env, arg1, arg2);
+}
diff --git a/bsd-user/i386/syscall.h b/bsd-user/i386/syscall.h
index 8028fc8..52de302 100644
--- a/bsd-user/i386/syscall.h
+++ b/bsd-user/i386/syscall.h
@@ -178,5 +178,7 @@  struct target_vm86plus_struct {
 
 
 #define UNAME_MACHINE "i386"
+#define TARGET_HW_MACHINE UNAME_MACHINE
+#define TARGET_HW_MACHINE_ARCH UNAME_MACHINE
 
 #endif /* ! _I386_SYSCALL_H_ */
diff --git a/bsd-user/i386/target_arch_sysarch.h b/bsd-user/i386/target_arch_sysarch.h
new file mode 100644
index 0000000..373c838
--- /dev/null
+++ b/bsd-user/i386/target_arch_sysarch.h
@@ -0,0 +1,69 @@ 
+/*
+ *  i386 sysarch system call emulation
+ *
+ *  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 __ARCH_SYSARCH_H_
+#define __ARCH_SYSARCH_H_
+
+#include "syscall.h"
+
+static abi_long do_freebsd_arch_sysarch(CPUX86State *env, int op,
+        abi_ulong parms)
+{
+    abi_long ret = 0;
+    abi_ulong val;
+    int idx;
+
+    switch (op) {
+    case TARGET_FREEBSD_I386_SET_GSBASE:
+    case TARGET_FREEBSD_I386_SET_FSBASE:
+        if (op == TARGET_FREEBSD_I386_SET_GSBASE) {
+            idx = R_GS;
+        } else {
+            idx = R_FS;
+        }
+        if (get_user(val, parms, abi_ulong)) {
+            return -TARGET_EFAULT;
+        }
+        cpu_x86_load_seg(env, idx, 0);
+        env->segs[idx].base = val;
+        break;
+
+    case TARGET_FREEBSD_I386_GET_GSBASE:
+    case TARGET_FREEBSD_I386_GET_FSBASE:
+        if (op == TARGET_FREEBSD_I386_GET_GSBASE) {
+            idx = R_GS;
+        } else {
+            idx = R_FS;
+        }
+        val = env->segs[idx].base;
+        if (put_user(val, parms, abi_ulong)) {
+            return -TARGET_EFAULT;
+        }
+        break;
+
+    /* XXX handle the others... */
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+    return ret;
+}
+
+#endif /* !__ARCH_SYSARCH_H_ */
+
diff --git a/bsd-user/mips/syscall.h b/bsd-user/mips/syscall.h
index 149970a..49e2833 100644
--- a/bsd-user/mips/syscall.h
+++ b/bsd-user/mips/syscall.h
@@ -36,7 +36,17 @@  struct target_pt_regs {
     abi_ulong cp0_epc;
 };
 
-
+#if defined(TARGET_WORDS_BIG_ENDIAN)
 #define UNAME_MACHINE "mips"
+#else
+#define UNAME_MACHINE "mipsel"
+#endif
+
+#define TARGET_HW_MACHINE       "mips"
+#define TARGET_HW_MACHINE_ARCH   UNAME_MACHINE
+
+/* sysarch() commands */
+#define TARGET_MIPS_SET_TLS     1
+#define TARGET_MIPS_GET_TLS     2
 
 #endif /* !_MIPS_SYSCALL_H_ */
diff --git a/bsd-user/mips/target_arch_sysarch.h b/bsd-user/mips/target_arch_sysarch.h
new file mode 100644
index 0000000..22fa53a
--- /dev/null
+++ b/bsd-user/mips/target_arch_sysarch.h
@@ -0,0 +1,50 @@ 
+/*
+ *  mips sysarch() system call emulation
+ *
+ *  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 __ARCH_SYSARCH_H_
+#define __ARCH_SYSARCH_H_
+
+#include "syscall.h"
+
+static abi_long do_freebsd_arch_sysarch(CPUMIPSState *env, int op,
+        abi_ulong parms)
+{
+    int ret = 0;
+
+    switch (op) {
+    case TARGET_MIPS_SET_TLS:
+        cpu_set_tls(env, parms);
+        break;
+
+    case TARGET_MIPS_GET_TLS:
+        /* XXX Need a cpu_get_tls() */
+        if (put_user(env->tls_value, parms, abi_ulong)) {
+            ret = -TARGET_EFAULT;
+        }
+        break;
+
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
+#endif /*!__ARCH_SYSARCH_H_ */
diff --git a/bsd-user/mips64/syscall.h b/bsd-user/mips64/syscall.h
index 300ed9b..b068fa1 100644
--- a/bsd-user/mips64/syscall.h
+++ b/bsd-user/mips64/syscall.h
@@ -37,6 +37,17 @@  struct target_pt_regs {
 };
 
 
+#if defined(TARGET_WORDS_BIG_ENDIAN)
 #define UNAME_MACHINE "mips64"
+#else
+#define UNAME_MACHINE "mips64el"
+#endif
+
+#define TARGET_HW_MACHINE       "mips"
+#define TARGET_HW_MACHINE_ARCH  UNAME_MACHINE
+
+/* sysarch() commands */
+#define TARGET_MIPS_SET_TLS     1
+#define TARGET_MIPS_GET_TLS     2
 
 #endif /* !_MIPS64_SYSCALL_H_ */
diff --git a/bsd-user/mips64/target_arch_sysarch.h b/bsd-user/mips64/target_arch_sysarch.h
new file mode 100644
index 0000000..503bc90
--- /dev/null
+++ b/bsd-user/mips64/target_arch_sysarch.h
@@ -0,0 +1,50 @@ 
+/*
+ *  mips64 sysarch() system call emulation
+ *
+ *  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 __ARCH_SYSARCH_H_
+#define __ARCH_SYSARCH_H_
+
+#include "syscall.h"
+
+static inline abi_long do_freebsd_arch_sysarch(CPUMIPSState *env, int op,
+        abi_ulong parms)
+{
+    int ret = 0;
+
+    switch (op) {
+    case TARGET_MIPS_SET_TLS:
+        cpu_set_tls(env, parms);
+        break;
+
+    case TARGET_MIPS_GET_TLS:
+        /* XXX Need a cpu_get_tls() */
+        if (put_user(env->tls_value, parms, abi_ulong)) {
+            ret = -TARGET_EFAULT;
+        }
+        break;
+
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
+#endif /*!__ARCH_SYSARCH_H_ */
diff --git a/bsd-user/netbsd/os-sys.c b/bsd-user/netbsd/os-sys.c
new file mode 100644
index 0000000..68ea0e1
--- /dev/null
+++ b/bsd-user/netbsd/os-sys.c
@@ -0,0 +1,46 @@ 
+/*
+ *  NetBSD sysctl() and sysarch() system call emulation
+ *
+ *
+ *  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/>.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <string.h>
+
+#include "qemu.h"
+
+#include "target_arch_sysarch.h"
+#include "target_os_vmparam.h"
+
+
+/* This must be emulated to support FreeBSD target binaries on NetBSD host. */
+
+abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
+        abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen)
+{
+
+    qemu_log("qemu: Unsupported syscall __sysctl()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sysarch() is architecture dependent. */
+abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall sysarch()\n");
+    return -TARGET_ENOSYS;
+}
diff --git a/bsd-user/openbsd/os-sys.c b/bsd-user/openbsd/os-sys.c
new file mode 100644
index 0000000..30df472
--- /dev/null
+++ b/bsd-user/openbsd/os-sys.c
@@ -0,0 +1,46 @@ 
+/*
+ *  OpenBSD sysctl() and sysarch() system call emulation
+ *
+ *
+ *  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/>.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <string.h>
+
+#include "qemu.h"
+
+#include "target_arch_sysarch.h"
+#include "target_os_vmparam.h"
+
+
+/* This must be emulated to support FreeBSD target binaries on NetBSD host. */
+
+abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
+        abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen)
+{
+
+    qemu_log("qemu: Unsupported syscall __sysctl()\n");
+    return -TARGET_ENOSYS;
+}
+
+/* sysarch() is architecture dependent. */
+abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2)
+{
+
+    qemu_log("qemu: Unsupported syscall sysarch()\n");
+    return -TARGET_ENOSYS;
+}
diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h
index ec194d2..2ddf244 100644
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -248,6 +248,11 @@  int is_error(abi_long ret);
 abi_long freebsd_exec_common(abi_ulong path_or_fd, abi_ulong guest_argp,
         abi_ulong guest_envp, int do_fexec);
 
+/* os-sys.c */
+abi_long do_freebsd_sysctl(CPUArchState *env, abi_ulong namep, int32_t namelen,
+        abi_ulong oldp, abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen);
+abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2);
+
 /* os-thread.c */
 extern pthread_mutex_t *new_freebsd_thread_lock_ptr;
 void *new_freebsd_thread_start(void *arg);
diff --git a/bsd-user/sparc/syscall.h b/bsd-user/sparc/syscall.h
index 804889a..3a5b1e2 100644
--- a/bsd-user/sparc/syscall.h
+++ b/bsd-user/sparc/syscall.h
@@ -26,6 +26,11 @@  struct target_pt_regs {
 	abi_ulong u_regs[16];
 };
 
-#define UNAME_MACHINE "sun4"
+#define UNAME_MACHINE           "sun4"
+#define TARGET_HW_MACHINE       "sparc"
+#define TARGET_HW_MACHINE_ARCH  "sparc"
+
+#define TARGET_SPARC_UTRAP_INSTALL      1
+#define TARGET_SPARC_SIGTRAMP_INSTALL   2
 
 #endif /* ! _SPARC_SYSCALL_H_ */
diff --git a/bsd-user/sparc/target_arch_sysarch.h b/bsd-user/sparc/target_arch_sysarch.h
new file mode 100644
index 0000000..e523798
--- /dev/null
+++ b/bsd-user/sparc/target_arch_sysarch.h
@@ -0,0 +1,43 @@ 
+/*
+ *  SPARC sysarch() system call emulation
+ *
+ *  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 __ARCH_SYSARCH_H_
+#define __ARCH_SYSARCH_H_
+
+#include "syscall.h"
+
+static abi_long do_freebsd_arch_sysarch(void *env, int op, abi_ulong parms)
+{
+    int ret = 0;
+
+    switch (op) {
+    case TARGET_SPARC_SIGTRAMP_INSTALL:
+        /* XXX not currently handled */
+    case TARGET_SPARC_UTRAP_INSTALL:
+        /* XXX not currently handled */
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
+
+#endif /*!__ARCH_SYSARCH_H_ */
diff --git a/bsd-user/sparc64/syscall.h b/bsd-user/sparc64/syscall.h
index 9f3b97e..58cc38d 100644
--- a/bsd-user/sparc64/syscall.h
+++ b/bsd-user/sparc64/syscall.h
@@ -26,6 +26,11 @@  struct target_pt_regs {
 	abi_ulong fprs;
 };
 
-#define UNAME_MACHINE "sun4u"
+#define UNAME_MACHINE           "sun4u"
+#define TARGET_HW_MACHINE       "sparc"
+#define TARGET_HW_MACHINE_ARCH  "sparc64"
+
+#define TARGET_SPARC_UTRAP_INSTALL      1
+#define TARGET_SPARC_SIGTRAMP_INSTALL   2
 
 #endif /* !_SPARC64_SYSCALL_H_ */
diff --git a/bsd-user/sparc64/target_arch_sysarch.h b/bsd-user/sparc64/target_arch_sysarch.h
new file mode 100644
index 0000000..c18f699
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_sysarch.h
@@ -0,0 +1,43 @@ 
+/*
+ *  SPARC64 sysarch() system call emulation
+ *
+ *  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 __ARCH_SYSARCH_H_
+#define __ARCH_SYSARCH_H_
+
+#include "syscall.h"
+
+static abi_long do_freebsd_arch_sysarch(void *env, int op, abi_ulong parms)
+{
+    int ret = 0;
+
+    switch (op) {
+    case TARGET_SPARC_SIGTRAMP_INSTALL:
+        /* XXX not currently handled */
+    case TARGET_SPARC_UTRAP_INSTALL:
+        /* XXX not currently handled */
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+
+    return ret;
+}
+
+
+#endif /*!__ARCH_SYSARCH_H_ */
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 3407894..b976c93 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -77,183 +77,6 @@  int is_error(abi_long ret)
     return (abi_ulong)ret >= (abi_ulong)(-4096);
 }
 
-#if defined(TARGET_I386)
-static abi_long do_freebsd_sysarch(CPUX86State *env, int op, abi_ulong parms)
-{
-    abi_long ret = 0;
-    abi_ulong val;
-    int idx;
-
-    switch (op) {
-#ifdef TARGET_ABI32
-    case TARGET_FREEBSD_I386_SET_GSBASE:
-    case TARGET_FREEBSD_I386_SET_FSBASE:
-        if (op == TARGET_FREEBSD_I386_SET_GSBASE)
-#else
-    case TARGET_FREEBSD_AMD64_SET_GSBASE:
-    case TARGET_FREEBSD_AMD64_SET_FSBASE:
-        if (op == TARGET_FREEBSD_AMD64_SET_GSBASE)
-#endif
-            idx = R_GS;
-        else
-            idx = R_FS;
-        if (get_user(val, parms, abi_ulong))
-            return -TARGET_EFAULT;
-        cpu_x86_load_seg(env, idx, 0);
-        env->segs[idx].base = val;
-        break;
-#ifdef TARGET_ABI32
-    case TARGET_FREEBSD_I386_GET_GSBASE:
-    case TARGET_FREEBSD_I386_GET_FSBASE:
-        if (op == TARGET_FREEBSD_I386_GET_GSBASE)
-#else
-    case TARGET_FREEBSD_AMD64_GET_GSBASE:
-    case TARGET_FREEBSD_AMD64_GET_FSBASE:
-        if (op == TARGET_FREEBSD_AMD64_GET_GSBASE)
-#endif
-            idx = R_GS;
-        else
-            idx = R_FS;
-        val = env->segs[idx].base;
-        if (put_user(val, parms, abi_ulong))
-            return -TARGET_EFAULT;
-        break;
-    /* XXX handle the others... */
-    default:
-        ret = -TARGET_EINVAL;
-        break;
-    }
-    return ret;
-}
-#endif
-
-#ifdef TARGET_MIPS
-static abi_long do_freebsd_sysarch(void *env, int op, abi_ulong parms)
-{
-
-    return -TARGET_EINVAL;
-}
-#endif /* TARGET_MIPS */
-
-#ifdef TARGET_SPARC
-static abi_long do_freebsd_sysarch(void *env, int op, abi_ulong parms)
-{
-    /* XXX handle
-     * TARGET_FREEBSD_SPARC_UTRAP_INSTALL,
-     * TARGET_FREEBSD_SPARC_SIGTRAMP_INSTALL
-     */
-    return -TARGET_EINVAL;
-}
-#endif
-
-#ifdef __FreeBSD__
-/*
- * XXX this uses the undocumented oidfmt interface to find the kind of
- * a requested sysctl, see /sys/kern/kern_sysctl.c:sysctl_sysctl_oidfmt()
- * (this is mostly copied from src/sbin/sysctl/sysctl.c)
- */
-static int
-oidfmt(int *oid, int len, char *fmt, uint32_t *kind)
-{
-    int qoid[CTL_MAXNAME+2];
-    uint8_t buf[BUFSIZ];
-    int i;
-    size_t j;
-
-    qoid[0] = 0;
-    qoid[1] = 4;
-    memcpy(qoid + 2, oid, len * sizeof(int));
-
-    j = sizeof(buf);
-    i = sysctl(qoid, len + 2, buf, &j, 0, 0);
-    if (i)
-        return i;
-
-    if (kind)
-        *kind = *(uint32_t *)buf;
-
-    if (fmt)
-        strcpy(fmt, (char *)(buf + sizeof(uint32_t)));
-    return 0;
-}
-
-/*
- * try and convert sysctl return data for the target.
- * XXX doesn't handle CTLTYPE_OPAQUE and CTLTYPE_STRUCT.
- */
-static int sysctl_oldcvt(void *holdp, size_t holdlen, uint32_t kind)
-{
-    switch (kind & CTLTYPE) {
-    case CTLTYPE_INT:
-    case CTLTYPE_UINT:
-        *(uint32_t *)holdp = tswap32(*(uint32_t *)holdp);
-        break;
-#ifdef TARGET_ABI32
-    case CTLTYPE_LONG:
-    case CTLTYPE_ULONG:
-        *(uint32_t *)holdp = tswap32(*(long *)holdp);
-        break;
-#else
-    case CTLTYPE_LONG:
-        *(uint64_t *)holdp = tswap64(*(long *)holdp);
-    case CTLTYPE_ULONG:
-        *(uint64_t *)holdp = tswap64(*(unsigned long *)holdp);
-        break;
-#endif
-#ifdef CTLTYPE_U64
-    case CTLTYPE_S64:
-    case CTLTYPE_U64:
-#else
-    case CTLTYPE_QUAD:
-#endif
-        *(uint64_t *)holdp = tswap64(*(uint64_t *)holdp);
-        break;
-    case CTLTYPE_STRING:
-        break;
-    default:
-        /* XXX unhandled */
-        return -1;
-    }
-    return 0;
-}
-
-/* XXX this needs to be emulated on non-FreeBSD hosts... */
-static abi_long do_freebsd_sysctl(abi_ulong namep, int32_t namelen, abi_ulong oldp,
-                          abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen)
-{
-    abi_long ret;
-    void *hnamep, *holdp, *hnewp = NULL;
-    size_t holdlen;
-    abi_ulong oldlen = 0;
-    int32_t *snamep = g_malloc(sizeof(int32_t) * namelen), *p, *q, i;
-    uint32_t kind = 0;
-
-    if (oldlenp)
-        get_user_ual(oldlen, oldlenp);
-    if (!(hnamep = lock_user(VERIFY_READ, namep, namelen, 1)))
-        return -TARGET_EFAULT;
-    if (newp && !(hnewp = lock_user(VERIFY_READ, newp, newlen, 1)))
-        return -TARGET_EFAULT;
-    if (!(holdp = lock_user(VERIFY_WRITE, oldp, oldlen, 0)))
-        return -TARGET_EFAULT;
-    holdlen = oldlen;
-    for (p = hnamep, q = snamep, i = 0; i < namelen; p++, i++)
-       *q++ = tswap32(*p);
-    oidfmt(snamep, namelen, NULL, &kind);
-    /* XXX swap hnewp */
-    ret = get_errno(sysctl(snamep, namelen, holdp, &holdlen, hnewp, newlen));
-    if (!ret)
-        sysctl_oldcvt(holdp, holdlen, kind);
-    put_user_ual(holdlen, oldlenp);
-    unlock_user(hnamep, namep, 0);
-    unlock_user(holdp, oldp, holdlen);
-    if (hnewp)
-        unlock_user(hnewp, newp, 0);
-    g_free(snamep);
-    return ret;
-}
-#endif
-
 /* FIXME
  * lock_iovec()/unlock_iovec() have a return code of 0 for success where
  * other lock functions have a return code of 0 for failure.
@@ -1348,24 +1171,30 @@  abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         ret = do_bsd_ioctl(arg1, arg2, arg3);
         break;
 
-
-    case TARGET_FREEBSD_NR_break:
-        ret = do_obreak(arg1);
-        break;
-#ifdef __FreeBSD__
-    case TARGET_FREEBSD_NR___sysctl:
-        ret = do_freebsd_sysctl(arg1, arg2, arg3, arg4, arg5, arg6);
+        /*
+         * sys{ctl, arch, call}
+         */
+    case TARGET_FREEBSD_NR___sysctl: /* sysctl(3) */
+        ret = do_freebsd_sysctl(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6);
         break;
-#endif
-    case TARGET_FREEBSD_NR_sysarch:
+
+    case TARGET_FREEBSD_NR_sysarch: /* sysarch(2) */
         ret = do_freebsd_sysarch(cpu_env, arg1, arg2);
         break;
-    case TARGET_FREEBSD_NR_syscall:
-    case TARGET_FREEBSD_NR___syscall:
-        ret = do_freebsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,arg7,arg8,0);
+
+    case TARGET_FREEBSD_NR_syscall: /* syscall(2) */
+    case TARGET_FREEBSD_NR___syscall: /* __syscall(2) */
+        ret = do_freebsd_syscall(cpu_env, arg1 & 0xffff, arg2, arg3, arg4,
+                arg5, arg6, arg7, arg8, 0);
+        break;
+
+    case TARGET_FREEBSD_NR_break:
+        ret = do_obreak(arg1);
         break;
+
     default:
-        ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8));
+        ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
+                    arg8));
         break;
     }
 
diff --git a/bsd-user/x86_64/syscall.h b/bsd-user/x86_64/syscall.h
index fbaeacf..4fff6a5 100644
--- a/bsd-user/x86_64/syscall.h
+++ b/bsd-user/x86_64/syscall.h
@@ -128,7 +128,9 @@  struct target_msqid64_ds {
 #define TARGET_FREEBSD_AMD64_SET_GSBASE	131
 
 
-#define UNAME_MACHINE "x86_64"
+#define UNAME_MACHINE           "x86_64"
+#define TARGET_HW_MACHINE       "amd64"
+#define TARGET_HW_MACHINE_ARCH  "amd64"
 
 #define TARGET_ARCH_SET_GS 0x1001
 #define TARGET_ARCH_SET_FS 0x1002
diff --git a/bsd-user/x86_64/target_arch_sysarch.h b/bsd-user/x86_64/target_arch_sysarch.h
new file mode 100644
index 0000000..52a1d18
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_sysarch.h
@@ -0,0 +1,67 @@ 
+/*
+ *  x86_64 sysarch() syscall emulation
+ *
+ *
+ *  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 __ARCH_SYSARCH_H_
+#define __ARCH_SYSARCH_H_
+
+#include "syscall.h"
+
+static abi_long do_freebsd_arch_sysarch(CPUX86State *env, int op,
+        abi_ulong parms)
+{
+    abi_long ret = 0;
+    abi_ulong val;
+    int idx;
+
+    switch (op) {
+    case TARGET_FREEBSD_AMD64_SET_GSBASE:
+    case TARGET_FREEBSD_AMD64_SET_FSBASE:
+        if (op == TARGET_FREEBSD_AMD64_SET_GSBASE) {
+            idx = R_GS;
+        } else {
+            idx = R_FS;
+        }
+        if (get_user(val, parms, abi_ulong)) {
+            return -TARGET_EFAULT;
+        }
+        cpu_x86_load_seg(env, idx, 0);
+        env->segs[idx].base = val;
+        break;
+
+    case TARGET_FREEBSD_AMD64_GET_GSBASE:
+    case TARGET_FREEBSD_AMD64_GET_FSBASE:
+        if (op == TARGET_FREEBSD_AMD64_GET_GSBASE) {
+            idx = R_GS;
+        } else {
+            idx = R_FS;
+        }
+        val = env->segs[idx].base;
+        if (put_user(val, parms, abi_ulong)) {
+            return -TARGET_EFAULT;
+        }
+        break;
+
+    /* XXX handle the others... */
+    default:
+        ret = -TARGET_EINVAL;
+        break;
+    }
+    return ret;
+}
+
+#endif /*! __ARCH_SYSARCH_H_ */