From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1K1jdS-0003uV-HR for qemu-devel@nongnu.org; Thu, 29 May 2008 11:01:46 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1K1jdO-0003tV-Ef for qemu-devel@nongnu.org; Thu, 29 May 2008 11:01:45 -0400 Received: from [199.232.76.173] (port=47165 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1K1jdO-0003tS-9O for qemu-devel@nongnu.org; Thu, 29 May 2008 11:01:42 -0400 Received: from grayson.netsweng.com ([207.235.77.11]:53684) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1K1jdN-0006rg-O3 for qemu-devel@nongnu.org; Thu, 29 May 2008 11:01:41 -0400 Received: from amavis by grayson.netsweng.com with scanned-ok (Exim 3.36 #1 (Debian)) id 1K1jd2-0006xD-00 for ; Thu, 29 May 2008 11:01:20 -0400 Received: from grayson.netsweng.com ([127.0.0.1]) by localhost (grayson.netsweng.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id b+6GW2Y2ygML for ; Thu, 29 May 2008 11:00:53 -0400 (EDT) Received: from h250.94.213.151.ip.alltel.net ([151.213.94.250] helo=trantor.stuart.netsweng.com) by grayson.netsweng.com with esmtp (Exim 3.36 #1 (Debian)) id 1K1jca-0006wR-00 for ; Thu, 29 May 2008 11:00:53 -0400 Date: Thu, 29 May 2008 11:00:35 -0400 (EDT) From: Stuart Anderson Subject: Re: [Qemu-devel] [4616] NPTL host detection and futex syscall passthrough. In-Reply-To: Message-ID: References: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII; format=flowed Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org 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 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 #include #include @@ -61,6 +63,7 @@ #define tchars host_tchars /* same as target */ #define ltchars host_ltchars /* same as target */ +#include #include #include #include @@ -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_. */ @@ -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 anderson@netsweng.com Network & Software Engineering http://www.netsweng.com/ 1024D/37A79149: 0791 D3B8 9A4C 2CDC A31F BD03 0A62 E534 37A7 9149