qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] Re: playing with qemu usermode emulation on FreeBSD...


From: Juergen Lock
Subject: Re: [Qemu-devel] Re: playing with qemu usermode emulation on FreeBSD...
Date: Sat, 17 Oct 2009 00:34:26 +0200
User-agent: Mutt/1.5.20 (2009-06-14)

On Wed, Oct 14, 2009 at 12:19:32AM +0200, Juergen Lock wrote:
> On Tue, Oct 13, 2009 at 12:20:58AM +0200, Juergen Lock wrote:
> > On Mon, Oct 12, 2009 at 10:55:24PM +0300, Blue Swirl wrote:
> > > On Mon, Oct 12, 2009 at 1:18 AM, Juergen Lock <address@hidden> wrote:
> > > > On Thu, Oct 08, 2009 at 12:05:49AM +0200, Juergen Lock wrote:
> > > >> I recently noticed there are x86 bsd-user targets now (yeah I totally
> > > >> missed those commits...) and now got it working a tiny little bit:
> > > >> I can run
> > > >>       qemu-x86_64 -bsd freebsd /rescue/echo foo bar
> > > >> here on FreeBSD 8/amd64 and it echoes foo bar as expected, but
> > > >> segfaults afterwards. :)  (in pthread_setcancelstate() invoked from
> > > >> a guest write() syscall, in case anyone is wondering.)  Other things
> > > >> I tried either exit with errors or segfault as well, and i386 hosts
> > > >> probably still don't work at all yet.  (qemu-i386 here on amd64 does
> > > >> at least something, but probably needs lock_user() treatment for all
> > > >> kinds of syscalls, I only tried adding that for sysctl so far.)
> > > >>
> > > >>  Anyway, here is an emulators/qemu-devel git head snapshot port
> > > >> update with my current patches (files/patch-bsd-user), feel free to
> > > >> test/debug/improve:
> > > >>       http://people.freebsd.org/~nox/qemu/qemu-devel-20091007.patch
> > > >> (For the folks reading this on the qemu list:  I shall start doing
> > > >> `proper' patch submissions later, this is more for the FreeBSD folks
> > > >> and because I was asked to send what I have...)
> > > >
> > > > New version at the same place, which now runs FreeBSD/{i386,sparc64}
> > > > /rescue/echo on FreeBSD/amd64, the FreeBSD/amd64 target now segfaults
> > > > in pthread_setcancelstate() invoked from the final writev() tho.
> > > > Oh and I also uploaded the snapshot tarball so others can now actually
> > > > build the port too... :)  And I have switched to the cpu-exec.c patch
> > > > posted by Aleksej Saushev on the qemu list and added back amd64
> > > > code there.
> > > >
> > > >  Here is the bsd-user patch again:
> > > 
> > > Please add Signed-off-by: line and use 'diff -u' (or preferably git diff).
> > > 
> > Well I wasn't expecting this diff to be committed just yet anyway,
> > it's still more a wip version...
> > 
> > > > +    if (1 /* bsd_type == target_freebsd */)
> > > > +        regs->rdi = infop->start_stack;
> > > 
> > > Why the if and comment?
> > > 
> > > > +        if (1 /* bsd_type == target_freebsd */) {
> > > > +            regs->u_regs[8] = infop->start_stack;
> > > > +            regs->u_regs[11] = infop->start_stack;
> > > 
> > > Same here.
> > > 
> >  Because bsd_type isn't available at these places in the code but
> > probably should be checked, I still wanted to fix that.  (Maybe
> > make it global?)
> > 
> I still haven't fixed this...
> 
> > > >         case 0x100:
> > > > +        /* FreeBSD uses 0x141 for syscalls too */
> > > > +        case 0x141:
> > > > +            if (bsd_type != target_freebsd)
> > > > +                goto badtrap;
> > > 
> > > You are now also trapping on case 0x100 if bsd_type != target_freebsd,
> > > which probably breaks other BSDs.
> > > 
> >  Right, thats broken, the 0x141 case should come before the 0x100
> > here of course.
> > 
>  ...but this I just fixed, and I added the multiboot.S patch, and
> fixed the port's cdrom dma disable knob (files/cdrom-dma-patch).
> (And I added the cpu-exec.c whitspace fix that was already in the
> patch I posted in the BSD support thread.)
> 
>  New version at the same place,
>       http://people.freebsd.org/~nox/qemu/qemu-devel-20091007.patch
> and I now also made a shar of the patched port:
>       http://people.freebsd.org/~nox/qemu/qemu-devel-20091007.shar

Updated again, among other things I added basic FreeBSD sysarch(2)
handling, fixed syscall errno return (I had added code to set the
carry bit for the x86 target before but the sign of the returned errno
was still wrong), and I finally fixed the if (1) above (made bsd_type
global.)

 And, I now can run FreeBSD/amd64 /bin/sh and vim on same! :)  (zsh
not yet tho.)

 Oh and Toni tested taking FreeBSD/i386's default linker script,
changing only the load address to 0x60000000 as in qemu's and,
using that as i386.ld, he now can run qemu-i386 on FreeBSD/i386 with
simple executables too...  See files/patch-bsd-user-ld in the shar,
which I also now moved the x86_64.ld patch to that I had talked about
earlier.  It probably can't be used everywhere as is tho since it has:
        OUTPUT_FORMAT("elf32-i386-freebsd", "elf32-i386-freebsd",
                      "elf32-i386-freebsd")
(and I also don't know if the one currently in the tree has other
features that are needed at least on Linux, any linker gurus care
to comment?)

 Here is the rest of the bsd-user patches again (files/patch-bsd-user
in the shar), if you think they are ready to commit I'm not against it
anymore :), comments are also welcome of course.

 Thanx,
        Juergen

--- a/bsd-user/elfload.c
+++ b/bsd-user/elfload.c
@@ -126,6 +126,9 @@ static inline void init_thread(struct ta
     regs->rax = 0;
     regs->rsp = infop->start_stack;
     regs->rip = infop->entry;
+    if (bsd_type == target_freebsd) {
+        regs->rdi = infop->start_stack;
+    }
 }
 
 #else
@@ -249,8 +252,13 @@ static inline void init_thread(struct ta
 #else
     if (personality(infop->personality) == PER_LINUX32)
         regs->u_regs[14] = infop->start_stack - 16 * 4;
-    else
+    else {
         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
 }
 
--- a/bsd-user/freebsd/strace.list
+++ b/bsd-user/freebsd/strace.list
@@ -39,6 +39,7 @@
 { TARGET_FREEBSD_NR_ftruncate, "ftruncate", NULL, NULL, NULL },
 { TARGET_FREEBSD_NR_futimes, "futimes", 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_geteuid, "geteuid", "%s()", NULL, NULL },
 { TARGET_FREEBSD_NR_getfh, "getfh", NULL, NULL, NULL },
--- a/bsd-user/i386/syscall.h
+++ b/bsd-user/i386/syscall.h
@@ -143,5 +143,19 @@ struct target_vm86plus_struct {
        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"
 
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -46,6 +46,7 @@ int have_guest_base;
 static const char *interp_prefix = CONFIG_QEMU_PREFIX;
 const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
 extern char **environ;
+enum BSDType bsd_type;
 
 /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
    we allocate a bigger stack. Need a better solution, for example
@@ -168,7 +169,7 @@ static void set_idt(int n, unsigned int 
 }
 #endif
 
-void cpu_loop(CPUX86State *env, enum BSDType bsd_type)
+void cpu_loop(CPUX86State *env)
 {
     int trapnr;
     abi_ulong pc;
@@ -179,27 +180,90 @@ void cpu_loop(CPUX86State *env, enum BSD
         switch(trapnr) {
         case 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;
 #ifndef TARGET_ABI32
         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;
+            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;
 #endif
 #if 0
@@ -446,7 +510,7 @@ static void flush_windows(CPUSPARCState 
 #endif
 }
 
-void cpu_loop(CPUSPARCState *env, enum BSDType bsd_type)
+void cpu_loop(CPUSPARCState *env)
 {
     int trapnr, ret, syscall_nr;
     //target_siginfo_t info;
@@ -458,6 +522,10 @@ void cpu_loop(CPUSPARCState *env, enum B
 #ifndef TARGET_SPARC64
         case 0x80:
 #else
+        /* FreeBSD uses 0x141 for syscalls too */
+        case 0x141:
+            if (bsd_type != target_freebsd)
+                goto badtrap;
         case 0x100:
 #endif
             syscall_nr = env->gregs[1];
@@ -465,7 +533,7 @@ void cpu_loop(CPUSPARCState *env, enum B
                 ret = do_freebsd_syscall(env, syscall_nr,
                                          env->regwptr[0], env->regwptr[1],
                                          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)
                 ret = do_netbsd_syscall(env, syscall_nr,
                                         env->regwptr[0], env->regwptr[1],
@@ -482,6 +550,7 @@ void cpu_loop(CPUSPARCState *env, enum B
                                          env->regwptr[4], env->regwptr[5]);
             }
             if ((unsigned int)ret >= (unsigned int)(-515)) {
+                ret = -ret;
 #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
                 env->xcc |= PSR_CARRY;
 #else
@@ -587,6 +656,9 @@ void cpu_loop(CPUSPARCState *env, enum B
             }
             break;
         default:
+#ifdef TARGET_SPARC64
+        badtrap:
+#endif
             printf ("Unhandled trap: 0x%x\n", trapnr);
             cpu_dump_state(env, stderr, fprintf, 0);
             exit (1);
@@ -668,7 +740,7 @@ int main(int argc, char **argv)
     int gdbstub_port = 0;
     char **target_environ, **wrk;
     envlist_t *envlist = NULL;
-    enum BSDType bsd_type = target_openbsd;
+    bsd_type = target_openbsd;
 
     if (argc <= 1)
         usage();
@@ -1033,7 +1105,7 @@ int main(int argc, char **argv)
         gdbserver_start (gdbstub_port);
         gdb_handlesig(env, 0);
     }
-    cpu_loop(env, bsd_type);
+    cpu_loop(env);
     /* never exits */
     return 0;
 }
--- a/bsd-user/qemu.h
+++ b/bsd-user/qemu.h
@@ -18,6 +18,7 @@ enum BSDType {
     target_netbsd,
     target_openbsd,
 };
+extern enum BSDType bsd_type;
 
 #include "syscall_defs.h"
 #include "syscall.h"
@@ -130,7 +131,8 @@ abi_long do_brk(abi_ulong new_brk);
 void syscall_init(void);
 abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1,
                             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 arg2, abi_long arg3, abi_long arg4,
                            abi_long arg5, abi_long arg6);
@@ -139,7 +141,7 @@ abi_long do_openbsd_syscall(void *cpu_en
                             abi_long arg5, abi_long arg6);
 void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2)));
 extern THREAD CPUState *thread_env;
-void cpu_loop(CPUState *env, enum BSDType bsd_type);
+void cpu_loop(CPUState *env);
 char *target_strerror(int err);
 int get_osversion(void);
 void fork_start(void);
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -29,6 +29,7 @@
 #include <sys/types.h>
 #include <sys/mman.h>
 #include <sys/syscall.h>
+#include <sys/sysctl.h>
 #include <signal.h>
 #include <utime.h>
 
@@ -40,20 +41,283 @@
 static abi_ulong target_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)
 
+static inline int is_error(abi_long ret)
+{
+    return (abi_ulong)ret >= (abi_ulong)(-4096);
+}
+
 void target_set_brk(abi_ulong 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
    that actions, such as logging of syscall results, can be performed.
    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 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;
     void *p;
@@ -86,6 +350,18 @@ abi_long do_freebsd_syscall(void *cpu_en
         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);
+        }
+        break;
     case TARGET_FREEBSD_NR_open:
         if (!(p = lock_user_string(arg1)))
             goto efault;
@@ -103,12 +379,23 @@ abi_long do_freebsd_syscall(void *cpu_en
     case TARGET_FREEBSD_NR_mprotect:
         ret = get_errno(target_mprotect(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);
+        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:
-        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;
     default:
-        ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
+        ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, 
arg8));
         break;
     }
  fail:
--- a/bsd-user/syscall_defs.h
+++ b/bsd-user/syscall_defs.h
@@ -106,3 +106,9 @@
 #include "freebsd/syscall_nr.h"
 #include "netbsd/syscall_nr.h"
 #include "openbsd/syscall_nr.h"
+
+struct target_iovec {
+    abi_long iov_base;   /* Starting address */
+    abi_long iov_len;   /* Number of bytes */
+};
+
--- a/bsd-user/x86_64/syscall.h
+++ b/bsd-user/x86_64/syscall.h
@@ -90,6 +90,24 @@ struct target_msqid64_ds {
        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 TARGET_ARCH_SET_GS 0x1001
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -805,6 +805,20 @@ static inline int handle_cpu_signal(unsi
 # define TRAP_sig(context)    ((context)->uc_mcontext->es.trapno)
 # define ERROR_sig(context)   ((context)->uc_mcontext->es.err)
 # 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__)
 # define EIP_sig(context)     ((context)->sc_eip)
 # define TRAP_sig(context)    ((context)->sc_trapno)
@@ -821,7 +835,9 @@ int cpu_signal_handler(int host_signum, 
                        void *puc)
 {
     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;
 #else
     struct ucontext *uc = puc;
@@ -855,6 +871,13 @@ int cpu_signal_handler(int host_signum, 
 #define TRAP_sig(context)     ((context)->sc_trapno)
 #define ERROR_sig(context)    ((context)->sc_err)
 #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
 #define PC_sig(context)       ((context)->uc_mcontext.gregs[REG_RIP])
 #define TRAP_sig(context)     ((context)->uc_mcontext.gregs[REG_TRAPNO])
@@ -867,7 +890,7 @@ int cpu_signal_handler(int host_signum, 
 {
     siginfo_t *info = pinfo;
     unsigned long pc;
-#ifdef __NetBSD__
+#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
     ucontext_t *uc = puc;
 #elif defined(__OpenBSD__)
     struct sigcontext *uc = puc;

 Signed-off-by: Juergen Lock <address@hidden>




reply via email to

[Prev in Thread] Current Thread [Next in Thread]