Sfoglia il codice sorgente

bsd-user: FreeBSD update

basic FreeBSD sysarch(2) handling
fixed syscall errno return

Signed-off-by: Juergen Lock <nox@jelal.kn-bremen.de>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Juergen Lock 16 anni fa
parent
commit
78cfb07fe0

+ 9 - 1
bsd-user/elfload.c

@@ -126,6 +126,9 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
     regs->rax = 0;
     regs->rax = 0;
     regs->rsp = infop->start_stack;
     regs->rsp = infop->start_stack;
     regs->rip = infop->entry;
     regs->rip = infop->entry;
+    if (bsd_type == target_freebsd) {
+        regs->rdi = infop->start_stack;
+    }
 }
 }
 
 
 #else
 #else
@@ -249,8 +252,13 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
 #else
 #else
     if (personality(infop->personality) == PER_LINUX32)
     if (personality(infop->personality) == PER_LINUX32)
         regs->u_regs[14] = infop->start_stack - 16 * 4;
         regs->u_regs[14] = infop->start_stack - 16 * 4;
-    else
+    else {
         regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
         regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
+        if (bsd_type == target_freebsd) {
+            regs->u_regs[8] = infop->start_stack;
+            regs->u_regs[11] = infop->start_stack;
+        }
+    }
 #endif
 #endif
 }
 }
 
 

+ 1 - 0
bsd-user/freebsd/strace.list

@@ -39,6 +39,7 @@
 { TARGET_FREEBSD_NR_ftruncate, "ftruncate", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_ftruncate, "ftruncate", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_futimes, "futimes", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_futimes, "futimes", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_getdirentries, "getdirentries", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_getdirentries, "getdirentries", NULL, NULL, NULL },
+{ TARGET_FREEBSD_NR_freebsd6_mmap, "freebsd6_mmap", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_getegid, "getegid", "%s()", NULL, NULL },
 { TARGET_FREEBSD_NR_getegid, "getegid", "%s()", NULL, NULL },
 { TARGET_FREEBSD_NR_geteuid, "geteuid", "%s()", NULL, NULL },
 { TARGET_FREEBSD_NR_geteuid, "geteuid", "%s()", NULL, NULL },
 { TARGET_FREEBSD_NR_getfh, "getfh", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_getfh, "getfh", NULL, NULL, NULL },

+ 14 - 0
bsd-user/i386/syscall.h

@@ -143,5 +143,19 @@ struct target_vm86plus_struct {
 	struct target_vm86plus_info_struct vm86plus;
 	struct target_vm86plus_info_struct vm86plus;
 };
 };
 
 
+/* FreeBSD sysarch(2) */
+#define TARGET_FREEBSD_I386_GET_LDT	0
+#define TARGET_FREEBSD_I386_SET_LDT	1
+				/* I386_IOPL */
+#define TARGET_FREEBSD_I386_GET_IOPERM	3
+#define TARGET_FREEBSD_I386_SET_IOPERM	4
+				/* xxxxx */
+#define TARGET_FREEBSD_I386_VM86	6
+#define TARGET_FREEBSD_I386_GET_FSBASE	7
+#define TARGET_FREEBSD_I386_SET_FSBASE	8
+#define TARGET_FREEBSD_I386_GET_GSBASE	9
+#define TARGET_FREEBSD_I386_SET_GSBASE	10
+
+
 #define UNAME_MACHINE "i386"
 #define UNAME_MACHINE "i386"
 
 

+ 94 - 22
bsd-user/main.c

@@ -46,6 +46,7 @@ int have_guest_base;
 static const char *interp_prefix = CONFIG_QEMU_PREFIX;
 static const char *interp_prefix = CONFIG_QEMU_PREFIX;
 const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
 const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
 extern char **environ;
 extern char **environ;
+enum BSDType bsd_type;
 
 
 /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
 /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
    we allocate a bigger stack. Need a better solution, for example
    we allocate a bigger stack. Need a better solution, for example
@@ -168,7 +169,7 @@ static void set_idt(int n, unsigned int dpl)
 }
 }
 #endif
 #endif
 
 
-void cpu_loop(CPUX86State *env, enum BSDType bsd_type)
+void cpu_loop(CPUX86State *env)
 {
 {
     int trapnr;
     int trapnr;
     abi_ulong pc;
     abi_ulong pc;
@@ -179,27 +180,90 @@ void cpu_loop(CPUX86State *env, enum BSDType bsd_type)
         switch(trapnr) {
         switch(trapnr) {
         case 0x80:
         case 0x80:
             /* syscall from int $0x80 */
             /* syscall from int $0x80 */
-            env->regs[R_EAX] = do_openbsd_syscall(env,
-                                                  env->regs[R_EAX],
-                                                  env->regs[R_EBX],
-                                                  env->regs[R_ECX],
-                                                  env->regs[R_EDX],
-                                                  env->regs[R_ESI],
-                                                  env->regs[R_EDI],
-                                                  env->regs[R_EBP]);
+            if (bsd_type == target_freebsd) {
+                abi_ulong params = (abi_ulong) env->regs[R_ESP] +
+                    sizeof(int32_t);
+                int32_t syscall_nr = env->regs[R_EAX];
+                int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
+
+                if (syscall_nr == TARGET_FREEBSD_NR_syscall) {
+                    get_user_s32(syscall_nr, params);
+                    params += sizeof(int32_t);
+                } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) {
+                    get_user_s32(syscall_nr, params);
+                    params += sizeof(int64_t);
+                }
+                get_user_s32(arg1, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg2, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg3, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg4, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg5, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg6, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg7, params);
+                params += sizeof(int32_t);
+                get_user_s32(arg8, params);
+                env->regs[R_EAX] = do_freebsd_syscall(env,
+                                                      syscall_nr,
+                                                      arg1,
+                                                      arg2,
+                                                      arg3,
+                                                      arg4,
+                                                      arg5,
+                                                      arg6,
+                                                      arg7,
+                                                      arg8);
+            } else { //if (bsd_type == target_openbsd)
+                env->regs[R_EAX] = do_openbsd_syscall(env,
+                                                      env->regs[R_EAX],
+                                                      env->regs[R_EBX],
+                                                      env->regs[R_ECX],
+                                                      env->regs[R_EDX],
+                                                      env->regs[R_ESI],
+                                                      env->regs[R_EDI],
+                                                      env->regs[R_EBP]);
+            }
+            if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
+                env->regs[R_EAX] = -env->regs[R_EAX];
+                env->eflags |= CC_C;
+            } else {
+                env->eflags &= ~CC_C;
+            }
             break;
             break;
 #ifndef TARGET_ABI32
 #ifndef TARGET_ABI32
         case EXCP_SYSCALL:
         case EXCP_SYSCALL:
-            /* linux syscall from syscall intruction */
-            env->regs[R_EAX] = do_openbsd_syscall(env,
-                                                  env->regs[R_EAX],
-                                                  env->regs[R_EDI],
-                                                  env->regs[R_ESI],
-                                                  env->regs[R_EDX],
-                                                  env->regs[10],
-                                                  env->regs[8],
-                                                  env->regs[9]);
+            /* syscall from syscall intruction */
+            if (bsd_type == target_freebsd)
+                env->regs[R_EAX] = do_freebsd_syscall(env,
+                                                      env->regs[R_EAX],
+                                                      env->regs[R_EDI],
+                                                      env->regs[R_ESI],
+                                                      env->regs[R_EDX],
+                                                      env->regs[R_ECX],
+                                                      env->regs[8],
+                                                      env->regs[9], 0, 0);
+            else { //if (bsd_type == target_openbsd)
+                env->regs[R_EAX] = do_openbsd_syscall(env,
+                                                      env->regs[R_EAX],
+                                                      env->regs[R_EDI],
+                                                      env->regs[R_ESI],
+                                                      env->regs[R_EDX],
+                                                      env->regs[10],
+                                                      env->regs[8],
+                                                      env->regs[9]);
+            }
             env->eip = env->exception_next_eip;
             env->eip = env->exception_next_eip;
+            if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
+                env->regs[R_EAX] = -env->regs[R_EAX];
+                env->eflags |= CC_C;
+            } else {
+                env->eflags &= ~CC_C;
+            }
             break;
             break;
 #endif
 #endif
 #if 0
 #if 0
@@ -446,7 +510,7 @@ static void flush_windows(CPUSPARCState *env)
 #endif
 #endif
 }
 }
 
 
-void cpu_loop(CPUSPARCState *env, enum BSDType bsd_type)
+void cpu_loop(CPUSPARCState *env)
 {
 {
     int trapnr, ret, syscall_nr;
     int trapnr, ret, syscall_nr;
     //target_siginfo_t info;
     //target_siginfo_t info;
@@ -458,6 +522,10 @@ void cpu_loop(CPUSPARCState *env, enum BSDType bsd_type)
 #ifndef TARGET_SPARC64
 #ifndef TARGET_SPARC64
         case 0x80:
         case 0x80:
 #else
 #else
+        /* FreeBSD uses 0x141 for syscalls too */
+        case 0x141:
+            if (bsd_type != target_freebsd)
+                goto badtrap;
         case 0x100:
         case 0x100:
 #endif
 #endif
             syscall_nr = env->gregs[1];
             syscall_nr = env->gregs[1];
@@ -465,7 +533,7 @@ void cpu_loop(CPUSPARCState *env, enum BSDType bsd_type)
                 ret = do_freebsd_syscall(env, syscall_nr,
                 ret = do_freebsd_syscall(env, syscall_nr,
                                          env->regwptr[0], env->regwptr[1],
                                          env->regwptr[0], env->regwptr[1],
                                          env->regwptr[2], env->regwptr[3],
                                          env->regwptr[2], env->regwptr[3],
-                                         env->regwptr[4], env->regwptr[5]);
+                                         env->regwptr[4], env->regwptr[5], 0, 0);
             else if (bsd_type == target_netbsd)
             else if (bsd_type == target_netbsd)
                 ret = do_netbsd_syscall(env, syscall_nr,
                 ret = do_netbsd_syscall(env, syscall_nr,
                                         env->regwptr[0], env->regwptr[1],
                                         env->regwptr[0], env->regwptr[1],
@@ -482,6 +550,7 @@ void cpu_loop(CPUSPARCState *env, enum BSDType bsd_type)
                                          env->regwptr[4], env->regwptr[5]);
                                          env->regwptr[4], env->regwptr[5]);
             }
             }
             if ((unsigned int)ret >= (unsigned int)(-515)) {
             if ((unsigned int)ret >= (unsigned int)(-515)) {
+                ret = -ret;
 #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
 #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
                 env->xcc |= PSR_CARRY;
                 env->xcc |= PSR_CARRY;
 #else
 #else
@@ -587,6 +656,9 @@ void cpu_loop(CPUSPARCState *env, enum BSDType bsd_type)
             }
             }
             break;
             break;
         default:
         default:
+#ifdef TARGET_SPARC64
+        badtrap:
+#endif
             printf ("Unhandled trap: 0x%x\n", trapnr);
             printf ("Unhandled trap: 0x%x\n", trapnr);
             cpu_dump_state(env, stderr, fprintf, 0);
             cpu_dump_state(env, stderr, fprintf, 0);
             exit (1);
             exit (1);
@@ -668,7 +740,7 @@ int main(int argc, char **argv)
     int gdbstub_port = 0;
     int gdbstub_port = 0;
     char **target_environ, **wrk;
     char **target_environ, **wrk;
     envlist_t *envlist = NULL;
     envlist_t *envlist = NULL;
-    enum BSDType bsd_type = target_openbsd;
+    bsd_type = target_openbsd;
 
 
     if (argc <= 1)
     if (argc <= 1)
         usage();
         usage();
@@ -1033,7 +1105,7 @@ int main(int argc, char **argv)
         gdbserver_start (gdbstub_port);
         gdbserver_start (gdbstub_port);
         gdb_handlesig(env, 0);
         gdb_handlesig(env, 0);
     }
     }
-    cpu_loop(env, bsd_type);
+    cpu_loop(env);
     /* never exits */
     /* never exits */
     return 0;
     return 0;
 }
 }

+ 4 - 2
bsd-user/qemu.h

@@ -18,6 +18,7 @@ enum BSDType {
     target_netbsd,
     target_netbsd,
     target_openbsd,
     target_openbsd,
 };
 };
+extern enum BSDType bsd_type;
 
 
 #include "syscall_defs.h"
 #include "syscall_defs.h"
 #include "syscall.h"
 #include "syscall.h"
@@ -130,7 +131,8 @@ abi_long do_brk(abi_ulong new_brk);
 void syscall_init(void);
 void syscall_init(void);
 abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
 abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
                             abi_long arg2, abi_long arg3, abi_long arg4,
                             abi_long arg2, abi_long arg3, abi_long arg4,
-                            abi_long arg5, abi_long arg6);
+                            abi_long arg5, abi_long arg6, abi_long arg7,
+                            abi_long arg8);
 abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
 abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1,
                            abi_long arg2, abi_long arg3, abi_long arg4,
                            abi_long arg2, abi_long arg3, abi_long arg4,
                            abi_long arg5, abi_long arg6);
                            abi_long arg5, abi_long arg6);
@@ -139,7 +141,7 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1,
                             abi_long arg5, abi_long arg6);
                             abi_long arg5, abi_long arg6);
 void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2)));
 void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2)));
 extern THREAD CPUState *thread_env;
 extern THREAD CPUState *thread_env;
-void cpu_loop(CPUState *env, enum BSDType bsd_type);
+void cpu_loop(CPUState *env);
 char *target_strerror(int err);
 char *target_strerror(int err);
 int get_osversion(void);
 int get_osversion(void);
 void fork_start(void);
 void fork_start(void);

+ 291 - 4
bsd-user/syscall.c

@@ -29,6 +29,7 @@
 #include <sys/types.h>
 #include <sys/types.h>
 #include <sys/mman.h>
 #include <sys/mman.h>
 #include <sys/syscall.h>
 #include <sys/syscall.h>
+#include <sys/sysctl.h>
 #include <signal.h>
 #include <signal.h>
 #include <utime.h>
 #include <utime.h>
 
 
@@ -40,20 +41,283 @@
 static abi_ulong target_brk;
 static abi_ulong target_brk;
 static abi_ulong target_original_brk;
 static abi_ulong target_original_brk;
 
 
-#define get_errno(x) (x)
+static inline abi_long get_errno(abi_long ret)
+{
+    if (ret == -1)
+        /* XXX need to translate host -> target errnos here */
+        return -(errno);
+    else
+        return ret;
+}
+
 #define target_to_host_bitmask(x, tbl) (x)
 #define target_to_host_bitmask(x, tbl) (x)
 
 
+static inline int is_error(abi_long ret)
+{
+    return (abi_ulong)ret >= (abi_ulong)(-4096);
+}
+
 void target_set_brk(abi_ulong new_brk)
 void target_set_brk(abi_ulong new_brk)
 {
 {
     target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
     target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
 }
 }
 
 
+/* do_obreak() must return target errnos. */
+static abi_long do_obreak(abi_ulong new_brk)
+{
+    abi_ulong brk_page;
+    abi_long mapped_addr;
+    int new_alloc_size;
+
+    if (!new_brk)
+        return 0;
+    if (new_brk < target_original_brk)
+        return -TARGET_EINVAL;
+
+    brk_page = HOST_PAGE_ALIGN(target_brk);
+
+    /* If the new brk is less than this, set it and we're done... */
+    if (new_brk < brk_page) {
+        target_brk = new_brk;
+        return 0;
+    }
+
+    /* We need to allocate more memory after the brk... */
+    new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1);
+    mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
+                                        PROT_READ|PROT_WRITE,
+                                        MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0));
+
+    if (!is_error(mapped_addr))
+        target_brk = new_brk;
+    else
+        return mapped_addr;
+
+    return 0;
+}
+
+#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_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
+    case CTLTYPE_QUAD:
+        *(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 = qemu_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);
+    qemu_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.
+ */
+static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr,
+                           int count, int copy)
+{
+    struct target_iovec *target_vec;
+    abi_ulong base;
+    int i;
+
+    target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
+    if (!target_vec)
+        return -TARGET_EFAULT;
+    for(i = 0;i < count; i++) {
+        base = tswapl(target_vec[i].iov_base);
+        vec[i].iov_len = tswapl(target_vec[i].iov_len);
+        if (vec[i].iov_len != 0) {
+            vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy);
+            /* Don't check lock_user return value. We must call writev even
+               if a element has invalid base address. */
+        } else {
+            /* zero length pointer is ignored */
+            vec[i].iov_base = NULL;
+        }
+    }
+    unlock_user (target_vec, target_addr, 0);
+    return 0;
+}
+
+static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr,
+                             int count, int copy)
+{
+    struct target_iovec *target_vec;
+    abi_ulong base;
+    int i;
+
+    target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1);
+    if (!target_vec)
+        return -TARGET_EFAULT;
+    for(i = 0;i < count; i++) {
+        if (target_vec[i].iov_base) {
+            base = tswapl(target_vec[i].iov_base);
+            unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
+        }
+    }
+    unlock_user (target_vec, target_addr, 0);
+
+    return 0;
+}
+
 /* do_syscall() should always have a single exit point at the end so
 /* do_syscall() should always have a single exit point at the end so
    that actions, such as logging of syscall results, can be performed.
    that actions, such as logging of syscall results, can be performed.
    All errnos that do_syscall() returns must be -TARGET_<errcode>. */
    All errnos that do_syscall() returns must be -TARGET_<errcode>. */
 abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
 abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
                             abi_long arg2, abi_long arg3, abi_long arg4,
                             abi_long arg2, abi_long arg3, abi_long arg4,
-                            abi_long arg5, abi_long arg6)
+                            abi_long arg5, abi_long arg6, abi_long arg7,
+                            abi_long arg8)
 {
 {
     abi_long ret;
     abi_long ret;
     void *p;
     void *p;
@@ -86,6 +350,18 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
         ret = get_errno(write(arg1, p, arg3));
         ret = get_errno(write(arg1, p, arg3));
         unlock_user(p, arg2, 0);
         unlock_user(p, arg2, 0);
         break;
         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);
+        }
+        break;
     case TARGET_FREEBSD_NR_open:
     case TARGET_FREEBSD_NR_open:
         if (!(p = lock_user_string(arg1)))
         if (!(p = lock_user_string(arg1)))
             goto efault;
             goto efault;
@@ -103,12 +379,23 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
     case TARGET_FREEBSD_NR_mprotect:
     case TARGET_FREEBSD_NR_mprotect:
         ret = get_errno(target_mprotect(arg1, arg2, arg3));
         ret = get_errno(target_mprotect(arg1, arg2, arg3));
         break;
         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);
+        break;
+#endif
+    case TARGET_FREEBSD_NR_sysarch:
+        ret = do_freebsd_sysarch(cpu_env, arg1, arg2);
+        break;
     case TARGET_FREEBSD_NR_syscall:
     case TARGET_FREEBSD_NR_syscall:
     case TARGET_FREEBSD_NR___syscall:
     case TARGET_FREEBSD_NR___syscall:
-        ret = do_freebsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0);
+        ret = do_freebsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,arg7,arg8,0);
         break;
         break;
     default:
     default:
-        ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
+        ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8));
         break;
         break;
     }
     }
  fail:
  fail:

+ 6 - 0
bsd-user/syscall_defs.h

@@ -106,3 +106,9 @@
 #include "freebsd/syscall_nr.h"
 #include "freebsd/syscall_nr.h"
 #include "netbsd/syscall_nr.h"
 #include "netbsd/syscall_nr.h"
 #include "openbsd/syscall_nr.h"
 #include "openbsd/syscall_nr.h"
+
+struct target_iovec {
+    abi_long iov_base;   /* Starting address */
+    abi_long iov_len;   /* Number of bytes */
+};
+

+ 18 - 0
bsd-user/x86_64/syscall.h

@@ -90,6 +90,24 @@ struct target_msqid64_ds {
 	abi_ulong  __unused5;
 	abi_ulong  __unused5;
 };
 };
 
 
+/* FreeBSD sysarch(2) */
+#define TARGET_FREEBSD_I386_GET_LDT	0
+#define TARGET_FREEBSD_I386_SET_LDT	1
+				/* I386_IOPL */
+#define TARGET_FREEBSD_I386_GET_IOPERM	3
+#define TARGET_FREEBSD_I386_SET_IOPERM	4
+				/* xxxxx */
+#define TARGET_FREEBSD_I386_GET_FSBASE	7
+#define TARGET_FREEBSD_I386_SET_FSBASE	8
+#define TARGET_FREEBSD_I386_GET_GSBASE	9
+#define TARGET_FREEBSD_I386_SET_GSBASE	10
+
+#define TARGET_FREEBSD_AMD64_GET_FSBASE	128
+#define TARGET_FREEBSD_AMD64_SET_FSBASE	129
+#define TARGET_FREEBSD_AMD64_GET_GSBASE	130
+#define TARGET_FREEBSD_AMD64_SET_GSBASE	131
+
+
 #define UNAME_MACHINE "x86_64"
 #define UNAME_MACHINE "x86_64"
 
 
 #define TARGET_ARCH_SET_GS 0x1001
 #define TARGET_ARCH_SET_GS 0x1001

+ 25 - 2
cpu-exec.c

@@ -805,6 +805,20 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
 # define TRAP_sig(context)    ((context)->uc_mcontext->es.trapno)
 # define TRAP_sig(context)    ((context)->uc_mcontext->es.trapno)
 # define ERROR_sig(context)   ((context)->uc_mcontext->es.err)
 # define ERROR_sig(context)   ((context)->uc_mcontext->es.err)
 # define MASK_sig(context)    ((context)->uc_sigmask)
 # define MASK_sig(context)    ((context)->uc_sigmask)
+#elif defined (__NetBSD__)
+# include <ucontext.h>
+
+# define EIP_sig(context)     ((context)->uc_mcontext.__gregs[_REG_EIP])
+# define TRAP_sig(context)    ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
+# define ERROR_sig(context)   ((context)->uc_mcontext.__gregs[_REG_ERR])
+# define MASK_sig(context)    ((context)->uc_sigmask)
+#elif defined (__FreeBSD__) || defined(__DragonFly__)
+# include <ucontext.h>
+
+# define EIP_sig(context)  (*((unsigned long*)&(context)->uc_mcontext.mc_eip))
+# define TRAP_sig(context)    ((context)->uc_mcontext.mc_trapno)
+# define ERROR_sig(context)   ((context)->uc_mcontext.mc_err)
+# define MASK_sig(context)    ((context)->uc_sigmask)
 #elif defined(__OpenBSD__)
 #elif defined(__OpenBSD__)
 # define EIP_sig(context)     ((context)->sc_eip)
 # define EIP_sig(context)     ((context)->sc_eip)
 # define TRAP_sig(context)    ((context)->sc_trapno)
 # define TRAP_sig(context)    ((context)->sc_trapno)
@@ -821,7 +835,9 @@ int cpu_signal_handler(int host_signum, void *pinfo,
                        void *puc)
                        void *puc)
 {
 {
     siginfo_t *info = pinfo;
     siginfo_t *info = pinfo;
-#if defined(__OpenBSD__)
+#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
+    ucontext_t *uc = puc;
+#elif defined(__OpenBSD__)
     struct sigcontext *uc = puc;
     struct sigcontext *uc = puc;
 #else
 #else
     struct ucontext *uc = puc;
     struct ucontext *uc = puc;
@@ -855,6 +871,13 @@ int cpu_signal_handler(int host_signum, void *pinfo,
 #define TRAP_sig(context)     ((context)->sc_trapno)
 #define TRAP_sig(context)     ((context)->sc_trapno)
 #define ERROR_sig(context)    ((context)->sc_err)
 #define ERROR_sig(context)    ((context)->sc_err)
 #define MASK_sig(context)     ((context)->sc_mask)
 #define MASK_sig(context)     ((context)->sc_mask)
+#elif defined (__FreeBSD__) || defined(__DragonFly__)
+#include <ucontext.h>
+
+#define PC_sig(context)  (*((unsigned long*)&(context)->uc_mcontext.mc_rip))
+#define TRAP_sig(context)     ((context)->uc_mcontext.mc_trapno)
+#define ERROR_sig(context)    ((context)->uc_mcontext.mc_err)
+#define MASK_sig(context)     ((context)->uc_sigmask)
 #else
 #else
 #define PC_sig(context)       ((context)->uc_mcontext.gregs[REG_RIP])
 #define PC_sig(context)       ((context)->uc_mcontext.gregs[REG_RIP])
 #define TRAP_sig(context)     ((context)->uc_mcontext.gregs[REG_TRAPNO])
 #define TRAP_sig(context)     ((context)->uc_mcontext.gregs[REG_TRAPNO])
@@ -867,7 +890,7 @@ int cpu_signal_handler(int host_signum, void *pinfo,
 {
 {
     siginfo_t *info = pinfo;
     siginfo_t *info = pinfo;
     unsigned long pc;
     unsigned long pc;
-#ifdef __NetBSD__
+#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
     ucontext_t *uc = puc;
     ucontext_t *uc = puc;
 #elif defined(__OpenBSD__)
 #elif defined(__OpenBSD__)
     struct sigcontext *uc = puc;
     struct sigcontext *uc = puc;