qemu-devel
[Top][All Lists]
Advanced

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

Re: [Qemu-devel] [4616] NPTL host detection and futex syscall passthroug


From: Stuart Anderson
Subject: Re: [Qemu-devel] [4616] NPTL host detection and futex syscall passthrough.
Date: Thu, 29 May 2008 11:00:35 -0400 (EDT)

On Thu, 29 May 2008, Paul Brook wrote:

Revision: 4616
         http://svn.sv.gnu.org/viewvc/?view=rev&root=qemu&revision=4616
Author:   pbrook
Date:     2008-05-29 14:34:11 +0000 (Thu, 29 May 2008)

Log Message:
-----------
NPTL host detection and futex syscall passthrough.


I'm glad to see this (and the recent TLS) patches make it in finally!

This patch however doesn't handle private futexes which we're now seeing
in the field, nor does it handle byte swaping as is needed for certain
host/target combinations.

Here is the patch that we've been using for a while now. I'll eventually
be able to resync w/ current svn, and send an updated patch to the list,
but it may be awhile so I'm just sending what I've got in case someone
else can get to it before I do.


Author: Stuart R. Anderson <address@hidden>

    This patch provides an implementation for the futex() syscall.

Index: olmec-qemu/linux-user/syscall.c
===================================================================
--- olmec-qemu.orig/linux-user/syscall.c
+++ olmec-qemu/linux-user/syscall.c
@@ -17,6 +17,8 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
+
+#define __user
 #include <stddef.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -61,6 +63,7 @@
 #define tchars host_tchars /* same as target */
 #define ltchars host_ltchars /* same as target */

+#include <linux/futex.h>
 #include <linux/termios.h>
 #include <linux/unistd.h>
 #include <linux/utsname.h>
@@ -3310,6 +3313,114 @@
     return 0;
 }

+#if defined(TARGET_NR_futex)
+#ifdef BSWAP_NEEDED
+static int futex_op(int oldval, int op, int oparg)
+{
+    int retval = oparg;
+    switch(op) {
+        case FUTEX_OP_SET: break;
+        case FUTEX_OP_ADD: retval += oparg; break;
+        case FUTEX_OP_OR: retval |= oparg; break;
+        case FUTEX_OP_ANDN: retval &= oparg; break;
+        case FUTEX_OP_XOR: retval ^= oparg; break;
+    }
+    return retval;
+}
+
+static int futex_cmp(int oldval, int cmp, int cmparg)
+{
+    switch(cmp) {
+        case FUTEX_OP_CMP_EQ: return oldval == cmparg;
+        case FUTEX_OP_CMP_NE: return oldval != cmparg;
+        case FUTEX_OP_CMP_LT: return oldval <  cmparg;
+        case FUTEX_OP_CMP_LE: return oldval <= cmparg;
+        case FUTEX_OP_CMP_GT: return oldval >  cmparg;
+        case FUTEX_OP_CMP_GE: return oldval >= cmparg;
+    }
+    return -1;
+}
+#endif
+
+#if !defined(FUTEX_PRIVATE_FLAG)
+#define FUTEX_PRIVATE_FLAG      128
+#define FUTEX_CMD_MASK          ~FUTEX_PRIVATE_FLAG
+
+#define FUTEX_WAIT_PRIVATE      (FUTEX_WAIT | FUTEX_PRIVATE_FLAG)
+#define FUTEX_WAKE_PRIVATE      (FUTEX_WAKE | FUTEX_PRIVATE_FLAG)
+#define FUTEX_REQUEUE_PRIVATE   (FUTEX_REQUEUE | FUTEX_PRIVATE_FLAG)
+#define FUTEX_CMP_REQUEUE_PRIVATE (FUTEX_CMP_REQUEUE | FUTEX_PRIVATE_FLAG)
+#define FUTEX_WAKE_OP_PRIVATE   (FUTEX_WAKE_OP | FUTEX_PRIVATE_FLAG)
+#define FUTEX_LOCK_PI_PRIVATE   (FUTEX_LOCK_PI | FUTEX_PRIVATE_FLAG)
+#define FUTEX_UNLOCK_PI_PRIVATE (FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG)
+#define FUTEX_TRYLOCK_PI_PRIVATE (FUTEX_TRYLOCK_PI | FUTEX_PRIVATE_FLAG)
+#endif
+
+static abi_long do_futex(abi_ulong uaddr, int op, uint32_t val,
+                         abi_ulong utime, abi_ulong uaddr2,
+                         uint32_t val3)
+{
+    struct timespec host_utime;
+    unsigned long val2 = utime;
+    long retval;
+
+    if (utime && ((op&FUTEX_CMD_MASK) == FUTEX_WAIT || (op&FUTEX_CMD_MASK) == 
FUTEX_LOCK_PI)) {
+        if (target_to_host_timespec(&host_utime, utime))
+            return -TARGET_EFAULT;
+        val2 = (unsigned long)&host_utime;
+    }
+
+#ifdef BSWAP_NEEDED
+    switch(op&FUTEX_CMD_MASK) {
+    case FUTEX_CMP_REQUEUE:
+        val3 = tswap32(val3);
+    case FUTEX_REQUEUE:
+        val2 = tswap32(val2);
+    case FUTEX_WAIT:
+    case FUTEX_WAKE:
+    case FUTEX_WAKE_OP:
+        val = tswap32(val);
+    case FUTEX_LOCK_PI: /* This one's icky, but comes out OK */
+    case FUTEX_UNLOCK_PI:
+        break;
+    default:
+        gemu_log("qemu: Unsupported futex op %d\n", op);
+        return -ENOSYS;
+    }
+    if ((op&FUTEX_CMD_MASK) == FUTEX_WAKE_OP) {
+        /* Need to munge the secondary operation (val3) */
+        gemu_log("qemu: Tricky FUTEX_WAKE_OP - trying to emulate it\n");
+        val3 = tswap32(val3);
+        int op2 = (val3 >> 28) & 0xf;
+        int cmp = (val3 >> 24) & 0xf;
+        int oparg = (val3 >> 12) & 0xfff;
+        int cmparg = val3 & 0xfff;
+        int shift = val3 & (FUTEX_OP_OPARG_SHIFT << 28);
+        int oldval;
+
+        if (get_user_s32(oldval, uaddr2))
+            return -TARGET_EFAULT;
+
+        if (shift)
+            oparg = 1 << oparg;
+
+        if (put_user_s32(futex_op(oldval, op2, oparg), uaddr2))
+            return -TARGET_EFAULT;
+
+        retval = syscall(__NR_futex, g2h(uaddr), op, val, 0, 0, 0);
+        if(futex_cmp(oldval, cmp, cmparg)) {
+            retval = syscall(__NR_futex, g2h(uaddr2), op, val2, 0, 0, 0);
+        }
+    } else {
+        retval = syscall(__NR_futex, g2h(uaddr), op, val, val2, g2h(uaddr2), 
val3);
+    }
+#else
+    retval = syscall(__NR_futex, g2h(uaddr), op, val, val2, g2h(uaddr2), val3);
+#endif
+    return retval;
+}
+#endif /* defined(TARGET_NR_futex) */
+
 /* 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>. */
@@ -5792,6 +5903,11 @@
     }
 #endif

+#ifdef TARGET_NR_futex
+    case TARGET_NR_futex:
+        ret = get_errno(do_futex(arg1, arg2, arg3, arg4, arg5, arg6));
+        break;
+#endif
 #if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
     case TARGET_NR_set_tid_address:
         ret = get_errno(set_tid_address((int *)g2h(arg1)));


                                Stuart

Stuart R. Anderson                               address@hidden
Network & Software Engineering                   http://www.netsweng.com/
1024D/37A79149:                                  0791 D3B8 9A4C 2CDC A31F
                                                 BD03 0A62 E534 37A7 9149




reply via email to

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