Patchwork i386-linux-user NPTL support

login
register
mail settings
Submitter Ulrich Hecht
Date Aug. 20, 2009, 4:19 p.m.
Message ID <1250785143-24969-1-git-send-email-uli@suse.de>
Download mbox | patch
Permalink /patch/31746/
State Superseded
Headers show

Comments

Ulrich Hecht - Aug. 20, 2009, 4:19 p.m.
Makes NPTL binaries run by implementing TLS.

Signed-off-by: Ulrich Hecht <uli@suse.de>
---
 configure            |    1 +
 linux-user/syscall.c |   16 ++++++++++++++--
 2 files changed, 15 insertions(+), 2 deletions(-)
Nathan Froyd - Aug. 20, 2009, 4:43 p.m.
On Thu, Aug 20, 2009 at 06:19:03PM +0200, Ulrich Hecht wrote:
> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> -        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
Ulrich Hecht - Aug. 21, 2009, 10:10 a.m.
On Thursday 20 August 2009, Nathan Froyd wrote:
> 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.

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
Nathan Froyd - Aug. 21, 2009, 1:11 p.m.
On Fri, Aug 21, 2009 at 12:10:31PM +0200, Ulrich Hecht wrote:
> On Thursday 20 August 2009, Nathan Froyd wrote:
> > 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
> 
> 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

Patch

diff --git a/configure b/configure
index 824b21c..c3c5d4a 100755
--- a/configure
+++ b/configure
@@ -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
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 5778e32..bbaec3d 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -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