Index: qemu.bkp/linux-user/syscall.c =================================================================== --- qemu.bkp.orig/linux-user/syscall.c +++ qemu.bkp/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 @@ -60,6 +62,7 @@ #define tchars host_tchars /* same as target */ #define ltchars host_ltchars /* same as target */ +#include #include #include #include @@ -2554,6 +2557,91 @@ static inline void host_to_target_timesp unlock_user_struct(target_ts, target_addr, 1); } +#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 + +static long do_futex(target_ulong uaddr, int op, uint32_t val, + target_ulong utime, target_ulong uaddr2, + uint32_t val3) +{ + struct timespec host_utime; + unsigned long val2 = utime; + long retval; + + if (utime && (op == FUTEX_WAIT || op == FUTEX_LOCK_PI)) { + target_to_host_timespec(&host_utime, utime); + val2 = (unsigned long)&host_utime; + } + +#ifdef BSWAP_NEEDED + switch(op) { + 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_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 = tget32(uaddr2); + if (shift) + oparg = 1 << oparg; + + tput32(uaddr2,futex_op(oldval, op2, oparg)); + retval = syscall(__NR_futex, g2h(uaddr), FUTEX_WAKE, val, 0, 0, 0); + if(futex_cmp(oldval, cmp, cmparg)) { + retval = syscall(__NR_futex, g2h(uaddr2), FUTEX_WAKE, 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; +} + long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6) { @@ -4713,6 +4801,11 @@ long do_syscall(void *cpu_env, int num, } #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 *) arg1));