//#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 abi_long copy_from_user_fdset(fd_set *fds,
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[env->current_tc][29];
- new_env->gpr[env->current_tc][29] = 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)))
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:
{
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: