//#include <sys/user.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
+#if defined(USE_NPTL)
+#include <sys/futex.h>
+#endif
#define termios host_termios
#define winsize host_winsize
#include <linux/soundcard.h>
#include <linux/dirent.h>
#include <linux/kd.h>
+#include "linux_loop.h"
#include "qemu.h"
#define __NR_sys_tkill __NR_tkill
#define __NR_sys_unlinkat __NR_unlinkat
#define __NR_sys_utimensat __NR_utimensat
+#define __NR_sys_futex __NR_futex
#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__)
#define __NR__llseek __NR_lseek
_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
const struct timespec *,tsp,int,flags)
#endif
+#if defined(TARGET_NR_futex) && defined(__NR_futex)
+_syscall6(int,sys_futex,int *,uaddr,int,op,int,val,
+ const struct timespec *,timeout,int *,uaddr2,int,val3)
+
+#endif
extern int personality(int);
extern int flock(int, int);
if (!new_brk)
return target_brk;
if (new_brk < target_original_brk)
- return -TARGET_ENOMEM;
+ return target_brk;
brk_page = HOST_PAGE_ALIGN(target_brk);
mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
PROT_READ|PROT_WRITE,
MAP_ANON|MAP_FIXED|MAP_PRIVATE, 0, 0));
- if (is_error(mapped_addr)) {
- return mapped_addr;
- } else {
+
+ if (!is_error(mapped_addr))
target_brk = new_brk;
- return target_brk;
- }
+
+ return target_brk;
}
-static inline fd_set *target_to_host_fds(fd_set *fds,
- abi_long *target_fds, int n)
+static inline abi_long copy_from_user_fdset(fd_set *fds,
+ abi_ulong target_fds_addr,
+ int n)
{
-#if !defined(BSWAP_NEEDED) && !defined(WORDS_BIGENDIAN)
- return (fd_set *)target_fds;
-#else
- int i, b;
- if (target_fds) {
- FD_ZERO(fds);
- for(i = 0;i < n; i++) {
- b = (tswapl(target_fds[i / TARGET_ABI_BITS]) >>
- (i & (TARGET_ABI_BITS - 1))) & 1;
- if (b)
- FD_SET(i, fds);
+ int i, nw, j, k;
+ abi_ulong b, *target_fds;
+
+ nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
+ if (!(target_fds = lock_user(VERIFY_READ,
+ target_fds_addr,
+ sizeof(abi_ulong) * nw,
+ 1)))
+ return -TARGET_EFAULT;
+
+ FD_ZERO(fds);
+ k = 0;
+ for (i = 0; i < nw; i++) {
+ /* grab the abi_ulong */
+ __get_user(b, &target_fds[i]);
+ for (j = 0; j < TARGET_ABI_BITS; j++) {
+ /* check the bit inside the abi_ulong */
+ if ((b >> j) & 1)
+ FD_SET(k, fds);
+ k++;
}
- return fds;
- } else {
- return NULL;
}
-#endif
+
+ unlock_user(target_fds, target_fds_addr, 0);
+
+ return 0;
}
-static inline void host_to_target_fds(abi_long *target_fds,
- fd_set *fds, int n)
+static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr,
+ const fd_set *fds,
+ int n)
{
-#if !defined(BSWAP_NEEDED) && !defined(WORDS_BIGENDIAN)
- /* nothing to do */
-#else
int i, nw, j, k;
abi_long v;
+ abi_ulong *target_fds;
- if (target_fds) {
- nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
- k = 0;
- for(i = 0;i < nw; i++) {
- v = 0;
- for(j = 0; j < TARGET_ABI_BITS; j++) {
- v |= ((FD_ISSET(k, fds) != 0) << j);
- k++;
- }
- target_fds[i] = tswapl(v);
+ nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS;
+ if (!(target_fds = lock_user(VERIFY_WRITE,
+ target_fds_addr,
+ sizeof(abi_ulong) * nw,
+ 0)))
+ return -TARGET_EFAULT;
+
+ k = 0;
+ for (i = 0; i < nw; i++) {
+ v = 0;
+ for (j = 0; j < TARGET_ABI_BITS; j++) {
+ v |= ((FD_ISSET(k, fds) != 0) << j);
+ k++;
}
+ __put_user(v, &target_fds[i]);
}
-#endif
+
+ unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw);
+
+ return 0;
}
#if defined(__alpha__)
return 0;
}
-static inline abi_long target_to_host_timeval(struct timeval *tv,
- abi_ulong target_addr)
+static inline abi_long copy_from_user_timeval(struct timeval *tv,
+ abi_ulong target_tv_addr)
{
struct target_timeval *target_tv;
- if (!lock_user_struct(VERIFY_READ, target_tv, target_addr, 1))
+ if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1))
return -TARGET_EFAULT;
- tv->tv_sec = tswapl(target_tv->tv_sec);
- tv->tv_usec = tswapl(target_tv->tv_usec);
- unlock_user_struct(target_tv, target_addr, 0);
+
+ __get_user(tv->tv_sec, &target_tv->tv_sec);
+ __get_user(tv->tv_usec, &target_tv->tv_usec);
+
+ unlock_user_struct(target_tv, target_tv_addr, 0);
return 0;
}
-static inline abi_long host_to_target_timeval(abi_ulong target_addr,
- const struct timeval *tv)
+static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
+ const struct timeval *tv)
{
struct target_timeval *target_tv;
- if (!lock_user_struct(VERIFY_WRITE, target_tv, target_addr, 0))
+ if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0))
return -TARGET_EFAULT;
- target_tv->tv_sec = tswapl(tv->tv_sec);
- target_tv->tv_usec = tswapl(tv->tv_usec);
- unlock_user_struct(target_tv, target_addr, 1);
+
+ __put_user(tv->tv_sec, &target_tv->tv_sec);
+ __put_user(tv->tv_usec, &target_tv->tv_usec);
+
+ unlock_user_struct(target_tv, target_tv_addr, 1);
return 0;
}
/* do_select() must return target values and target errnos. */
static abi_long do_select(int n,
- abi_ulong rfd_p, abi_ulong wfd_p,
- abi_ulong efd_p, abi_ulong target_tv)
+ abi_ulong rfd_addr, abi_ulong wfd_addr,
+ abi_ulong efd_addr, abi_ulong target_tv_addr)
{
fd_set rfds, wfds, efds;
fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
- abi_long *target_rfds, *target_wfds, *target_efds;
struct timeval tv, *tv_ptr;
abi_long ret;
- int ok;
- if (rfd_p) {
- target_rfds = lock_user(VERIFY_WRITE, rfd_p, sizeof(abi_long) * n, 1);
- if (!target_rfds) {
- ret = -TARGET_EFAULT;
- goto end;
- }
- rfds_ptr = target_to_host_fds(&rfds, target_rfds, n);
+ if (rfd_addr) {
+ if (copy_from_user_fdset(&rfds, rfd_addr, n))
+ return -TARGET_EFAULT;
+ rfds_ptr = &rfds;
} else {
- target_rfds = NULL;
rfds_ptr = NULL;
}
- if (wfd_p) {
- target_wfds = lock_user(VERIFY_WRITE, wfd_p, sizeof(abi_long) * n, 1);
- if (!target_wfds) {
- ret = -TARGET_EFAULT;
- goto end;
- }
- wfds_ptr = target_to_host_fds(&wfds, target_wfds, n);
+ if (wfd_addr) {
+ if (copy_from_user_fdset(&wfds, wfd_addr, n))
+ return -TARGET_EFAULT;
+ wfds_ptr = &wfds;
} else {
- target_wfds = NULL;
wfds_ptr = NULL;
}
- if (efd_p) {
- target_efds = lock_user(VERIFY_WRITE, efd_p, sizeof(abi_long) * n, 1);
- if (!target_efds) {
- ret = -TARGET_EFAULT;
- goto end;
- }
- efds_ptr = target_to_host_fds(&efds, target_efds, n);
+ if (efd_addr) {
+ if (copy_from_user_fdset(&efds, efd_addr, n))
+ return -TARGET_EFAULT;
+ efds_ptr = &efds;
} else {
- target_efds = NULL;
efds_ptr = NULL;
}
- if (target_tv) {
- target_to_host_timeval(&tv, target_tv);
+ if (target_tv_addr) {
+ if (copy_from_user_timeval(&tv, target_tv_addr))
+ return -TARGET_EFAULT;
tv_ptr = &tv;
} else {
tv_ptr = NULL;
}
+
ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
- ok = !is_error(ret);
- if (ok) {
- host_to_target_fds(target_rfds, rfds_ptr, n);
- host_to_target_fds(target_wfds, wfds_ptr, n);
- host_to_target_fds(target_efds, efds_ptr, n);
+ if (!is_error(ret)) {
+ if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n))
+ return -TARGET_EFAULT;
+ if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n))
+ return -TARGET_EFAULT;
+ if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n))
+ return -TARGET_EFAULT;
- if (target_tv) {
- host_to_target_timeval(target_tv, &tv);
- }
+ if (target_tv_addr && copy_to_user_timeval(target_tv_addr, &tv))
+ return -TARGET_EFAULT;
}
-end:
- unlock_user(target_rfds, rfd_p, ok ? sizeof(abi_long) * n : 0);
- unlock_user(target_wfds, wfd_p, ok ? sizeof(abi_long) * n : 0);
- unlock_user(target_efds, efd_p, ok ? sizeof(abi_long) * n : 0);
-
return ret;
}
default:
unimplemented:
gemu_log("Unsupported setsockopt level=%d optname=%d \n", level, optname);
- ret = -TARGET_ENOSYS;
+ ret = -TARGET_ENOPROTOOPT;
}
return ret;
}
}
break;
default:
- goto unimplemented;
+ ret = -TARGET_ENOPROTOOPT;
+ break;
}
break;
default:
unimplemented:
gemu_log("getsockopt level=%d optname=%d not yet supported\n",
level, optname);
- ret = -TARGET_ENOSYS;
+ ret = -TARGET_EOPNOTSUPP;
break;
}
return ret;
for(i = 0;i < count; i++) {
base = tswapl(target_vec[i].iov_base);
vec[i].iov_len = tswapl(target_vec[i].iov_len);
- vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy);
- if (!vec[i].iov_base)
- goto fail;
+ if (vec[i].iov_len != 0) {
+ vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy);
+ if (!vec[i].iov_base && vec[i].iov_len)
+ goto fail;
+ } else {
+ /* zero length pointer is ignored */
+ vec[i].iov_base = NULL;
+ }
}
unlock_user (target_vec, target_addr, 0);
return 0;
CPUState *new_env;
if (flags & CLONE_VM) {
+#if defined(USE_NPTL)
+ /* qemu is not threadsafe. Bail out immediately if application
+ tries to create a thread. */
+ if (!(flags & CLONE_VFORK)) {
+ gemu_log ("clone(CLONE_VM) not supported\n");
+ return -EINVAL;
+ }
+#endif
ts = malloc(sizeof(TaskState) + NEW_STACK_SIZE);
memset(ts, 0, sizeof(TaskState));
new_stack = ts->stack;
first_task_state = ts;
/* we create a new CPU instance. */
new_env = cpu_copy(env);
-#if defined(TARGET_I386)
- if (!newsp)
- newsp = env->regs[R_ESP];
- new_env->regs[R_ESP] = newsp;
- new_env->regs[R_EAX] = 0;
-#elif defined(TARGET_ARM)
- if (!newsp)
- newsp = env->regs[13];
- new_env->regs[13] = newsp;
- new_env->regs[0] = 0;
-#elif defined(TARGET_SPARC)
- if (!newsp)
- newsp = env->regwptr[22];
- new_env->regwptr[22] = newsp;
- new_env->regwptr[0] = 0;
- /* XXXXX */
- printf ("HELPME: %s:%d\n", __FILE__, __LINE__);
-#elif defined(TARGET_M68K)
- if (!newsp)
- newsp = env->aregs[7];
- new_env->aregs[7] = newsp;
- new_env->dregs[0] = 0;
- /* ??? is this sufficient? */
-#elif defined(TARGET_MIPS)
- if (!newsp)
- newsp = env->gpr[29][env->current_tc];
- new_env->gpr[29][env->current_tc] = newsp;
-#elif defined(TARGET_PPC)
- if (!newsp)
- newsp = env->gpr[1];
- new_env->gpr[1] = newsp;
- {
- int i;
- for (i = 7; i < 32; i++)
- new_env->gpr[i] = 0;
- }
-#elif defined(TARGET_SH4)
- if (!newsp)
- newsp = env->gregs[15];
- new_env->gregs[15] = newsp;
- /* XXXXX */
-#elif defined(TARGET_ALPHA)
- if (!newsp)
- newsp = env->ir[30];
- new_env->ir[30] = newsp;
- /* ? */
- {
- int i;
- for (i = 7; i < 30; i++)
- new_env->ir[i] = 0;
- }
-#elif defined(TARGET_CRIS)
- if (!newsp)
- newsp = env->regs[14];
- new_env->regs[14] = newsp;
-#else
-#error unsupported target CPU
-#endif
+ /* Init regs that differ from the parent. */
+ cpu_clone_regs(new_env, newsp);
new_env->opaque = ts;
#ifdef __ia64__
ret = __clone2(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
if ((flags & ~CSIGNAL) != 0)
return -EINVAL;
ret = fork();
+ if (ret == 0) {
+ cpu_clone_regs(env, newsp);
+ }
}
return ret;
}
host_ts->tv_sec = tswapl(target_ts->tv_sec);
host_ts->tv_nsec = tswapl(target_ts->tv_nsec);
unlock_user_struct(target_ts, target_addr, 0);
+ return 0;
}
static inline abi_long host_to_target_timespec(abi_ulong target_addr,
target_ts->tv_sec = tswapl(host_ts->tv_sec);
target_ts->tv_nsec = tswapl(host_ts->tv_nsec);
unlock_user_struct(target_ts, target_addr, 1);
+ return 0;
+}
+
+#if defined(USE_NPTL)
+/* ??? Using host futex calls even when target atomic operations
+ are not really atomic probably breaks things. However implementing
+ futexes locally would make futexes shared between multiple processes
+ tricky. However they're probably useless because guest atomic
+ operations won't work either. */
+int do_futex(target_ulong uaddr, int op, int val, target_ulong timeout,
+ target_ulong uaddr2, int val3)
+{
+ struct timespec ts, *pts;
+
+ /* ??? We assume FUTEX_* constants are the same on both host
+ and target. */
+ switch (op) {
+ case FUTEX_WAIT:
+ if (timeout) {
+ pts = &ts;
+ target_to_host_timespec(pts, timeout);
+ } else {
+ pts = NULL;
+ }
+ return get_errno(sys_futex(g2h(uaddr), FUTEX_WAIT, tswap32(val),
+ pts, NULL, 0));
+ case FUTEX_WAKE:
+ return get_errno(sys_futex(g2h(uaddr), FUTEX_WAKE, val, NULL, NULL, 0));
+ case FUTEX_FD:
+ return get_errno(sys_futex(g2h(uaddr), FUTEX_FD, val, NULL, NULL, 0));
+ case FUTEX_REQUEUE:
+ return get_errno(sys_futex(g2h(uaddr), FUTEX_REQUEUE, val,
+ NULL, g2h(uaddr2), 0));
+ case FUTEX_CMP_REQUEUE:
+ return get_errno(sys_futex(g2h(uaddr), FUTEX_CMP_REQUEUE, val,
+ NULL, g2h(uaddr2), tswap32(val3)));
+ default:
+ return -TARGET_ENOSYS;
+ }
+}
+#endif
+
+int get_osversion(void)
+{
+ static int osversion;
+ struct new_utsname buf;
+ const char *s;
+ int i, n, tmp;
+ if (osversion)
+ return osversion;
+ if (qemu_uname_release && *qemu_uname_release) {
+ s = qemu_uname_release;
+ } else {
+ if (sys_uname(&buf))
+ return 0;
+ s = buf.release;
+ }
+ tmp = 0;
+ for (i = 0; i < 3; i++) {
+ n = 0;
+ while (*s >= '0' && *s <= '9') {
+ n *= 10;
+ n += *s - '0';
+ s++;
+ }
+ tmp = (tmp << 8) + n;
+ if (*s == '.')
+ s++;
+ }
+ osversion = tmp;
+ return osversion;
}
/* do_syscall() should always have a single exit point at the end so
}
break;
#endif
+#ifdef TARGET_NR_waitid
+ case TARGET_NR_waitid:
+ {
+ siginfo_t info;
+ info.si_pid = 0;
+ ret = get_errno(waitid(arg1, arg2, &info, arg4));
+ if (!is_error(ret) && arg3 && info.si_pid != 0) {
+ if (!(p = lock_user(VERIFY_WRITE, arg3, sizeof(target_siginfo_t), 0)))
+ goto efault;
+ host_to_target_siginfo(p, &info);
+ unlock_user(p, arg3, sizeof(target_siginfo_t));
+ }
+ }
+ break;
+#endif
#ifdef TARGET_NR_creat /* not on alpha */
case TARGET_NR_creat:
if (!(p = lock_user_string(arg1)))
goto efault;
ret = get_errno(sys_unlinkat(arg1, p, arg3));
unlock_user(p, arg2, 0);
+ break;
#endif
case TARGET_NR_execve:
{
argc = 0;
guest_argp = arg2;
- for (gp = guest_argp; ; gp++) {
+ for (gp = guest_argp; ; gp += sizeof(abi_ulong)) {
if (get_user_ual(addr, gp))
goto efault;
if (!addr)
}
envc = 0;
guest_envp = arg3;
- for (gp = guest_envp; ; gp++) {
+ for (gp = guest_envp; ; gp += sizeof(abi_ulong)) {
if (get_user_ual(addr, gp))
goto efault;
if (!addr)
{
struct timeval *tvp, tv[2];
if (arg2) {
- target_to_host_timeval(&tv[0], arg2);
- target_to_host_timeval(&tv[1],
- arg2 + sizeof (struct target_timeval));
+ if (copy_from_user_timeval(&tv[0], arg2)
+ || copy_from_user_timeval(&tv[1],
+ arg2 + sizeof(struct target_timeval)))
+ goto efault;
tvp = tv;
} else {
tvp = NULL;
ret = 0;
break;
case TARGET_NR_kill:
- ret = get_errno(kill(arg1, arg2));
+ ret = get_errno(kill(arg1, target_to_host_signal(arg2)));
break;
case TARGET_NR_rename:
{
if (!is_error(ret)) {
#if defined(TARGET_MIPS)
CPUMIPSState *env = (CPUMIPSState*)cpu_env;
- env->gpr[3][env->current_tc] = host_pipe[1];
+ env->gpr[env->current_tc][3] = host_pipe[1];
+ ret = host_pipe[0];
+#elif defined(TARGET_SH4)
+ ((CPUSH4State*)cpu_env)->gregs[1] = host_pipe[1];
ret = host_pipe[0];
#else
if (put_user_s32(host_pipe[0], arg1)
struct timeval tv;
ret = get_errno(gettimeofday(&tv, NULL));
if (!is_error(ret)) {
- host_to_target_timeval(arg1, &tv);
+ if (copy_to_user_timeval(arg1, &tv))
+ goto efault;
}
}
break;
case TARGET_NR_settimeofday:
{
struct timeval tv;
- target_to_host_timeval(&tv, arg1);
+ if (copy_from_user_timeval(&tv, arg1))
+ goto efault;
ret = get_errno(settimeofday(&tv, NULL));
}
break;
#endif
#ifdef TARGET_NR_mmap2
case TARGET_NR_mmap2:
-#if defined(TARGET_SPARC) || defined(TARGET_MIPS)
+#ifndef MMAP_SHIFT
#define MMAP_SHIFT 12
-#else
-#define MMAP_SHIFT TARGET_PAGE_BITS
#endif
ret = get_errno(target_mmap(arg1, arg2, arg3,
target_to_host_bitmask(arg4, mmap_flags_tbl),
if (arg2) {
pvalue = &value;
- target_to_host_timeval(&pvalue->it_interval,
- arg2);
- target_to_host_timeval(&pvalue->it_value,
- arg2 + sizeof(struct target_timeval));
+ if (copy_from_user_timeval(&pvalue->it_interval, arg2)
+ || copy_from_user_timeval(&pvalue->it_value,
+ arg2 + sizeof(struct target_timeval)))
+ goto efault;
} else {
pvalue = NULL;
}
ret = get_errno(setitimer(arg1, pvalue, &ovalue));
if (!is_error(ret) && arg3) {
- host_to_target_timeval(arg3,
- &ovalue.it_interval);
- host_to_target_timeval(arg3 + sizeof(struct target_timeval),
- &ovalue.it_value);
+ if (copy_to_user_timeval(arg3,
+ &ovalue.it_interval)
+ || copy_to_user_timeval(arg3 + sizeof(struct target_timeval),
+ &ovalue.it_value))
+ goto efault;
}
}
break;
ret = get_errno(getitimer(arg1, &value));
if (!is_error(ret) && arg2) {
- host_to_target_timeval(arg2,
- &value.it_interval);
- host_to_target_timeval(arg2 + sizeof(struct target_timeval),
- &value.it_value);
+ if (copy_to_user_timeval(arg2,
+ &value.it_interval)
+ || copy_to_user_timeval(arg2 + sizeof(struct target_timeval),
+ &value.it_value))
+ goto efault;
}
}
break;
struct iovec *vec;
vec = alloca(count * sizeof(struct iovec));
- lock_iovec(VERIFY_WRITE, vec, arg2, count, 0);
+ if (lock_iovec(VERIFY_WRITE, vec, arg2, count, 0) < 0)
+ goto efault;
ret = get_errno(readv(arg1, vec, count));
unlock_iovec(vec, arg2, count, 1);
}
struct iovec *vec;
vec = alloca(count * sizeof(struct iovec));
- lock_iovec(VERIFY_READ, vec, arg2, count, 1);
+ 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);
}
ret = get_errno(pwrite(arg1, p, arg3, arg4));
unlock_user(p, arg2, 0);
break;
+#endif
+#ifdef TARGET_NR_pread64
+ case TARGET_NR_pread64:
+ if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
+ goto efault;
+ ret = get_errno(pread64(arg1, p, arg3, target_offset64(arg4, arg5)));
+ unlock_user(p, arg2, ret);
+ break;
+ case TARGET_NR_pwrite64:
+ if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
+ goto efault;
+ ret = get_errno(pwrite64(arg1, p, arg3, target_offset64(arg4, arg5)));
+ unlock_user(p, arg2, 0);
+ break;
#endif
case TARGET_NR_getcwd:
if (!(p = lock_user(VERIFY_WRITE, arg1, arg2, 0)))
break;
}
#endif
+#ifdef TARGET_NR_clock_nanosleep
+ case TARGET_NR_clock_nanosleep:
+ {
+ struct timespec ts;
+ target_to_host_timespec(&ts, arg3);
+ ret = get_errno(clock_nanosleep(arg1, arg2, &ts, arg4 ? &ts : NULL));
+ if (arg4)
+ host_to_target_timespec(arg4, &ts);
+ break;
+ }
+#endif
#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
case TARGET_NR_set_tid_address:
#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
case TARGET_NR_tkill:
- ret = get_errno(sys_tkill((int)arg1, (int)arg2));
+ ret = get_errno(sys_tkill((int)arg1, target_to_host_signal(arg2)));
break;
#endif
#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
case TARGET_NR_tgkill:
- ret = get_errno(sys_tgkill((int)arg1, (int)arg2, (int)arg3));
+ ret = get_errno(sys_tgkill((int)arg1, (int)arg2,
+ target_to_host_signal(arg3)));
break;
#endif
}
break;
#endif
+#if defined(USE_NPTL)
+ case TARGET_NR_futex:
+ ret = do_futex(arg1, arg2, arg3, arg4, arg5, arg6);
+ break;
+#endif
default:
unimplemented: