Skip to contentSkip to conversation

i386-linux-user NPTL support

PATCH In review Ulrich Hecht 2 participants 4 messages Aug 20, 2009 – Aug 21, 2009

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 i386-linux-user NPTL support

Makes NPTL binaries run by implementing TLS.

---
 configure            |    1 +
 linux-user/syscall.c |   16 ++++++++++++++--
 2 files changed, 15 insertions(+), 2 deletions(-)
configure +1 -0
index 824b21c..c3c5d4a 100755
@@ -1894,6 +1894,7 @@ TARGET_ABI_DIR=""
 case "$target_arch2" in
   i386)
     target_phys_bits=32
+    target_nptl="yes"
   ;;
   x86_64)
     TARGET_BASE_ARCH=i386
linux-user/syscall.c +14 -2
index 5778e32..bbaec3d 100644
@@ -3730,8 +3730,14 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp,
             ts->child_tidptr = child_tidptr;
         }
 
-        if (nptl_flags & CLONE_SETTLS)
+        if (nptl_flags & CLONE_SETTLS) {
+#if defined(TARGET_I386) && defined(TARGET_ABI32)
+            do_set_thread_area(new_env, newtls);
+            cpu_x86_load_seg(new_env, R_GS, new_env->segs[R_GS].selector);
+#else
             cpu_set_tls (new_env, newtls);
+#endif
+        }
 
         /* Grab a mutex so that thread setup appears atomic.  */
         pthread_mutex_lock(&clone_lock);
@@ -3804,8 +3810,14 @@ static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp,
             if (flags & CLONE_PARENT_SETTID)
                 put_user_u32(gettid(), parent_tidptr);
             ts = (TaskState *)env->opaque;
-            if (flags & CLONE_SETTLS)
+            if (flags & CLONE_SETTLS) {
+#if defined(TARGET_I386) && defined(TARGET_ABI32)
+                do_set_thread_area(env, newtls);
+                cpu_x86_load_seg(env, R_GS, env->segs[R_GS].selector);
+#else
                 cpu_set_tls (env, newtls);
+#endif
+            }
             if (flags & CLONE_CHILD_CLEARTID)
                 ts->child_tidptr = child_tidptr;
 #endif
Signature · 1 line
1.6.4
#1 lore raw

linux-user/syscall.c static int do_fork(CPUState *env, unsigned int flags, abi_ulong newsp, · line 3740

Quoted 10 lines · Ulrich Hecht
linux-user/syscall.c +7 -1
-        if (nptl_flags & CLONE_SETTLS)
+        if (nptl_flags & CLONE_SETTLS) {
+#if defined(TARGET_I386) && defined(TARGET_ABI32)
+            do_set_thread_area(new_env, newtls);
+            cpu_x86_load_seg(new_env, R_GS, new_env->segs[R_GS].selector);
+#else
             cpu_set_tls (new_env, newtls);
+#endif
+        }

Why not just stick things in cpu_set_tls in target-i386/cpu.h like so:

#if defined(TARGET-I386) && defined(TARGET_ABI32) static inline void cpu_set_tls(CPUState *env, target_ulong newtls)

{
    do_set_thread_area(env, newtls);
    cpu_x86_load_seg(env, R_GS, env->segs[R_GS].selector);
}

#endif

Less duplicated code and fewer #ifdefs that way and it's still clear that x86-64 linux-user emulation doesn't support NPTL.

-Nathan

#2 lore raw
Quoted 4 lines · Nathan Froyd

Why not just stick things in cpu_set_tls in target-i386/cpu.h like so:

#if defined(TARGET-I386) && defined(TARGET_ABI32) static inline void cpu_set_tls(CPUState *env, target_ulong newtls)

Quoted 8 lines
{
    do_set_thread_area(env, newtls);
    cpu_x86_load_seg(env, R_GS, env->segs[R_GS].selector);
}

#endif

Less duplicated code and fewer #ifdefs that way and it's still clear that x86-64 linux-user emulation doesn't support NPTL.

do_set_thread_area() is declared static in syscall.c, so you would have to unstaticize it, create a prototype somewhere (where?), and you would introduce a dependency between the CPU emulation and the userspace emulation. These problems are all unique to the i386 architecture which doesn't get away with just setting a CPU register like all the others. (Except maybe x86-64, but I don't know how TLS is implemented there.) My solution may not look as clean, but it sidesteps all this, which I thought made it worthwhile to special-case i386 in syscall.c.

CU
Uli

Signature · 1 line
SUSE LINUX Products GmbH, GF: Markus Rex, HRB 16746 (AG Nürnberg)
#3 lore raw
Quoted 11 lines · Ulrich Hecht
Quoted 9 lines · Nathan Froyd

Why not just stick things in cpu_set_tls in target-i386/cpu.h like so:

#if defined(TARGET-I386) && defined(TARGET_ABI32) static inline void cpu_set_tls(CPUState *env, target_ulong newtls)

{
    do_set_thread_area(env, newtls);
    cpu_x86_load_seg(env, R_GS, env->segs[R_GS].selector);
}

#endif

Quoted 5 lines

do_set_thread_area() is declared static in syscall.c, so you would have to unstaticize it, create a prototype somewhere (where?), and you would introduce a dependency between the CPU emulation and the userspace emulation. These problems are all unique to the i386 architecture which doesn't get away with just setting a CPU register like all the others.

Hm, that's a good point. I imagine the problems are similar on x86-64.

My first thought was to simply move do_set_thread_area and cpu_set_tls (the latter for all architectures, not just x86) to linux-user/target-FOO/syscall.h. But that won't work for ARM, since it uses cpu_set_tls in linux-user/main.c. Maybe creating a new file/header for cpu-specific support code would be the right way to do things; you might have to make cpu_set_tls out-of-line, but that's not particularly bad. (This would help with other things, like moving cpu_loop from linux-user/main.c into architecture-specific files.)

But that's a little much to tackle for just x86 NPTL support, I suppose. :)

-Nathan