* [Qemu-devel] [PATCH] arm eabi TLS
@ 2007-12-12 0:44 Thayne Harbaugh
2007-12-12 1:29 ` Paul Brook
2007-12-12 23:03 ` Fabrice Bellard
0 siblings, 2 replies; 11+ messages in thread
From: Thayne Harbaugh @ 2007-12-12 0:44 UTC (permalink / raw)
To: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 336 bytes --]
I believe Paul Brook did the original patch for arm eabi TLS. The patch
has bounced around for a bit but hasn't been applied. We've been using
this patch for a while and have tweaked it to be a bit more correct as
far as code organization.
Please let me know what else should be improved for this so that it can
be applied.
Thanks.
[-- Attachment #2: 09_arm_eabitls.patch --]
[-- Type: text/x-patch, Size: 27912 bytes --]
Index: qemu/configure
===================================================================
--- qemu.orig/configure 2007-12-11 10:16:49.000000000 -0700
+++ qemu/configure 2007-12-11 10:16:50.000000000 -0700
@@ -105,6 +105,7 @@
darwin_user="no"
build_docs="no"
uname_release=""
+nptl="yes"
# OS specific
targetos=`uname -s`
@@ -318,6 +319,8 @@
;;
*) echo "ERROR: unknown option $opt"; show_help="yes"
;;
+ --disable-nptl) nptl="no"
+ ;;
esac
done
@@ -413,6 +416,7 @@
echo " --disable-linux-user disable all linux usermode emulation targets"
echo " --enable-darwin-user enable all darwin usermode emulation targets"
echo " --disable-darwin-user disable all darwin usermode emulation targets"
+echo " --disable-nptl disable usermode NPTL guest support"
echo " --fmod-lib path to FMOD library"
echo " --fmod-inc path to FMOD includes"
echo " --enable-uname-release=R Return R for uname -r in usermode emulation"
@@ -579,6 +583,23 @@
}
EOF
+# check NPTL support
+cat > $TMPC <<EOF
+#include <sched.h>
+void foo()
+{
+#ifndef CLONE_SETTLS
+#error bork
+#endif
+}
+EOF
+
+if $cc -c -o $TMPO $TMPC 2> /dev/null ; then
+ :
+else
+ nptl="no"
+fi
+
##########################################
# SDL probe
@@ -743,6 +764,7 @@
echo "Documentation $build_docs"
[ ! -z "$uname_release" ] && \
echo "uname -r $uname_release"
+echo "NPTL support $nptl"
if test $sdl_too_old = "yes"; then
echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -948,6 +970,7 @@
echo "SDL_CFLAGS=`$sdl_config --cflags`" >> $config_mak
fi
fi
+
if test "$cocoa" = "yes" ; then
echo "#define CONFIG_COCOA 1" >> $config_h
echo "CONFIG_COCOA=yes" >> $config_mak
@@ -1183,6 +1206,15 @@
echo "#define TARGET_HAS_ELFLOAD32 1" >> $config_h
fi
+if test "$nptl" = "yes" ; then
+ case "$target_cpu" in
+ arm | armeb | ppc | ppc64)
+ echo "USE_NPTL=yes" >> $config_mak
+ echo "#define USE_NPTL 1" >> $config_h
+ ;;
+ esac
+fi
+
test -f ${config_h}~ && cmp -s $config_h ${config_h}~ && mv ${config_h}~ $config_h
done # for target in $targets
Index: qemu/exec-all.h
===================================================================
--- qemu.orig/exec-all.h 2007-12-11 10:16:49.000000000 -0700
+++ qemu/exec-all.h 2007-12-11 10:16:50.000000000 -0700
@@ -340,170 +340,7 @@
extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
extern void *io_mem_opaque[IO_MEM_NB_ENTRIES];
-#if defined(__powerpc__)
-static inline int testandset (int *p)
-{
- int ret;
- __asm__ __volatile__ (
- "0: lwarx %0,0,%1\n"
- " xor. %0,%3,%0\n"
- " bne 1f\n"
- " stwcx. %2,0,%1\n"
- " bne- 0b\n"
- "1: "
- : "=&r" (ret)
- : "r" (p), "r" (1), "r" (0)
- : "cr0", "memory");
- return ret;
-}
-#elif defined(__i386__)
-static inline int testandset (int *p)
-{
- long int readval = 0;
-
- __asm__ __volatile__ ("lock; cmpxchgl %2, %0"
- : "+m" (*p), "+a" (readval)
- : "r" (1)
- : "cc");
- return readval;
-}
-#elif defined(__x86_64__)
-static inline int testandset (int *p)
-{
- long int readval = 0;
-
- __asm__ __volatile__ ("lock; cmpxchgl %2, %0"
- : "+m" (*p), "+a" (readval)
- : "r" (1)
- : "cc");
- return readval;
-}
-#elif defined(__s390__)
-static inline int testandset (int *p)
-{
- int ret;
-
- __asm__ __volatile__ ("0: cs %0,%1,0(%2)\n"
- " jl 0b"
- : "=&d" (ret)
- : "r" (1), "a" (p), "0" (*p)
- : "cc", "memory" );
- return ret;
-}
-#elif defined(__alpha__)
-static inline int testandset (int *p)
-{
- int ret;
- unsigned long one;
-
- __asm__ __volatile__ ("0: mov 1,%2\n"
- " ldl_l %0,%1\n"
- " stl_c %2,%1\n"
- " beq %2,1f\n"
- ".subsection 2\n"
- "1: br 0b\n"
- ".previous"
- : "=r" (ret), "=m" (*p), "=r" (one)
- : "m" (*p));
- return ret;
-}
-#elif defined(__sparc__)
-static inline int testandset (int *p)
-{
- int ret;
-
- __asm__ __volatile__("ldstub [%1], %0"
- : "=r" (ret)
- : "r" (p)
- : "memory");
-
- return (ret ? 1 : 0);
-}
-#elif defined(__arm__)
-static inline int testandset (int *spinlock)
-{
- register unsigned int ret;
- __asm__ __volatile__("swp %0, %1, [%2]"
- : "=r"(ret)
- : "0"(1), "r"(spinlock));
-
- return ret;
-}
-#elif defined(__mc68000)
-static inline int testandset (int *p)
-{
- char ret;
- __asm__ __volatile__("tas %1; sne %0"
- : "=r" (ret)
- : "m" (p)
- : "cc","memory");
- return ret;
-}
-#elif defined(__ia64)
-
-#include <ia64intrin.h>
-
-static inline int testandset (int *p)
-{
- return __sync_lock_test_and_set (p, 1);
-}
-#elif defined(__mips__)
-static inline int testandset (int *p)
-{
- int ret;
-
- __asm__ __volatile__ (
- " .set push \n"
- " .set noat \n"
- " .set mips2 \n"
- "1: li $1, 1 \n"
- " ll %0, %1 \n"
- " sc $1, %1 \n"
- " beqz $1, 1b \n"
- " .set pop "
- : "=r" (ret), "+R" (*p)
- :
- : "memory");
-
- return ret;
-}
-#else
-#error unimplemented CPU support
-#endif
-
-typedef int spinlock_t;
-
-#define SPIN_LOCK_UNLOCKED 0
-
-#if defined(CONFIG_USER_ONLY)
-static inline void spin_lock(spinlock_t *lock)
-{
- while (testandset(lock));
-}
-
-static inline void spin_unlock(spinlock_t *lock)
-{
- *lock = 0;
-}
-
-static inline int spin_trylock(spinlock_t *lock)
-{
- return !testandset(lock);
-}
-#else
-static inline void spin_lock(spinlock_t *lock)
-{
-}
-
-static inline void spin_unlock(spinlock_t *lock)
-{
-}
-
-static inline int spin_trylock(spinlock_t *lock)
-{
- return 1;
-}
-#endif
+#include "qspinlock.h"
extern spinlock_t tb_lock;
Index: qemu/linux-user/arm/syscall.h
===================================================================
--- qemu.orig/linux-user/arm/syscall.h 2007-12-11 10:16:49.000000000 -0700
+++ qemu/linux-user/arm/syscall.h 2007-12-11 10:16:50.000000000 -0700
@@ -28,7 +28,9 @@
#define ARM_SYSCALL_BASE 0x900000
#define ARM_THUMB_SYSCALL 0
-#define ARM_NR_cacheflush (ARM_SYSCALL_BASE + 0xf0000 + 2)
+#define ARM_NR_BASE 0xf0000
+#define ARM_NR_cacheflush (ARM_NR_BASE + 2)
+#define ARM_NR_set_tls (ARM_NR_BASE + 5)
#define ARM_NR_semihosting 0x123456
#define ARM_NR_thumb_semihosting 0xAB
Index: qemu/linux-user/main.c
===================================================================
--- qemu.orig/linux-user/main.c 2007-12-11 10:16:49.000000000 -0700
+++ qemu/linux-user/main.c 2007-12-11 10:16:50.000000000 -0700
@@ -363,6 +363,50 @@
}
}
+/* Handle a jump to the kernel code page. */
+static int
+do_kernel_trap(CPUARMState *env)
+{
+ uint32_t addr;
+ uint32_t *ptr;
+ uint32_t cpsr;
+
+ switch (env->regs[15]) {
+ case 0xffff0fc0: /* __kernel_cmpxchg */
+ /* XXX: This only works between threads, not between processes.
+ Use native atomic operations. */
+ /* ??? This probably breaks horribly if the access segfaults. */
+ cpu_lock();
+ ptr = (uint32_t *)env->regs[2];
+ cpsr = cpsr_read(env);
+ if (*ptr == env->regs[0]) {
+ *ptr = env->regs[1];
+ env->regs[0] = 0;
+ cpsr |= CPSR_C;
+ } else {
+ env->regs[0] = -1;
+ cpsr &= ~CPSR_C;
+ }
+ cpsr_write(env, cpsr, CPSR_C);
+ cpu_unlock();
+ break;
+ case 0xffff0fe0: /* __kernel_get_tls */
+ env->regs[0] = env->cp15.c13_tls3;
+ break;
+ default:
+ return 1;
+ }
+ /* Jump back to the caller. */
+ addr = env->regs[14];
+ if (addr & 1) {
+ env->thumb = 1;
+ addr &= ~1;
+ }
+ env->regs[15] = addr;
+
+ return 0;
+}
+
void cpu_loop(CPUARMState *env)
{
int trapnr;
@@ -424,10 +468,8 @@
}
}
- if (n == ARM_NR_cacheflush) {
- arm_cache_flush(env->regs[0], env->regs[1]);
- } else if (n == ARM_NR_semihosting
- || n == ARM_NR_thumb_semihosting) {
+ if (n == ARM_NR_semihosting
+ || n == ARM_NR_thumb_semihosting) {
env->regs[0] = do_arm_semihosting (env);
} else if (n == 0 || n >= ARM_SYSCALL_BASE
|| (env->thumb && n == ARM_THUMB_SYSCALL)) {
@@ -438,6 +480,26 @@
n -= ARM_SYSCALL_BASE;
env->eabi = 0;
}
+ if (n > ARM_NR_BASE) {
+ switch (n)
+ {
+ case ARM_NR_cacheflush:
+ arm_cache_flush(env->regs[0], env->regs[1]);
+ break;
+#ifdef USE_NPTL
+ case ARM_NR_set_tls:
+ cpu_set_tls(env, env->regs[0]);
+ env->regs[0] = 0;
+ break;
+#endif
+ default:
+ printf ("Error: Bad syscall: %x\n", n);
+ env->regs[0] = -TARGET_ENOSYS;
+ goto error;
+ }
+ }
+ else
+ {
env->regs[0] = do_syscall(env,
n,
env->regs[0],
@@ -446,7 +508,9 @@
env->regs[3],
env->regs[4],
env->regs[5]);
+ }
} else {
+ printf ("Error: Bad syscall: %x\n", n);
goto error;
}
}
@@ -484,6 +548,10 @@
}
}
break;
+ case EXCP_KERNEL_TRAP:
+ if (do_kernel_trap(env))
+ goto error;
+ break;
default:
error:
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
@@ -2348,6 +2416,10 @@
ts->heap_base = info->brk;
/* This will be filled in on the first SYS_HEAPINFO call. */
ts->heap_limit = 0;
+ /* Register the magic kernel code page. The cpu will generate a
+ special exception when it tries to execute code here. We can't
+ put real code here because it may be in use by the host kernel. */
+ page_set_flags(0xffff0000, 0xffff0fff, 0);
#endif
if (gdbstub_port) {
Index: qemu/linux-user/qemu.h
===================================================================
--- qemu.orig/linux-user/qemu.h 2007-12-11 10:16:49.000000000 -0700
+++ qemu/linux-user/qemu.h 2007-12-11 10:16:50.000000000 -0700
@@ -104,6 +104,9 @@
#endif
int used; /* non zero if used */
struct image_info *info;
+#ifdef USE_NPTL
+ abi_ulong child_tid_addr;
+#endif
uint8_t stack[0];
} __attribute__((aligned(16))) TaskState;
Index: qemu/linux-user/syscall.c
===================================================================
--- qemu.orig/linux-user/syscall.c 2007-12-11 10:16:49.000000000 -0700
+++ qemu/linux-user/syscall.c 2007-12-11 10:16:50.000000000 -0700
@@ -71,9 +71,18 @@
#include <linux/kd.h>
#include "qemu.h"
+#include "qspinlock.h"
//#define DEBUG
+#ifdef USE_NPTL
+#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
+ CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
+#else
+/* XXX: Hardcode the above values. */
+#define CLONE_NPTL_FLAGS2 0
+#endif
+
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \
|| defined(TARGET_M68K) || defined(TARGET_SH4) || defined(TARGET_CRIS)
/* 16 bit uid wrappers emulation */
@@ -2797,9 +2806,19 @@
thread/process */
#define NEW_STACK_SIZE 8192
+#ifdef USE_NPTL
+static spinlock_t nptl_lock = SPIN_LOCK_UNLOCKED;
+#endif
+
static int clone_func(void *arg)
{
CPUState *env = arg;
+#ifdef USE_NPTL
+ /* Wait until the parent has finshed initializing the tls state. */
+ while (!spin_trylock(&nptl_lock))
+ usleep(1);
+ spin_unlock(&nptl_lock);
+#endif
cpu_loop(env);
/* never exits */
return 0;
@@ -2807,12 +2826,24 @@
/* do_fork() Must return host values and target errnos (unlike most
do_*() functions). */
-int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp)
+int do_fork(CPUState *env,
+ unsigned int flags,
+ abi_ulong new_stk_addr,
+ abi_ulong parent_tid_addr,
+ abi_ulong newtls_addr,
+ abi_ulong child_tid_addr)
{
int ret;
TaskState *ts;
uint8_t *new_stack;
CPUState *new_env;
+#ifdef USE_NPTL
+ unsigned int nptl_flags;
+
+ if (flags & CLONE_PARENT_SETTID)
+ if (put_user_s32(gettid(), parent_tid_addr))
+ return -TARGET_EFAULT;
+#endif
if (flags & CLONE_VM) {
ts = malloc(sizeof(TaskState) + NEW_STACK_SIZE);
@@ -2824,51 +2855,37 @@
first_task_state = ts;
/* we create a new CPU instance. */
new_env = cpu_copy(env);
+ if (!new_stk_addr)
+ new_stk_addr = get_sp_from_cpustate(env);
#if defined(TARGET_I386)
- if (!newsp)
- newsp = env->regs[R_ESP];
- new_env->regs[R_ESP] = newsp;
+ new_env->regs[R_ESP] = new_stk_addr;
new_env->regs[R_EAX] = 0;
#elif defined(TARGET_ARM)
- if (!newsp)
- newsp = env->regs[13];
- new_env->regs[13] = newsp;
+ new_env->regs[13] = new_stk_addr;
new_env->regs[0] = 0;
#elif defined(TARGET_SPARC)
- if (!newsp)
- newsp = env->regwptr[22];
- new_env->regwptr[22] = newsp;
+ new_env->regwptr[22] = new_stk_addr;
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->aregs[7] = new_stk_addr;
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;
+ new_env->gpr[29][env->current_tc] = new_stk_addr;
#elif defined(TARGET_PPC)
- if (!newsp)
- newsp = env->gpr[1];
- new_env->gpr[1] = newsp;
+ new_env->gpr[1] = new_stk_addr;
{
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;
+ new_env->gregs[15] = new_stk_addr;
/* XXXXX */
#elif defined(TARGET_ALPHA)
- if (!newsp)
- newsp = env->ir[30];
- new_env->ir[30] = newsp;
+ new_env->ir[30] = new_stk_addr;
/* ? */
{
int i;
@@ -2876,23 +2893,71 @@
new_env->ir[i] = 0;
}
#elif defined(TARGET_CRIS)
- if (!newsp)
- newsp = env->regs[14];
- new_env->regs[14] = newsp;
+ new_env->regs[14] = new_stk_addr;
#else
#error unsupported target CPU
#endif
new_env->opaque = ts;
+#ifdef USE_NPTL
+ nptl_flags = flags;
+ flags &= ~CLONE_NPTL_FLAGS2;
+
+ if (nptl_flags & CLONE_CHILD_CLEARTID) {
+ ts->child_tid_addr = child_tid_addr;
+ }
+
+ if (nptl_flags & CLONE_SETTLS)
+ cpu_set_tls(new_env, newtls_addr);
+
+ /* Grab the global cpu lock so that the thread setup appears
+ atomic. */
+ if (nptl_flags & CLONE_CHILD_SETTID)
+ spin_lock(&nptl_lock);
+
+#else
+ if (flags & CLONE_NPTL_FLAGS2)
+ return -EINVAL;
+#endif
#ifdef __ia64__
ret = __clone2(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
#else
ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
#endif
+#ifdef USE_NPTL
+ if (ret != -1) {
+ if (nptl_flags & CLONE_CHILD_SETTID)
+ if (put_user_s32(ret, child_tid_addr))
+ return -TARGET_EFAULT;
+ }
+
+ /* Allow the child to continue. */
+ if (nptl_flags & CLONE_CHILD_SETTID)
+ spin_unlock(&nptl_lock);
+#endif
} else {
/* if no CLONE_VM, we consider it is a fork */
- if ((flags & ~CSIGNAL) != 0)
+ if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
return -EINVAL;
ret = fork();
+#ifdef USE_NPTL
+ /* There is a race condition here. The parent process could
+ theoretically read the TID in the child process before the child
+ tid is set. This would require using either ptrace
+ (not implemented) or having *_tidptr to point at a shared memory
+ mapping. We can't repeat the spinlock hack used above because
+ the child process gets its own copy of the lock. */
+ if (ret == 0) {
+ /* Child Process. */
+ if (flags & CLONE_CHILD_SETTID)
+ if (put_user_s32(gettid(), child_tid_addr))
+ return -TARGET_EFAULT;
+ ts = (TaskState *)env->opaque;
+ if (flags & CLONE_CHILD_CLEARTID)
+ ts->child_tid_addr = child_tid_addr;
+ if (flags & CLONE_SETTLS)
+ cpu_set_tls(env, newtls_addr);
+ }
+#endif
}
return ret;
}
@@ -3370,7 +3435,7 @@
ret = do_brk(arg1);
break;
case TARGET_NR_fork:
- ret = get_errno(do_fork(cpu_env, SIGCHLD, 0));
+ ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
break;
#ifdef TARGET_NR_waitpid
case TARGET_NR_waitpid:
@@ -4726,7 +4791,7 @@
ret = get_errno(fsync(arg1));
break;
case TARGET_NR_clone:
- ret = get_errno(do_fork(cpu_env, arg1, arg2));
+ ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
break;
#ifdef __NR_exit_group
/* new thread calls */
@@ -5152,7 +5217,9 @@
#endif
#ifdef TARGET_NR_vfork
case TARGET_NR_vfork:
- ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0));
+ ret = get_errno(do_fork(cpu_env,
+ CLONE_VFORK | CLONE_VM | SIGCHLD,
+ 0, 0, 0, 0));
break;
#endif
#ifdef TARGET_NR_ugetrlimit
Index: qemu/qspinlock.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ qemu/qspinlock.h 2007-12-11 10:16:50.000000000 -0700
@@ -0,0 +1,188 @@
+/*
+ * Atomic operation helper include
+ *
+ * Copyright (c) 2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef QSPINLOCK_H
+#define QSPINLOCK_H
+
+#if defined(__powerpc__)
+static inline int testandset (int *p)
+{
+ int ret;
+ __asm__ __volatile__ (
+ "0: lwarx %0,0,%1\n"
+ " xor. %0,%3,%0\n"
+ " bne 1f\n"
+ " stwcx. %2,0,%1\n"
+ " bne- 0b\n"
+ "1: "
+ : "=&r" (ret)
+ : "r" (p), "r" (1), "r" (0)
+ : "cr0", "memory");
+ return ret;
+}
+#elif defined(__i386__)
+static inline int testandset (int *p)
+{
+ long int readval = 0;
+
+ __asm__ __volatile__ ("lock; cmpxchgl %2, %0"
+ : "+m" (*p), "+a" (readval)
+ : "r" (1)
+ : "cc");
+ return readval;
+}
+#elif defined(__x86_64__)
+static inline int testandset (int *p)
+{
+ long int readval = 0;
+
+ __asm__ __volatile__ ("lock; cmpxchgl %2, %0"
+ : "+m" (*p), "+a" (readval)
+ : "r" (1)
+ : "cc");
+ return readval;
+}
+#elif defined(__s390__)
+static inline int testandset (int *p)
+{
+ int ret;
+
+ __asm__ __volatile__ ("0: cs %0,%1,0(%2)\n"
+ " jl 0b"
+ : "=&d" (ret)
+ : "r" (1), "a" (p), "0" (*p)
+ : "cc", "memory" );
+ return ret;
+}
+#elif defined(__alpha__)
+static inline int testandset (int *p)
+{
+ int ret;
+ unsigned long one;
+
+ __asm__ __volatile__ ("0: mov 1,%2\n"
+ " ldl_l %0,%1\n"
+ " stl_c %2,%1\n"
+ " beq %2,1f\n"
+ ".subsection 2\n"
+ "1: br 0b\n"
+ ".previous"
+ : "=r" (ret), "=m" (*p), "=r" (one)
+ : "m" (*p));
+ return ret;
+}
+#elif defined(__sparc__)
+static inline int testandset (int *p)
+{
+ int ret;
+
+ __asm__ __volatile__("ldstub [%1], %0"
+ : "=r" (ret)
+ : "r" (p)
+ : "memory");
+
+ return (ret ? 1 : 0);
+}
+#elif defined(__arm__)
+static inline int testandset (int *spinlock)
+{
+ register unsigned int ret;
+ __asm__ __volatile__("swp %0, %1, [%2]"
+ : "=r"(ret)
+ : "0"(1), "r"(spinlock));
+
+ return ret;
+}
+#elif defined(__mc68000)
+static inline int testandset (int *p)
+{
+ char ret;
+ __asm__ __volatile__("tas %1; sne %0"
+ : "=r" (ret)
+ : "m" (p)
+ : "cc","memory");
+ return ret;
+}
+#elif defined(__ia64)
+
+#include <ia64intrin.h>
+
+static inline int testandset (int *p)
+{
+ return __sync_lock_test_and_set (p, 1);
+}
+#elif defined(__mips__)
+static inline int testandset (int *p)
+{
+ int ret;
+
+ __asm__ __volatile__ (
+ " .set push \n"
+ " .set noat \n"
+ " .set mips2 \n"
+ "1: li $1, 1 \n"
+ " ll %0, %1 \n"
+ " sc $1, %1 \n"
+ " beqz $1, 1b \n"
+ " .set pop "
+ : "=r" (ret), "+R" (*p)
+ :
+ : "memory");
+
+ return ret;
+}
+#else
+#error unimplemented CPU support
+#endif
+
+typedef int spinlock_t;
+
+#define SPIN_LOCK_UNLOCKED 0
+
+#if defined(CONFIG_USER_ONLY)
+static inline void spin_lock(spinlock_t *lock)
+{
+ while (testandset(lock));
+}
+
+static inline void spin_unlock(spinlock_t *lock)
+{
+ *lock = 0;
+}
+
+static inline int spin_trylock(spinlock_t *lock)
+{
+ return !testandset(lock);
+}
+#else
+static inline void spin_lock(spinlock_t *lock)
+{
+}
+
+static inline void spin_unlock(spinlock_t *lock)
+{
+}
+
+static inline int spin_trylock(spinlock_t *lock)
+{
+ return 1;
+}
+#endif
+
+#endif /* QSPINLOCK_H */
Index: qemu/target-arm/cpu.h
===================================================================
--- qemu.orig/target-arm/cpu.h 2007-12-11 10:16:49.000000000 -0700
+++ qemu/target-arm/cpu.h 2007-12-11 10:16:50.000000000 -0700
@@ -37,7 +37,11 @@
#define EXCP_IRQ 5
#define EXCP_FIQ 6
#define EXCP_BKPT 7
+#if defined(CONFIG_USER_ONLY)
+#define EXCP_KERNEL_TRAP 8 /* Jumped to kernel code page. */
+#else
#define EXCP_EXCEPTION_EXIT 8 /* Return from v7M exception. */
+#endif
#define ARMV7M_EXCP_RESET 1
#define ARMV7M_EXCP_NMI 2
@@ -221,6 +225,12 @@
void cpu_lock(void);
void cpu_unlock(void);
+#if defined(USE_NPTL)
+static inline void cpu_set_tls(CPUARMState *env, uint32_t newtls_addr)
+{
+ env->cp15.c13_tls3 = newtls_addr;
+}
+#endif
#define CPSR_M (0x1f)
#define CPSR_T (1 << 5)
Index: qemu/target-arm/op.c
===================================================================
--- qemu.orig/target-arm/op.c 2007-12-11 10:16:49.000000000 -0700
+++ qemu/target-arm/op.c 2007-12-11 10:16:50.000000000 -0700
@@ -1003,11 +1003,19 @@
cpu_loop_exit();
}
+#if !defined(CONFIG_USER_ONLY)
void OPPROTO op_exception_exit(void)
{
env->exception_index = EXCP_EXCEPTION_EXIT;
cpu_loop_exit();
}
+#else
+void OPPROTO op_kernel_trap(void)
+{
+ env->exception_index = EXCP_KERNEL_TRAP;
+ cpu_loop_exit();
+}
+#endif /* defined(CONFIG_USER_ONLY) */
/* VFP support. We follow the convention used for VFP instrunctions:
Single precition routines have a "s" suffix, double precision a
Index: qemu/target-arm/translate.c
===================================================================
--- qemu.orig/target-arm/translate.c 2007-12-11 10:16:49.000000000 -0700
+++ qemu/target-arm/translate.c 2007-12-11 10:16:50.000000000 -0700
@@ -7513,13 +7513,20 @@
if (env->condexec_bits)
gen_op_set_condexec(0);
do {
-#ifndef CONFIG_USER_ONLY
+#if defined(CONFIG_USER_ONLY)
+ /* Intercept jump to the magic kernel page. */
+ if (dc->pc > 0xffff0000) {
+ gen_op_kernel_trap();
+ dc->is_jmp = DISAS_UPDATE;
+ break;
+ }
+#else /* !defined(CONFIG_USER_ONLY) */
if (dc->pc >= 0xfffffff0 && IS_M(env)) {
/* We always get here via a jump, so know we are not in a
conditional execution block. */
gen_op_exception_exit();
}
-#endif
+#endif /* !defined(CONFIG_USER_ONLY) */
if (env->nb_breakpoints > 0) {
for(j = 0; j < env->nb_breakpoints; j++) {
Index: qemu/arm.ld
===================================================================
--- qemu.orig/arm.ld 2007-12-11 10:16:49.000000000 -0700
+++ qemu/arm.ld 2007-12-11 10:16:50.000000000 -0700
@@ -26,6 +26,10 @@
{ *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
.rela.rodata :
{ *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
+ .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
+ .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
+ .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
+ .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
.rel.got : { *(.rel.got) }
.rela.got : { *(.rela.got) }
.rel.ctors : { *(.rel.ctors) }
Index: qemu/target-ppc/cpu.h
===================================================================
--- qemu.orig/target-ppc/cpu.h 2007-12-11 10:16:49.000000000 -0700
+++ qemu/target-ppc/cpu.h 2007-12-11 10:16:50.000000000 -0700
@@ -712,6 +712,12 @@
void do_interrupt (CPUPPCState *env);
void ppc_hw_interrupt (CPUPPCState *env);
void cpu_loop_exit (void);
+#if defined(USE_NPTL)
+static inline void cpu_set_tls(CPUPPCState *env, ppc_gpr_t newtls_addr)
+{
+ env->gpr[2] = newtls_addr;
+}
+#endif
void dump_stack (CPUPPCState *env);
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH] arm eabi TLS
2007-12-12 0:44 [Qemu-devel] [PATCH] arm eabi TLS Thayne Harbaugh
@ 2007-12-12 1:29 ` Paul Brook
2007-12-12 23:03 ` Fabrice Bellard
1 sibling, 0 replies; 11+ messages in thread
From: Paul Brook @ 2007-12-12 1:29 UTC (permalink / raw)
To: qemu-devel, thayne
On Wednesday 12 December 2007, Thayne Harbaugh wrote:
> I believe Paul Brook did the original patch for arm eabi TLS. The patch
> has bounced around for a bit but hasn't been applied. We've been using
> this patch for a while and have tweaked it to be a bit more correct as
> far as code organization.
>
> Please let me know what else should be improved for this so that it can
> be applied.
Implementing clone(CLONE_VM) is a bad idea. We should only do that after we've
fixed everything else that breaks with multiple threads
You're also missing some of the ARM kernel helper routines.
Paul
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH] arm eabi TLS
2007-12-12 0:44 [Qemu-devel] [PATCH] arm eabi TLS Thayne Harbaugh
2007-12-12 1:29 ` Paul Brook
@ 2007-12-12 23:03 ` Fabrice Bellard
2007-12-13 1:21 ` Paul Brook
1 sibling, 1 reply; 11+ messages in thread
From: Fabrice Bellard @ 2007-12-12 23:03 UTC (permalink / raw)
To: thayne, qemu-devel
Thayne Harbaugh wrote:
> I believe Paul Brook did the original patch for arm eabi TLS. The patch
> has bounced around for a bit but hasn't been applied. We've been using
> this patch for a while and have tweaked it to be a bit more correct as
> far as code organization.
>
> Please let me know what else should be improved for this so that it can
> be applied.
- the clone() syscall must be disabled when it is used to create a
thread because it cannot work reliably in its current state.
- the system to intercept calls to the syscall page must be made more
generic to be used at least by arm user and x86_64 user.
- It would be good to limit the changes in the CPU emulation code to
handle the TLS. For example, on MIPS, the TLS register must not be
stored in the CPU state. Same for ARM.
Regards,
Fabrice.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH] arm eabi TLS
2007-12-13 1:21 ` Paul Brook
@ 2007-12-13 1:15 ` Thayne Harbaugh
2008-01-28 18:27 ` Felipe Contreras
2007-12-13 8:57 ` Fabrice Bellard
2007-12-13 13:28 ` Daniel Jacobowitz
2 siblings, 1 reply; 11+ messages in thread
From: Thayne Harbaugh @ 2007-12-13 1:15 UTC (permalink / raw)
To: Paul Brook; +Cc: qemu-devel
On Thu, 2007-12-13 at 01:21 +0000, Paul Brook wrote:
> > - It would be good to limit the changes in the CPU emulation code to
> > handle the TLS. For example, on MIPS, the TLS register must not be
> > stored in the CPU state. Same for ARM.
>
> I disagree. The TLS register is part of the CPU state. On many machines
> (including ARMv6 CPUs) it's an actual CPU register. I'm fairly sure the same
> is true for recent MIPS revisions.
I agree with Paul. Some archs actually use a CPU register and require
the kernel to help manage TLS. Other archs can manage TLS completely in
user space. It's been a while since I've investigated all the details
for each arch but I'll go review it.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH] arm eabi TLS
2007-12-12 23:03 ` Fabrice Bellard
@ 2007-12-13 1:21 ` Paul Brook
2007-12-13 1:15 ` Thayne Harbaugh
` (2 more replies)
0 siblings, 3 replies; 11+ messages in thread
From: Paul Brook @ 2007-12-13 1:21 UTC (permalink / raw)
To: qemu-devel; +Cc: thayne
> - It would be good to limit the changes in the CPU emulation code to
> handle the TLS. For example, on MIPS, the TLS register must not be
> stored in the CPU state. Same for ARM.
I disagree. The TLS register is part of the CPU state. On many machines
(including ARMv6 CPUs) it's an actual CPU register. I'm fairly sure the same
is true for recent MIPS revisions.
Paul
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH] arm eabi TLS
2007-12-13 1:21 ` Paul Brook
2007-12-13 1:15 ` Thayne Harbaugh
@ 2007-12-13 8:57 ` Fabrice Bellard
2007-12-13 13:28 ` Daniel Jacobowitz
2 siblings, 0 replies; 11+ messages in thread
From: Fabrice Bellard @ 2007-12-13 8:57 UTC (permalink / raw)
To: Paul Brook; +Cc: qemu-devel, thayne
Paul Brook wrote:
>> - It would be good to limit the changes in the CPU emulation code to
>> handle the TLS. For example, on MIPS, the TLS register must not be
>> stored in the CPU state. Same for ARM.
>
> I disagree. The TLS register is part of the CPU state. On many machines
> (including ARMv6 CPUs) it's an actual CPU register. I'm fairly sure the same
> is true for recent MIPS revisions.
If some CPUs implement it in hardware, then I agree.
Fabrice.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH] arm eabi TLS
2007-12-13 1:21 ` Paul Brook
2007-12-13 1:15 ` Thayne Harbaugh
2007-12-13 8:57 ` Fabrice Bellard
@ 2007-12-13 13:28 ` Daniel Jacobowitz
2 siblings, 0 replies; 11+ messages in thread
From: Daniel Jacobowitz @ 2007-12-13 13:28 UTC (permalink / raw)
To: qemu-devel
On Thu, Dec 13, 2007 at 01:21:03AM +0000, Paul Brook wrote:
> I disagree. The TLS register is part of the CPU state. On many machines
> (including ARMv6 CPUs) it's an actual CPU register. I'm fairly sure the same
> is true for recent MIPS revisions.
That's correct, though I don't know if there is silicon to match yet.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH] arm eabi TLS
2007-12-13 1:15 ` Thayne Harbaugh
@ 2008-01-28 18:27 ` Felipe Contreras
2008-04-04 15:03 ` Marc-André Lureau
0 siblings, 1 reply; 11+ messages in thread
From: Felipe Contreras @ 2008-01-28 18:27 UTC (permalink / raw)
To: thayne, qemu-devel; +Cc: Paul Brook
On Dec 13, 2007 3:15 AM, Thayne Harbaugh <thayne@c2.net> wrote:
>
>
> On Thu, 2007-12-13 at 01:21 +0000, Paul Brook wrote:
> > > - It would be good to limit the changes in the CPU emulation code to
> > > handle the TLS. For example, on MIPS, the TLS register must not be
> > > stored in the CPU state. Same for ARM.
> >
> > I disagree. The TLS register is part of the CPU state. On many machines
> > (including ARMv6 CPUs) it's an actual CPU register. I'm fairly sure the same
> > is true for recent MIPS revisions.
>
> I agree with Paul. Some archs actually use a CPU register and require
> the kernel to help manage TLS. Other archs can manage TLS completely in
> user space. It's been a while since I've investigated all the details
> for each arch but I'll go review it.
How is this going?
The patch works pretty well for me.
--
Felipe Contreras
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH] arm eabi TLS
2008-01-28 18:27 ` Felipe Contreras
@ 2008-04-04 15:03 ` Marc-André Lureau
2008-04-04 17:48 ` Stuart Anderson
2008-05-05 15:12 ` Felipe Contreras
0 siblings, 2 replies; 11+ messages in thread
From: Marc-André Lureau @ 2008-04-04 15:03 UTC (permalink / raw)
To: qemu-devel; +Cc: Paul Brook, thayne
Hi,
On Mon, Jan 28, 2008 at 9:27 PM, Felipe Contreras
<felipe.contreras@gmail.com> wrote:
>
> How is this going?
>
> The patch works pretty well for me.
>
Unfortunately, the patch does not apply cleanly anymore.
Is there an updated version somewhere?
regards,
--
Marc-André Lureau
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH] arm eabi TLS
2008-04-04 15:03 ` Marc-André Lureau
@ 2008-04-04 17:48 ` Stuart Anderson
2008-05-05 15:12 ` Felipe Contreras
1 sibling, 0 replies; 11+ messages in thread
From: Stuart Anderson @ 2008-04-04 17:48 UTC (permalink / raw)
To: qemu-devel
[-- Attachment #1: Type: TEXT/PLAIN, Size: 1291 bytes --]
On Fri, 4 Apr 2008, Marc-André Lureau wrote:
> Hi,
>
> On Mon, Jan 28, 2008 at 9:27 PM, Felipe Contreras
> <felipe.contreras@gmail.com> wrote:
>>
>> How is this going?
>>
>> The patch works pretty well for me.
>>
>
> Unfortunately, the patch does not apply cleanly anymore.
>
> Is there an updated version somewhere?
Not yet. Thayne (who started this thread) has moved on to other opportunities
and is no longer working on it. I am still working on it, but due to a
lack of time haven't touched it recently. I am however planning to spend
some time on it hopefully in the next week or two, once I finish up with
the tasks I'm currently working on. One of the first things to do will
of course be to pull the patches up to the CVS head again.
For anyone that is interested, all of our work on this can be found at
http://qemu.olmeclinux.com/ . This includes our full patch set, test
suites, and complete userspaces.
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
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Qemu-devel] [PATCH] arm eabi TLS
2008-04-04 15:03 ` Marc-André Lureau
2008-04-04 17:48 ` Stuart Anderson
@ 2008-05-05 15:12 ` Felipe Contreras
1 sibling, 0 replies; 11+ messages in thread
From: Felipe Contreras @ 2008-05-05 15:12 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Paul Brook, thayne
[-- Attachment #1: Type: text/plain, Size: 944 bytes --]
Hi,
On Fri, Apr 4, 2008 at 6:03 PM, Marc-André Lureau
<marcandre.lureau@gmail.com> wrote:
> Hi,
>
>
> On Mon, Jan 28, 2008 at 9:27 PM, Felipe Contreras
> <felipe.contreras@gmail.com> wrote:
> >
> > How is this going?
> >
> > The patch works pretty well for me.
> >
>
> Unfortunately, the patch does not apply cleanly anymore.
>
> Is there an updated version somewhere?
>
> regards,
I just updated the patch to current CVS (actually git ;)
Also, I found other similar patches:
http://dev.openbossa.org/trac/mamona/browser/packages/qemu/qemu-0.9.1/qemu-0.9.0-nptl-update.patch
http://dev.openbossa.org/trac/mamona/browser/packages/qemu/qemu-0.9.1/qemu-0.9.0-nptl.patch
And, Paul Brook is supposed to be working on this.
http://lists.gnu.org/archive/html/qemu-devel/2008-04/msg00685.html
Would be nice to know what is the actual status of this, I've updated
the patch multiple times already.
Best regards.
--
Felipe Contreras
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 09_arm_eabitls_felipec.patch --]
[-- Type: text/x-patch; name=09_arm_eabitls_felipec.patch, Size: 29721 bytes --]
commit 84135872f57ed0bbae528c589bca51ddf161663f
Author: Felipe Contreras <felipe.contreras@gmail.com>
Date: Mon May 5 17:35:52 2008 +0300
Add NPTL support.
Original patch by Thayne Harbaugh and Paul Brook.
diff --git a/arm.ld b/arm.ld
index e216cbf..08c87a1 100644
--- a/arm.ld
+++ b/arm.ld
@@ -26,6 +26,10 @@ SECTIONS
{ *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
.rela.rodata :
{ *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
+ .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
+ .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
+ .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
+ .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
.rel.got : { *(.rel.got) }
.rela.got : { *(.rela.got) }
.rel.ctors : { *(.rel.ctors) }
diff --git a/configure b/configure
index a2f54b8..912cf5e 100755
--- a/configure
+++ b/configure
@@ -112,6 +112,7 @@ darwin_user="no"
build_docs="no"
uname_release=""
curses="yes"
+nptl="yes"
# OS specific
targetos=`uname -s`
@@ -333,6 +334,8 @@ for opt do
;;
*) echo "ERROR: unknown option $opt"; show_help="yes"
;;
+ --disable-nptl) nptl="no"
+ ;;
esac
done
@@ -430,6 +433,7 @@ echo " --enable-linux-user enable all linux usermode emulation targets"
echo " --disable-linux-user disable all linux usermode emulation targets"
echo " --enable-darwin-user enable all darwin usermode emulation targets"
echo " --disable-darwin-user disable all darwin usermode emulation targets"
+echo " --disable-nptl disable usermode NPTL guest support"
echo " --fmod-lib path to FMOD library"
echo " --fmod-inc path to FMOD includes"
echo " --enable-uname-release=R Return R for uname -r in usermode emulation"
@@ -607,6 +611,23 @@ int main(void) {
}
EOF
+# check NPTL support
+cat > $TMPC <<EOF
+#include <sched.h>
+void foo()
+{
+#ifndef CLONE_SETTLS
+#error bork
+#endif
+}
+EOF
+
+if $cc -c -o $TMPO $TMPC 2> /dev/null ; then
+ :
+else
+ nptl="no"
+fi
+
##########################################
# SDL probe
@@ -805,6 +826,7 @@ echo "brlapi support $brlapi"
echo "Documentation $build_docs"
[ ! -z "$uname_release" ] && \
echo "uname -r $uname_release"
+echo "NPTL support $nptl"
if test $sdl_too_old = "yes"; then
echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -1027,6 +1049,7 @@ if test "$sdl1" = "yes" ; then
echo "SDL_CFLAGS=`$sdl_config --cflags`" >> $config_mak
fi
fi
+
if test "$cocoa" = "yes" ; then
echo "#define CONFIG_COCOA 1" >> $config_h
echo "CONFIG_COCOA=yes" >> $config_mak
@@ -1289,6 +1312,15 @@ if test "$target_user_only" = "yes" -a "$elfload32" = "yes"; then
echo "#define TARGET_HAS_ELFLOAD32 1" >> $config_h
fi
+if test "$nptl" = "yes" ; then
+ case "$target_cpu" in
+ arm | armeb | ppc | ppc64)
+ echo "USE_NPTL=yes" >> $config_mak
+ echo "#define USE_NPTL 1" >> $config_h
+ ;;
+ esac
+fi
+
test -f ${config_h}~ && cmp -s $config_h ${config_h}~ && mv ${config_h}~ $config_h
done # for target in $targets
diff --git a/exec-all.h b/exec-all.h
index 898cf68..22110e9 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -303,218 +303,8 @@ extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
extern void *io_mem_opaque[IO_MEM_NB_ENTRIES];
-#if defined(__hppa__)
-
-typedef int spinlock_t[4];
-
-#define SPIN_LOCK_UNLOCKED { 1, 1, 1, 1 }
-
-static inline void resetlock (spinlock_t *p)
-{
- (*p)[0] = (*p)[1] = (*p)[2] = (*p)[3] = 1;
-}
-
-#else
-
-typedef int spinlock_t;
-
-#define SPIN_LOCK_UNLOCKED 0
-
-static inline void resetlock (spinlock_t *p)
-{
- *p = SPIN_LOCK_UNLOCKED;
-}
-
-#endif
-
-#if defined(__powerpc__)
-static inline int testandset (int *p)
-{
- int ret;
- __asm__ __volatile__ (
- "0: lwarx %0,0,%1\n"
- " xor. %0,%3,%0\n"
- " bne 1f\n"
- " stwcx. %2,0,%1\n"
- " bne- 0b\n"
- "1: "
- : "=&r" (ret)
- : "r" (p), "r" (1), "r" (0)
- : "cr0", "memory");
- return ret;
-}
-#elif defined(__i386__)
-static inline int testandset (int *p)
-{
- long int readval = 0;
-
- __asm__ __volatile__ ("lock; cmpxchgl %2, %0"
- : "+m" (*p), "+a" (readval)
- : "r" (1)
- : "cc");
- return readval;
-}
-#elif defined(__x86_64__)
-static inline int testandset (int *p)
-{
- long int readval = 0;
-
- __asm__ __volatile__ ("lock; cmpxchgl %2, %0"
- : "+m" (*p), "+a" (readval)
- : "r" (1)
- : "cc");
- return readval;
-}
-#elif defined(__s390__)
-static inline int testandset (int *p)
-{
- int ret;
-
- __asm__ __volatile__ ("0: cs %0,%1,0(%2)\n"
- " jl 0b"
- : "=&d" (ret)
- : "r" (1), "a" (p), "0" (*p)
- : "cc", "memory" );
- return ret;
-}
-#elif defined(__alpha__)
-static inline int testandset (int *p)
-{
- int ret;
- unsigned long one;
-
- __asm__ __volatile__ ("0: mov 1,%2\n"
- " ldl_l %0,%1\n"
- " stl_c %2,%1\n"
- " beq %2,1f\n"
- ".subsection 2\n"
- "1: br 0b\n"
- ".previous"
- : "=r" (ret), "=m" (*p), "=r" (one)
- : "m" (*p));
- return ret;
-}
-#elif defined(__sparc__)
-static inline int testandset (int *p)
-{
- int ret;
-
- __asm__ __volatile__("ldstub [%1], %0"
- : "=r" (ret)
- : "r" (p)
- : "memory");
-
- return (ret ? 1 : 0);
-}
-#elif defined(__arm__)
-static inline int testandset (int *spinlock)
-{
- register unsigned int ret;
- __asm__ __volatile__("swp %0, %1, [%2]"
- : "=r"(ret)
- : "0"(1), "r"(spinlock));
-
- return ret;
-}
-#elif defined(__mc68000)
-static inline int testandset (int *p)
-{
- char ret;
- __asm__ __volatile__("tas %1; sne %0"
- : "=r" (ret)
- : "m" (p)
- : "cc","memory");
- return ret;
-}
-#elif defined(__hppa__)
-
-/* Because malloc only guarantees 8-byte alignment for malloc'd data,
- and GCC only guarantees 8-byte alignment for stack locals, we can't
- be assured of 16-byte alignment for atomic lock data even if we
- specify "__attribute ((aligned(16)))" in the type declaration. So,
- we use a struct containing an array of four ints for the atomic lock
- type and dynamically select the 16-byte aligned int from the array
- for the semaphore. */
-#define __PA_LDCW_ALIGNMENT 16
-static inline void *ldcw_align (void *p) {
- unsigned long a = (unsigned long)p;
- a = (a + __PA_LDCW_ALIGNMENT - 1) & ~(__PA_LDCW_ALIGNMENT - 1);
- return (void *)a;
-}
-
-static inline int testandset (spinlock_t *p)
-{
- unsigned int ret;
- p = ldcw_align(p);
- __asm__ __volatile__("ldcw 0(%1),%0"
- : "=r" (ret)
- : "r" (p)
- : "memory" );
- return !ret;
-}
-
-#elif defined(__ia64)
-
-#include <ia64intrin.h>
-
-static inline int testandset (int *p)
-{
- return __sync_lock_test_and_set (p, 1);
-}
-#elif defined(__mips__)
-static inline int testandset (int *p)
-{
- int ret;
-
- __asm__ __volatile__ (
- " .set push \n"
- " .set noat \n"
- " .set mips2 \n"
- "1: li $1, 1 \n"
- " ll %0, %1 \n"
- " sc $1, %1 \n"
- " beqz $1, 1b \n"
- " .set pop "
- : "=r" (ret), "+R" (*p)
- :
- : "memory");
-
- return ret;
-}
-#else
-#error unimplemented CPU support
-#endif
-
-#if defined(CONFIG_USER_ONLY)
-static inline void spin_lock(spinlock_t *lock)
-{
- while (testandset(lock));
-}
-
-static inline void spin_unlock(spinlock_t *lock)
-{
- resetlock(lock);
-}
-
-static inline int spin_trylock(spinlock_t *lock)
-{
- return !testandset(lock);
-}
-#else
-static inline void spin_lock(spinlock_t *lock)
-{
-}
-
-static inline void spin_unlock(spinlock_t *lock)
-{
-}
-
-static inline int spin_trylock(spinlock_t *lock)
-{
- return 1;
-}
-#endif
-
+#include "qspinlock.h"
+
extern spinlock_t tb_lock;
extern int tb_invalidated_flag;
diff --git a/linux-user/arm/syscall.h b/linux-user/arm/syscall.h
index e7f2e8d..be21cbe 100644
--- a/linux-user/arm/syscall.h
+++ b/linux-user/arm/syscall.h
@@ -28,7 +28,9 @@ struct target_pt_regs {
#define ARM_SYSCALL_BASE 0x900000
#define ARM_THUMB_SYSCALL 0
-#define ARM_NR_cacheflush (ARM_SYSCALL_BASE + 0xf0000 + 2)
+#define ARM_NR_BASE 0xf0000
+#define ARM_NR_cacheflush (ARM_NR_BASE + 2)
+#define ARM_NR_set_tls (ARM_NR_BASE + 5)
#define ARM_NR_semihosting 0x123456
#define ARM_NR_thumb_semihosting 0xAB
diff --git a/linux-user/main.c b/linux-user/main.c
index 2125aa5..c85e484 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -365,6 +365,50 @@ static void arm_cache_flush(abi_ulong start, abi_ulong last)
}
}
+/* Handle a jump to the kernel code page. */
+static int
+do_kernel_trap(CPUARMState *env)
+{
+ uint32_t addr;
+ uint32_t *ptr;
+ uint32_t cpsr;
+
+ switch (env->regs[15]) {
+ case 0xffff0fc0: /* __kernel_cmpxchg */
+ /* XXX: This only works between threads, not between processes.
+ Use native atomic operations. */
+ /* ??? This probably breaks horribly if the access segfaults. */
+ cpu_lock();
+ ptr = (uint32_t *)env->regs[2];
+ cpsr = cpsr_read(env);
+ if (*ptr == env->regs[0]) {
+ *ptr = env->regs[1];
+ env->regs[0] = 0;
+ cpsr |= CPSR_C;
+ } else {
+ env->regs[0] = -1;
+ cpsr &= ~CPSR_C;
+ }
+ cpsr_write(env, cpsr, CPSR_C);
+ cpu_unlock();
+ break;
+ case 0xffff0fe0: /* __kernel_get_tls */
+ env->regs[0] = env->cp15.c13_tls3;
+ break;
+ default:
+ return 1;
+ }
+ /* Jump back to the caller. */
+ addr = env->regs[14];
+ if (addr & 1) {
+ env->thumb = 1;
+ addr &= ~1;
+ }
+ env->regs[15] = addr;
+
+ return 0;
+}
+
void cpu_loop(CPUARMState *env)
{
int trapnr;
@@ -475,10 +519,8 @@ void cpu_loop(CPUARMState *env)
}
}
- if (n == ARM_NR_cacheflush) {
- arm_cache_flush(env->regs[0], env->regs[1]);
- } else if (n == ARM_NR_semihosting
- || n == ARM_NR_thumb_semihosting) {
+ if (n == ARM_NR_semihosting
+ || n == ARM_NR_thumb_semihosting) {
env->regs[0] = do_arm_semihosting (env);
} else if (n == 0 || n >= ARM_SYSCALL_BASE
|| (env->thumb && n == ARM_THUMB_SYSCALL)) {
@@ -489,6 +531,26 @@ void cpu_loop(CPUARMState *env)
n -= ARM_SYSCALL_BASE;
env->eabi = 0;
}
+ if (n > ARM_NR_BASE) {
+ switch (n)
+ {
+ case ARM_NR_cacheflush:
+ arm_cache_flush(env->regs[0], env->regs[1]);
+ break;
+#ifdef USE_NPTL
+ case ARM_NR_set_tls:
+ cpu_set_tls(env, env->regs[0]);
+ env->regs[0] = 0;
+ break;
+#endif
+ default:
+ printf ("Error: Bad syscall: %x\n", n);
+ env->regs[0] = -TARGET_ENOSYS;
+ goto error;
+ }
+ }
+ else
+ {
env->regs[0] = do_syscall(env,
n,
env->regs[0],
@@ -497,7 +559,9 @@ void cpu_loop(CPUARMState *env)
env->regs[3],
env->regs[4],
env->regs[5]);
+ }
} else {
+ printf ("Error: Bad syscall: %x\n", n);
goto error;
}
}
@@ -535,6 +599,10 @@ void cpu_loop(CPUARMState *env)
}
}
break;
+ case EXCP_KERNEL_TRAP:
+ if (do_kernel_trap(env))
+ goto error;
+ break;
default:
error:
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
@@ -2403,6 +2471,10 @@ int main(int argc, char **argv)
ts->heap_base = info->brk;
/* This will be filled in on the first SYS_HEAPINFO call. */
ts->heap_limit = 0;
+ /* Register the magic kernel code page. The cpu will generate a
+ special exception when it tries to execute code here. We can't
+ put real code here because it may be in use by the host kernel. */
+ page_set_flags(0xffff0000, 0xffff0fff, 0);
#endif
if (gdbstub_port) {
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index b33ad89..5b54c29 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -109,6 +109,9 @@ typedef struct TaskState {
#endif
int used; /* non zero if used */
struct image_info *info;
+#ifdef USE_NPTL
+ abi_ulong child_tid_addr;
+#endif
uint8_t stack[0];
} __attribute__((aligned(16))) TaskState;
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index b1dc365..34a0647 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -70,9 +70,18 @@
#include <linux/kd.h>
#include "qemu.h"
+#include "qspinlock.h"
//#define DEBUG
+#ifdef USE_NPTL
+#define CLONE_NPTL_FLAGS2 (CLONE_SETTLS | \
+ CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)
+#else
+/* XXX: Hardcode the above values. */
+#define CLONE_NPTL_FLAGS2 0
+#endif
+
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \
|| defined(TARGET_M68K) || defined(TARGET_SH4) || defined(TARGET_CRIS)
/* 16 bit uid wrappers emulation */
@@ -2700,9 +2709,19 @@ abi_long do_arch_prctl(CPUX86State *env, int code, abi_ulong addr)
thread/process */
#define NEW_STACK_SIZE 8192
+#ifdef USE_NPTL
+static spinlock_t nptl_lock = SPIN_LOCK_UNLOCKED;
+#endif
+
static int clone_func(void *arg)
{
CPUState *env = arg;
+#ifdef USE_NPTL
+ /* Wait until the parent has finshed initializing the tls state. */
+ while (!spin_trylock(&nptl_lock))
+ usleep(1);
+ spin_unlock(&nptl_lock);
+#endif
cpu_loop(env);
/* never exits */
return 0;
@@ -2710,12 +2729,24 @@ static int clone_func(void *arg)
/* do_fork() Must return host values and target errnos (unlike most
do_*() functions). */
-int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp)
+int do_fork(CPUState *env,
+ unsigned int flags,
+ abi_ulong new_stk_addr,
+ abi_ulong parent_tid_addr,
+ abi_ulong newtls_addr,
+ abi_ulong child_tid_addr)
{
int ret;
TaskState *ts;
uint8_t *new_stack;
CPUState *new_env;
+#ifdef USE_NPTL
+ unsigned int nptl_flags;
+
+ if (flags & CLONE_PARENT_SETTID)
+ if (put_user_s32(gettid(), parent_tid_addr))
+ return -TARGET_EFAULT;
+#endif
if (flags & CLONE_VM) {
ts = malloc(sizeof(TaskState) + NEW_STACK_SIZE);
@@ -2727,34 +2758,27 @@ int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp)
first_task_state = ts;
/* we create a new CPU instance. */
new_env = cpu_copy(env);
+ if (!new_stk_addr)
+ new_stk_addr = get_sp_from_cpustate(env);
#if defined(TARGET_I386)
- if (!newsp)
- newsp = env->regs[R_ESP];
- new_env->regs[R_ESP] = newsp;
+ new_env->regs[R_ESP] = new_stk_addr;
new_env->regs[R_EAX] = 0;
#elif defined(TARGET_ARM)
- if (!newsp)
- newsp = env->regs[13];
- new_env->regs[13] = newsp;
+ new_env->regs[13] = new_stk_addr;
new_env->regs[0] = 0;
#elif defined(TARGET_SPARC)
- if (!newsp)
- newsp = env->regwptr[22];
- new_env->regwptr[22] = newsp;
+ new_env->regwptr[22] = new_stk_addr;
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->aregs[7] = new_stk_addr;
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;
+ new_env->gpr[29][env->current_tc] = new_stk_addr;
#elif defined(TARGET_PPC)
+ new_env->gpr[1] = new_stk_addr;
if (!newsp)
newsp = env->gpr[1];
new_env->gpr[1] = newsp;
@@ -2764,14 +2788,10 @@ int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp)
new_env->gpr[i] = 0;
}
#elif defined(TARGET_SH4)
- if (!newsp)
- newsp = env->gregs[15];
- new_env->gregs[15] = newsp;
+ new_env->gregs[15] = new_stk_addr;
/* XXXXX */
#elif defined(TARGET_ALPHA)
- if (!newsp)
- newsp = env->ir[30];
- new_env->ir[30] = newsp;
+ new_env->ir[30] = new_stk_addr;
/* ? */
{
int i;
@@ -2779,23 +2799,71 @@ int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp)
new_env->ir[i] = 0;
}
#elif defined(TARGET_CRIS)
- if (!newsp)
- newsp = env->regs[14];
- new_env->regs[14] = newsp;
+ new_env->regs[14] = new_stk_addr;
#else
#error unsupported target CPU
#endif
new_env->opaque = ts;
+#ifdef USE_NPTL
+ nptl_flags = flags;
+ flags &= ~CLONE_NPTL_FLAGS2;
+
+ if (nptl_flags & CLONE_CHILD_CLEARTID) {
+ ts->child_tid_addr = child_tid_addr;
+ }
+
+ if (nptl_flags & CLONE_SETTLS)
+ cpu_set_tls(new_env, newtls_addr);
+
+ /* Grab the global cpu lock so that the thread setup appears
+ atomic. */
+ if (nptl_flags & CLONE_CHILD_SETTID)
+ spin_lock(&nptl_lock);
+
+#else
+ if (flags & CLONE_NPTL_FLAGS2)
+ return -EINVAL;
+#endif
#ifdef __ia64__
ret = __clone2(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
#else
ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
#endif
+#ifdef USE_NPTL
+ if (ret != -1) {
+ if (nptl_flags & CLONE_CHILD_SETTID)
+ if (put_user_s32(ret, child_tid_addr))
+ return -TARGET_EFAULT;
+ }
+
+ /* Allow the child to continue. */
+ if (nptl_flags & CLONE_CHILD_SETTID)
+ spin_unlock(&nptl_lock);
+#endif
} else {
/* if no CLONE_VM, we consider it is a fork */
- if ((flags & ~CSIGNAL) != 0)
+ if ((flags & ~(CSIGNAL | CLONE_NPTL_FLAGS2)) != 0)
return -EINVAL;
ret = fork();
+#ifdef USE_NPTL
+ /* There is a race condition here. The parent process could
+ theoretically read the TID in the child process before the child
+ tid is set. This would require using either ptrace
+ (not implemented) or having *_tidptr to point at a shared memory
+ mapping. We can't repeat the spinlock hack used above because
+ the child process gets its own copy of the lock. */
+ if (ret == 0) {
+ /* Child Process. */
+ if (flags & CLONE_CHILD_SETTID)
+ if (put_user_s32(gettid(), child_tid_addr))
+ return -TARGET_EFAULT;
+ ts = (TaskState *)env->opaque;
+ if (flags & CLONE_CHILD_CLEARTID)
+ ts->child_tid_addr = child_tid_addr;
+ if (flags & CLONE_SETTLS)
+ cpu_set_tls(env, newtls_addr);
+ }
+#endif
}
return ret;
}
@@ -3120,7 +3188,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = do_brk(arg1);
break;
case TARGET_NR_fork:
- ret = get_errno(do_fork(cpu_env, SIGCHLD, 0));
+ ret = get_errno(do_fork(cpu_env, SIGCHLD, 0, 0, 0, 0));
break;
#ifdef TARGET_NR_waitpid
case TARGET_NR_waitpid:
@@ -4483,7 +4551,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
ret = get_errno(fsync(arg1));
break;
case TARGET_NR_clone:
- ret = get_errno(do_fork(cpu_env, arg1, arg2));
+ ret = get_errno(do_fork(cpu_env, arg1, arg2, arg3, arg4, arg5));
break;
#ifdef __NR_exit_group
/* new thread calls */
@@ -4919,7 +4987,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#endif
#ifdef TARGET_NR_vfork
case TARGET_NR_vfork:
- ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0));
+ ret = get_errno(do_fork(cpu_env,
+ CLONE_VFORK | CLONE_VM | SIGCHLD,
+ 0, 0, 0, 0));
break;
#endif
#ifdef TARGET_NR_ugetrlimit
diff --git a/qspinlock.h b/qspinlock.h
new file mode 100644
index 0000000..2332eba
--- /dev/null
+++ b/qspinlock.h
@@ -0,0 +1,235 @@
+/*
+ * Atomic operation helper include
+ *
+ * Copyright (c) 2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef QSPINLOCK_H
+#define QSPINLOCK_H
+
+#if defined(__hppa__)
+
+typedef int spinlock_t[4];
+
+#define SPIN_LOCK_UNLOCKED { 1, 1, 1, 1 }
+
+static inline void resetlock (spinlock_t *p)
+{
+ (*p)[0] = (*p)[1] = (*p)[2] = (*p)[3] = 1;
+}
+
+#else
+
+typedef int spinlock_t;
+
+#define SPIN_LOCK_UNLOCKED 0
+
+static inline void resetlock (spinlock_t *p)
+{
+ *p = SPIN_LOCK_UNLOCKED;
+}
+
+#endif
+
+#if defined(__powerpc__)
+static inline int testandset (int *p)
+{
+ int ret;
+ __asm__ __volatile__ (
+ "0: lwarx %0,0,%1\n"
+ " xor. %0,%3,%0\n"
+ " bne 1f\n"
+ " stwcx. %2,0,%1\n"
+ " bne- 0b\n"
+ "1: "
+ : "=&r" (ret)
+ : "r" (p), "r" (1), "r" (0)
+ : "cr0", "memory");
+ return ret;
+}
+#elif defined(__i386__)
+static inline int testandset (int *p)
+{
+ long int readval = 0;
+
+ __asm__ __volatile__ ("lock; cmpxchgl %2, %0"
+ : "+m" (*p), "+a" (readval)
+ : "r" (1)
+ : "cc");
+ return readval;
+}
+#elif defined(__x86_64__)
+static inline int testandset (int *p)
+{
+ long int readval = 0;
+
+ __asm__ __volatile__ ("lock; cmpxchgl %2, %0"
+ : "+m" (*p), "+a" (readval)
+ : "r" (1)
+ : "cc");
+ return readval;
+}
+#elif defined(__s390__)
+static inline int testandset (int *p)
+{
+ int ret;
+
+ __asm__ __volatile__ ("0: cs %0,%1,0(%2)\n"
+ " jl 0b"
+ : "=&d" (ret)
+ : "r" (1), "a" (p), "0" (*p)
+ : "cc", "memory" );
+ return ret;
+}
+#elif defined(__alpha__)
+static inline int testandset (int *p)
+{
+ int ret;
+ unsigned long one;
+
+ __asm__ __volatile__ ("0: mov 1,%2\n"
+ " ldl_l %0,%1\n"
+ " stl_c %2,%1\n"
+ " beq %2,1f\n"
+ ".subsection 2\n"
+ "1: br 0b\n"
+ ".previous"
+ : "=r" (ret), "=m" (*p), "=r" (one)
+ : "m" (*p));
+ return ret;
+}
+#elif defined(__sparc__)
+static inline int testandset (int *p)
+{
+ int ret;
+
+ __asm__ __volatile__("ldstub [%1], %0"
+ : "=r" (ret)
+ : "r" (p)
+ : "memory");
+
+ return (ret ? 1 : 0);
+}
+#elif defined(__arm__)
+static inline int testandset (int *spinlock)
+{
+ register unsigned int ret;
+ __asm__ __volatile__("swp %0, %1, [%2]"
+ : "=r"(ret)
+ : "0"(1), "r"(spinlock));
+
+ return ret;
+}
+#elif defined(__mc68000)
+static inline int testandset (int *p)
+{
+ char ret;
+ __asm__ __volatile__("tas %1; sne %0"
+ : "=r" (ret)
+ : "m" (p)
+ : "cc","memory");
+ return ret;
+}
+#elif defined(__hppa__)
+
+/* Because malloc only guarantees 8-byte alignment for malloc'd data,
+ and GCC only guarantees 8-byte alignment for stack locals, we can't
+ be assured of 16-byte alignment for atomic lock data even if we
+ specify "__attribute ((aligned(16)))" in the type declaration. So,
+ we use a struct containing an array of four ints for the atomic lock
+ type and dynamically select the 16-byte aligned int from the array
+ for the semaphore. */
+#define __PA_LDCW_ALIGNMENT 16
+static inline void *ldcw_align (void *p) {
+ unsigned long a = (unsigned long)p;
+ a = (a + __PA_LDCW_ALIGNMENT - 1) & ~(__PA_LDCW_ALIGNMENT - 1);
+ return (void *)a;
+}
+
+static inline int testandset (spinlock_t *p)
+{
+ unsigned int ret;
+ p = ldcw_align(p);
+ __asm__ __volatile__("ldcw 0(%1),%0"
+ : "=r" (ret)
+ : "r" (p)
+ : "memory" );
+ return !ret;
+}
+
+#elif defined(__ia64)
+
+#include <ia64intrin.h>
+
+static inline int testandset (int *p)
+{
+ return __sync_lock_test_and_set (p, 1);
+}
+#elif defined(__mips__)
+static inline int testandset (int *p)
+{
+ int ret;
+
+ __asm__ __volatile__ (
+ " .set push \n"
+ " .set noat \n"
+ " .set mips2 \n"
+ "1: li $1, 1 \n"
+ " ll %0, %1 \n"
+ " sc $1, %1 \n"
+ " beqz $1, 1b \n"
+ " .set pop "
+ : "=r" (ret), "+R" (*p)
+ :
+ : "memory");
+
+ return ret;
+}
+#else
+#error unimplemented CPU support
+#endif
+
+#if defined(CONFIG_USER_ONLY)
+static inline void spin_lock(spinlock_t *lock)
+{
+ while (testandset(lock));
+}
+
+static inline void spin_unlock(spinlock_t *lock)
+{
+ resetlock(lock);
+}
+
+static inline int spin_trylock(spinlock_t *lock)
+{
+ return !testandset(lock);
+}
+#else
+static inline void spin_lock(spinlock_t *lock)
+{
+}
+
+static inline void spin_unlock(spinlock_t *lock)
+{
+}
+
+static inline int spin_trylock(spinlock_t *lock)
+{
+ return 1;
+}
+#endif
+
+#endif /* QSPINLOCK_H */
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 2ff25a5..ddae750 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -37,7 +37,11 @@
#define EXCP_IRQ 5
#define EXCP_FIQ 6
#define EXCP_BKPT 7
+#if defined(CONFIG_USER_ONLY)
+#define EXCP_KERNEL_TRAP 8 /* Jumped to kernel code page. */
+#else
#define EXCP_EXCEPTION_EXIT 8 /* Return from v7M exception. */
+#endif
#define ARMV7M_EXCP_RESET 1
#define ARMV7M_EXCP_NMI 2
@@ -217,6 +221,12 @@ int cpu_arm_signal_handler(int host_signum, void *pinfo,
void cpu_lock(void);
void cpu_unlock(void);
+#if defined(USE_NPTL)
+static inline void cpu_set_tls(CPUARMState *env, uint32_t newtls_addr)
+{
+ env->cp15.c13_tls3 = newtls_addr;
+}
+#endif
#define CPSR_M (0x1f)
#define CPSR_T (1 << 5)
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 4678586..6cece6e 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -8599,13 +8599,20 @@ static inline int gen_intermediate_code_internal(CPUState *env,
store_cpu_field(tmp, condexec_bits);
}
do {
-#ifndef CONFIG_USER_ONLY
+#if defined(CONFIG_USER_ONLY)
+ /* Intercept jump to the magic kernel page. */
+ if (dc->pc > 0xffff0000) {
+ gen_exception(EXCP_KERNEL_TRAP);
+ dc->is_jmp = DISAS_UPDATE;
+ break;
+ }
+#else /* !defined(CONFIG_USER_ONLY) */
if (dc->pc >= 0xfffffff0 && IS_M(env)) {
/* We always get here via a jump, so know we are not in a
conditional execution block. */
gen_exception(EXCP_EXCEPTION_EXIT);
}
-#endif
+#endif /* !defined(CONFIG_USER_ONLY) */
if (env->nb_breakpoints > 0) {
for(j = 0; j < env->nb_breakpoints; j++) {
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 8812975..30fae1c 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -712,6 +712,12 @@ int cpu_ppc_signal_handler (int host_signum, void *pinfo,
void do_interrupt (CPUPPCState *env);
void ppc_hw_interrupt (CPUPPCState *env);
void cpu_loop_exit (void);
+#if defined(USE_NPTL)
+static inline void cpu_set_tls(CPUPPCState *env, ppc_gpr_t newtls_addr)
+{
+ env->gpr[2] = newtls_addr;
+}
+#endif
void dump_stack (CPUPPCState *env);
^ permalink raw reply related [flat|nested] 11+ messages in thread
end of thread, other threads:[~2008-05-05 15:12 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-12-12 0:44 [Qemu-devel] [PATCH] arm eabi TLS Thayne Harbaugh
2007-12-12 1:29 ` Paul Brook
2007-12-12 23:03 ` Fabrice Bellard
2007-12-13 1:21 ` Paul Brook
2007-12-13 1:15 ` Thayne Harbaugh
2008-01-28 18:27 ` Felipe Contreras
2008-04-04 15:03 ` Marc-André Lureau
2008-04-04 17:48 ` Stuart Anderson
2008-05-05 15:12 ` Felipe Contreras
2007-12-13 8:57 ` Fabrice Bellard
2007-12-13 13:28 ` Daniel Jacobowitz
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).