qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] Fix TLS support on x86
@ 2007-06-08 14:17 Alexander Graf
  2007-06-18 19:21 ` Thiemo Seufer
  0 siblings, 1 reply; 11+ messages in thread
From: Alexander Graf @ 2007-06-08 14:17 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 966 bytes --]

Hi,

this patch is based on the NPTL/TLS patch, David Woodhouse sent to the
list some months ago, which unfortulately did not work for me, so these
are the fixes needed to get it working. After all there is a certain
chance, that I got something wrong but basically it does the following:

1. Implement the tg_kill syscall
2. Set the GS shadow register according to the information
set_thread_area receives. I'm not sure about that part, but using the
qemu internal functions (cpu_x86_load_seg) did not work for me.
3. Implement the "new" (2.5.xx) TID setting features of clone()
4. Use clone() for forking, since fork() did not always work for me
(especially when using TLS)

I'm open for suggestions. Using this patch all single-threaded and most
simple multi-threaded current applications (glibc 2.5) do work.
Everything bigger however does not. If anyone on this list is more into
these things, I would very much appreciate any help.


Regards,

Alexander Graf


[-- Attachment #2: qemu-0.9.0-nptl2.patch --]
[-- Type: text/x-patch, Size: 8994 bytes --]

Index: qemu-0.9.0/linux-user/i386/syscall_nr.h
===================================================================
--- qemu-0.9.0.orig/linux-user/i386/syscall_nr.h
+++ qemu-0.9.0/linux-user/i386/syscall_nr.h
@@ -271,5 +271,6 @@
 #define TARGET_NR_clock_getres	(TARGET_NR_timer_create+7)
 #define TARGET_NR_clock_nanosleep	(TARGET_NR_timer_create+8)
 
+#define TARGET_NR_tgkill		270
 #define TARGET_NR_utimes		271
 #define TARGET_NR_fadvise64_64		272
Index: qemu-0.9.0/linux-user/syscall.c
===================================================================
--- qemu-0.9.0.orig/linux-user/syscall.c
+++ qemu-0.9.0/linux-user/syscall.c
@@ -145,6 +145,8 @@ type name (type1 arg1,type2 arg2,type3 a
 #define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
 #define __NR_sys_syslog __NR_syslog
 #define __NR_sys_fadvise64 __NR_fadvise64
+#define __NR_sys_tgkill __NR_tgkill
+#define __NR_sys_clone __NR_clone
 
 #if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__)
 #define __NR__llseek __NR_lseek
@@ -166,6 +168,8 @@ _syscall5(int, _llseek,  uint,  fd, ulon
 _syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
 _syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
 _syscall4(int,sys_fadvise64,int,fd,loff_t,offset,loff_t,len,int,advice)
+_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
+_syscall5(int,sys_clone, int, flags, void *, child_stack, int *, parent_tidptr, struct user_desc *, newtls, int *, child_tidptr)
 #ifdef __NR_exit_group
 _syscall1(int,exit_group,int,error_code)
 #endif
@@ -1699,7 +1704,7 @@ int do_modify_ldt(CPUX86State *env, int 
     return ret;
 }
 
-int do_set_thread_area(CPUX86State *env, target_ulong ptr)
+int do_set_thread_area(CPUX86State *env, target_ulong ptr, int set_shadow_registers)
 {
     uint64_t *gdt_table = g2h(env->gdt.base);
     struct target_modify_ldt_ldt_s ldt_info;
@@ -1708,6 +1713,7 @@ int do_set_thread_area(CPUX86State *env,
     int seg_not_present, useable;
     uint32_t *lp, entry_1, entry_2;
     int i;
+    SegmentCache *sc = &env->segs[R_GS];
 
     lock_user_struct(target_ldt_info, ptr, 1);
     ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
@@ -1767,6 +1767,12 @@ int do_set_thread_area(CPUX86State *env,
        (useable << 20) |
        0x7000;
 
+    if(set_shadow_registers) {
+        sc->selector = env->regs[R_GS];
+        sc->base = ldt_info.base_addr;
+        sc->limit = ldt_info.limit;
+        sc->flags = entry_2;
+    }
     /* Install the new entry ...  */
 install:
     lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
@@ -1779,20 +1802,21 @@ install:
    thread/process */
 #define NEW_STACK_SIZE 8192
 
-static int clone_func(void *arg)
+static int clone_func(CPUState *cloneenv)
 {
-    CPUState *env = arg;
-    cpu_loop(env);
+    cpu_loop(cloneenv);
     /* never exits */
     return 0;
 }
 
-int do_fork(CPUState *env, unsigned int flags, unsigned long newsp)
+int do_fork(CPUState *env, unsigned int flags, target_ulong newsp, target_ulong parent_tidptr, target_ulong newtls, target_ulong child_tidptr)
 {
     int ret;
+    int cpu_index;
+    unsigned long parent_tid=gettid();
     TaskState *ts;
     uint8_t *new_stack;
-    CPUState *new_env;
+    CPUState *new_env, *next_cpu;
 #if defined(TARGET_I386)
     uint64_t *new_gdt_table;
 #endif
@@ -1807,9 +1835,14 @@ int do_fork(CPUState *env, unsigned int 
         /* add in task state list */
         ts->next = first_task_state;
         first_task_state = ts;
-        /* we create a new CPU instance. */
-        new_env = cpu_init();
-        memcpy(new_env, env, sizeof(CPUState));
+        /* we create a new CPU instance. (cpu_copy() in cvs) */
+	new_env = cpu_init();
+	/* preserve chaining and index */
+	next_cpu = new_env->next_cpu;                                                                                                                  
+	cpu_index = new_env->cpu_index;                                                                                                                      
+	memcpy(new_env, env, sizeof(CPUState));                                                                                                                  
+        new_env->next_cpu = next_cpu;                                                                                                                            
+	new_env->cpu_index = cpu_index;                                                                                                                          
 #if defined(TARGET_I386)
         if (!newsp)
             newsp = env->regs[R_ESP];
@@ -1818,26 +1851,20 @@ int do_fork(CPUState *env, unsigned int 
                 free(new_env);
                 return -ENOMEM;
        }
        /* Copy main GDT table from parent, but clear TLS entries */
        memcpy(new_gdt_table, g2h(env->gdt.base), 6 * 8);
        memset(&new_gdt_table[6], 0, 3 * 8); 
        new_env->gdt.base = h2g(new_gdt_table);
-       if (flags & 0x00080000 /* CLONE_SETTLS */) {
-               ret = do_set_thread_area(new_env, new_env->regs[R_ESI]);
+       if (flags & CLONE_SETTLS) {
+               ret = do_set_thread_area(new_env, newtls, 1);
                if (ret) {
                        free(new_gdt_table);
                        free(new_env);
                        return ret;
                }
        }
-       cpu_x86_load_seg(env, R_CS, new_env->regs[R_CS]);
-       cpu_x86_load_seg(env, R_DS, new_env->regs[R_DS]);
-       cpu_x86_load_seg(env, R_ES, new_env->regs[R_ES]);
-       cpu_x86_load_seg(env, R_SS, new_env->regs[R_SS]);
-       cpu_x86_load_seg(env, R_FS, new_env->regs[R_FS]);
-       cpu_x86_load_seg(env, R_GS, new_env->regs[R_GS]);
         new_env->regs[R_ESP] = newsp;
         new_env->regs[R_EAX] = 0;
 #elif defined(TARGET_ARM)
         if (!newsp)
             newsp = env->regs[13];
@@ -1877,16 +1933,28 @@ int do_fork(CPUState *env, unsigned int 
 #endif
         new_env->opaque = ts;
 #ifdef __ia64__
-        ret = __clone2(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
+	ret = __clone2(clone_func, new_stack + NEW_STACK_SIZE, flags & ~(CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID), new_env);
 #else
-	ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
+	ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags & ~(CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID), new_env);
 #endif
     } else {
         /* if no CLONE_VM, we consider it is a fork */
-        if ((flags & ~CSIGNAL) != 0)
-            return -EINVAL;
-        ret = fork();
+       ret = sys_clone(flags & ~(CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID), 0, g2h(parent_tidptr), NULL, g2h(child_tidptr));
+    }
+    /* Store child thread ID at location parent_tidptr in parent and child memory. 
+       Currently this is only done in client memory*/
+     if(flags & CLONE_PARENT_SETTID) {
+        tput32(parent_tidptr, parent_tid);
+     }
+ 
+    /* Store child thread ID at location child_tidptr in child memory. */
+    if(flags & CLONE_CHILD_SETTID) {
+      if(ret==0) { // only in client memory for fork()
+        tput32(child_tidptr, gettid());
+      } else if(flags & CLONE_VM) { // real threads need it too
+        tput32(child_tidptr, ret);
+      }
     }
     return ret;
 }
 
@@ -2206,7 +2221,7 @@ long do_syscall(void *cpu_env, int num, 
         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;
     case TARGET_NR_waitpid:
         {
@@ -3281,7 +3297,7 @@ long do_syscall(void *cpu_env, int num, 
         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 */
@@ -3339,7 +3397,7 @@ long do_syscall(void *cpu_env, int num, 
         ret = do_vm86(cpu_env, arg1, arg2);
         break;
     case TARGET_NR_set_thread_area:
-       ret = get_errno(do_set_thread_area(cpu_env, arg1));
+       ret = get_errno(do_set_thread_area(cpu_env, arg1, 0));
        break;
 #endif
     case TARGET_NR_adjtimex:
@@ -3635,7 +3651,7 @@ long do_syscall(void *cpu_env, int num, 
 #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
@@ -4164,6 +4180,11 @@ long do_syscall(void *cpu_env, int num, 
 	ret = get_errno(sys_fadvise64((int)arg1, arg2, arg3, (int)arg4));
 	break;
 #endif
+#ifdef TARGET_NR_tgkill
+    case TARGET_NR_tgkill:
+	ret = get_errno(sys_tgkill((int)arg1, (int)arg2, (int)arg3));
+	break;
+#endif
     default:
     unimplemented:
         gemu_log("qemu: Unsupported syscall: %d\n", num);

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH] Fix TLS support on x86
  2007-06-08 14:17 [Qemu-devel] [PATCH] Fix TLS support on x86 Alexander Graf
@ 2007-06-18 19:21 ` Thiemo Seufer
  2007-06-20 16:42   ` Alexander Graf
  0 siblings, 1 reply; 11+ messages in thread
From: Thiemo Seufer @ 2007-06-18 19:21 UTC (permalink / raw)
  To: Alexander Graf; +Cc: qemu-devel

Alexander Graf wrote:
> Hi,
> 
> this patch is based on the NPTL/TLS patch, David Woodhouse sent to the
> list some months ago, which unfortulately did not work for me, so these
> are the fixes needed to get it working. After all there is a certain
> chance, that I got something wrong but basically it does the following:
> 
> 1. Implement the tg_kill syscall
> 2. Set the GS shadow register according to the information
> set_thread_area receives. I'm not sure about that part, but using the
> qemu internal functions (cpu_x86_load_seg) did not work for me.
> 3. Implement the "new" (2.5.xx) TID setting features of clone()
> 4. Use clone() for forking, since fork() did not always work for me
> (especially when using TLS)

Please split the patch per-feature, and make sure it applies to CVS head.
(It fails to apply because it appears to depend on another patch which
adds fadvise64 support.) Also, keep the code formatting style the same as
the surrounding code (line length, space vs. tabs, whitespace around
parentheses, ... ).


Thiemo

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH] Fix TLS support on x86
  2007-06-18 19:21 ` Thiemo Seufer
@ 2007-06-20 16:42   ` Alexander Graf
  2007-06-21  5:31     ` David Woodhouse
       [not found]     ` <20070621225550.GB25967@networkno.de>
  0 siblings, 2 replies; 11+ messages in thread
From: Alexander Graf @ 2007-06-20 16:42 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 2698 bytes --]

Thiemo Seufer wrote:
> Alexander Graf wrote:
>   
>> Hi,
>>
>> this patch is based on the NPTL/TLS patch, David Woodhouse sent to the
>> list some months ago, which unfortulately did not work for me, so these
>> are the fixes needed to get it working. After all there is a certain
>> chance, that I got something wrong but basically it does the following:
>>
>> 1. Implement the tg_kill syscall
>> 2. Set the GS shadow register according to the information
>> set_thread_area receives. I'm not sure about that part, but using the
>> qemu internal functions (cpu_x86_load_seg) did not work for me.
>> 3. Implement the "new" (2.5.xx) TID setting features of clone()
>> 4. Use clone() for forking, since fork() did not always work for me
>> (especially when using TLS)
>>     
>
> Please split the patch per-feature, and make sure it applies to CVS head.
> (It fails to apply because it appears to depend on another patch which
> adds fadvise64 support.) Also, keep the code formatting style the same as
> the surrounding code (line length, space vs. tabs, whitespace around
> parentheses, ... ).
>
>
> Thiemo
>
>
>   
These are all of my patches so far, split as far as I thought might be
helpful and including the patch by David Woodhouse. Basically they are
independent of each other, because they affect similar areas of the
sources it's best to apply them in order though. I believe, I sent the
fadvise64-patch to the list as well some time ago. It is invalid and
everything should work without it as well though.
Would it be better to tgz the patches if I plan to send them to the list?

I hope there are no formatting mistakes left and everything applies
properly to CVS.

qemu-cvs-tgkill.patch

implements the tgkill syscall.

qemu-cvs-tls.patch

implements set_thread_area for x86 and modifies the do_clone function,
so TLS is evaluated. This is 90% done by David Woodhouse, I only changed
it so it works for me (TID setters, proper segment register setters,
fork() fix).

qemu-cvs-futex.patch

implements futexes (this is mostly done by David Woodhouse as well,
FUTEX_WAKE_OP done by me)

qemu-cvs-set_robust_list.patch

set_robust_list is only implemented in > 2.6.16, so it does not hurt to
ignore that one

qemu-cvs-sched_getaffinity.patch

Flash9 needs sys_get_getaffinity to work properly. As far as I can tell
there should be no need for endianness-conversion, because the
information is written bit-wise.

qemu-cvs-wine.patch

Wine checks if %FS is 0, and if it is initializes it properly. This
usually is the case with a normal i586 system (26 in qemu-i386), so we
should emulate that behavior as well. I'm not sure if this is the way to
go though, somehow the code looks ugly ;-)



[-- Attachment #2: qemu-cvs-futex.patch --]
[-- Type: text/x-patch, Size: 4138 bytes --]

Index: qemu/linux-user/syscall.c
===================================================================
--- qemu.orig/linux-user/syscall.c
+++ qemu/linux-user/syscall.c
@@ -17,6 +17,8 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
+
+#define __user
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdarg.h>
@@ -60,6 +62,7 @@
 #define tchars host_tchars /* same as target */
 #define ltchars host_ltchars /* same as target */
 
+#include <linux/futex.h>
 #include <linux/termios.h>
 #include <linux/unistd.h>
 #include <linux/utsname.h>
@@ -2556,6 +2559,91 @@ static inline void host_to_target_timesp
     unlock_user_struct(target_ts, target_addr, 1);
 }
 
+#ifdef BSWAP_NEEDED
+static int futex_op(int oldval, int op, int oparg)
+{
+	int retval = oparg;
+	switch(op) {
+	    case FUTEX_OP_SET: break;
+	    case FUTEX_OP_ADD: retval += oparg; break;
+	    case FUTEX_OP_OR: retval |= oparg; break;
+	    case FUTEX_OP_ANDN: retval &= oparg; break;
+	    case FUTEX_OP_XOR: retval ^= oparg; break;
+	}
+	return retval;
+}
+
+static int futex_cmp(int oldval, int cmp, int cmparg)
+{
+	switch(cmp) {
+	    case FUTEX_OP_CMP_EQ: return oldval == cmparg;
+	    case FUTEX_OP_CMP_NE: return oldval != cmparg;
+	    case FUTEX_OP_CMP_LT: return oldval <  cmparg;
+	    case FUTEX_OP_CMP_LE: return oldval <= cmparg;
+	    case FUTEX_OP_CMP_GT: return oldval >  cmparg;
+	    case FUTEX_OP_CMP_GE: return oldval >= cmparg;
+	}
+	return -1;
+}
+#endif
+
+static long do_futex(target_ulong uaddr, int op, uint32_t val,
+                    target_ulong utime, target_ulong uaddr2,
+                    uint32_t val3)
+{
+       struct timespec host_utime;
+       unsigned long val2 = utime;
+       long retval;
+
+       if (utime && (op == FUTEX_WAIT || op == FUTEX_LOCK_PI)) {
+               target_to_host_timespec(&host_utime, utime);
+               val2 = (unsigned long)&host_utime;
+       }
+ 
+#ifdef BSWAP_NEEDED
+       switch(op) {
+       case FUTEX_CMP_REQUEUE:
+               val3 = tswap32(val3);
+       case FUTEX_REQUEUE:
+               val2 = tswap32(val2);
+       case FUTEX_WAIT:
+       case FUTEX_WAKE:
+       case FUTEX_WAKE_OP:
+               val = tswap32(val);
+       case FUTEX_LOCK_PI: /* This one's icky, but comes out OK */
+       case FUTEX_UNLOCK_PI:
+               break;
+       default: 
+               gemu_log("qemu: Unsupported futex op %d\n", op);
+               spin_unlock(&mmap_lock);
+               return -ENOSYS;
+       } 
+       if (op == FUTEX_WAKE_OP) {
+               /* Need to munge the secondary operation (val3) */
+               val3 = tswap32(val3);
+               int op2 = (val3 >> 28) & 0xf;
+               int cmp = (val3 >> 24) & 0xf;
+               int oparg = (val3 >> 12) & 0xfff;
+               int cmparg = val3 & 0xfff;
+               int shift = val3 & (FUTEX_OP_OPARG_SHIFT << 28);
+               int oldval = tget32(uaddr2);
+               if (shift)
+                   oparg = 1 << oparg;
+
+              tput32(uaddr2,futex_op(oldval, op2, oparg));
+              retval = syscall(__NR_futex, g2h(uaddr), FUTEX_WAKE, val, 0, 0, 0);
+              if(futex_cmp(oldval, cmp, cmparg)) {
+                  retval = syscall(__NR_futex, g2h(uaddr2), FUTEX_WAKE, val2, 0, 0, 0);
+              }
+       } else {
+              retval = syscall(__NR_futex, g2h(uaddr), op, val, val2, g2h(uaddr2), val3);
+       }
+#else
+       retval = syscall(__NR_futex, g2h(uaddr), op, val, val2, g2h(uaddr2), val3);
+#endif
+       return retval;
+}
+
 long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, 
                 long arg4, long arg5, long arg6)
 {
@@ -4715,6 +4804,11 @@ long do_syscall(void *cpu_env, int num, 
     }
 #endif
 
+#ifdef TARGET_NR_futex
+    case TARGET_NR_futex:
+        ret = get_errno(do_futex(arg1, arg2, arg3, arg4, arg5, arg6));
+        break;
+#endif
 #if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
     case TARGET_NR_set_tid_address:
       ret = get_errno(set_tid_address((int *) arg1));

[-- Attachment #3: qemu-cvs-sched_getaffinity.patch --]
[-- Type: text/x-patch, Size: 1332 bytes --]

Index: qemu/linux-user/syscall.c
===================================================================
--- qemu.orig/linux-user/syscall.c
+++ qemu/linux-user/syscall.c
@@ -149,6 +149,7 @@ type name (type1 arg1,type2 arg2,type3 a
 #define __NR_sys_syslog __NR_syslog
 #define __NR_sys_tgkill __NR_tgkill
 #define __NR_sys_clone __NR_clone
+#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
 
 #if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__)
 #define __NR__llseek __NR_lseek
@@ -171,6 +172,7 @@ _syscall3(int,sys_rt_sigqueueinfo,int,pi
 _syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
 _syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
 _syscall5(int,sys_clone, int, flags, void *, child_stack, int *, parent_tidptr, struct user_desc *, newtls, int *, child_tidptr)
+_syscall3(int,sys_sched_getaffinity,pid_t,pid,unsigned int,cpusetsize,void*,mask)
 #ifdef __NR_exit_group
 _syscall1(int,exit_group,int,error_code)
 #endif
@@ -4826,6 +4828,12 @@ long do_syscall(void *cpu_env, int num, 
 	goto unimplemented_nowarn;
 #endif
 
+#ifdef TARGET_NR_sched_getaffinity
+    case TARGET_NR_sched_getaffinity:
+	ret = get_errno(sys_sched_getaffinity((pid_t)arg1, (unsigned int)arg2, (void*)arg3));
+	break;
+#endif
+
     default:
     unimplemented:
         gemu_log("qemu: Unsupported syscall: %d\n", num);

[-- Attachment #4: qemu-cvs-set_robust_list.patch --]
[-- Type: text/x-patch, Size: 1079 bytes --]

Index: qemu/linux-user/i386/syscall_nr.h
===================================================================
--- qemu.orig/linux-user/i386/syscall_nr.h
+++ qemu/linux-user/i386/syscall_nr.h
@@ -273,3 +273,5 @@
 
 #define TARGET_NR_tgkill		270
 #define TARGET_NR_utimes		271
+
+#define TARGET_NR_set_robust_list	311
Index: qemu/linux-user/syscall.c
===================================================================
--- qemu.orig/linux-user/syscall.c
+++ qemu/linux-user/syscall.c
@@ -4821,10 +4821,15 @@ long do_syscall(void *cpu_env, int num, 
 	break;
 #endif
 
+#ifdef TARGET_NR_set_robust_list
+    case TARGET_NR_set_robust_list:
+	goto unimplemented_nowarn;
+#endif
+
     default:
     unimplemented:
         gemu_log("qemu: Unsupported syscall: %d\n", num);
-#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_get_thread_area) || defined(TARGET_NR_getdomainname)
+#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_get_thread_area) || defined(TARGET_NR_getdomainname) || defined(TARGET_NR_set_robust_list)
     unimplemented_nowarn:
 #endif
         ret = -ENOSYS;

[-- Attachment #5: qemu-cvs-tgkill.patch --]
[-- Type: text/x-patch, Size: 1566 bytes --]

Index: qemu/linux-user/i386/syscall_nr.h
===================================================================
--- qemu.orig/linux-user/i386/syscall_nr.h
+++ qemu/linux-user/i386/syscall_nr.h
@@ -271,4 +271,5 @@
 #define TARGET_NR_clock_getres	(TARGET_NR_timer_create+7)
 #define TARGET_NR_clock_nanosleep	(TARGET_NR_timer_create+8)
 
+#define TARGET_NR_tgkill		270
 #define TARGET_NR_utimes		271
Index: qemu/linux-user/syscall.c
===================================================================
--- qemu.orig/linux-user/syscall.c
+++ qemu/linux-user/syscall.c
@@ -144,6 +144,7 @@ type name (type1 arg1,type2 arg2,type3 a
 #define __NR_sys_getdents64 __NR_getdents64
 #define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
 #define __NR_sys_syslog __NR_syslog
+#define __NR_sys_tgkill __NR_tgkill
 
 #if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__)
 #define __NR__llseek __NR_lseek
@@ -164,6 +165,7 @@ _syscall5(int, _llseek,  uint,  fd, ulon
           loff_t *, res, uint, wh);
 _syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
 _syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
+_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
 #ifdef __NR_exit_group
 _syscall1(int,exit_group,int,error_code)
 #endif
@@ -4604,6 +4606,12 @@ long do_syscall(void *cpu_env, int num, 
       break;
 #endif
 
+#ifdef TARGET_NR_tgkill
+    case TARGET_NR_tgkill:
+	ret = get_errno(sys_tgkill((int)arg1, (int)arg2, (int)arg3));
+	break;
+#endif
+
     default:
     unimplemented:
         gemu_log("qemu: Unsupported syscall: %d\n", num);

[-- Attachment #6: qemu-cvs-tls.patch --]
[-- Type: text/x-patch, Size: 9444 bytes --]

Index: qemu/linux-user/main.c
===================================================================
--- qemu.orig/linux-user/main.c
+++ qemu/linux-user/main.c
@@ -156,7 +156,7 @@ static void set_gate(void *ptr, unsigned
     p[1] = tswapl(e2);
 }
 
-uint64_t gdt_table[6];
+uint64_t gdt_table[9];
 uint64_t idt_table[256];
 
 /* only dpl matters as we do only user space emulation */
Index: qemu/linux-user/syscall.c
===================================================================
--- qemu.orig/linux-user/syscall.c
+++ qemu/linux-user/syscall.c
@@ -145,6 +145,7 @@ type name (type1 arg1,type2 arg2,type3 a
 #define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
 #define __NR_sys_syslog __NR_syslog
 #define __NR_sys_tgkill __NR_tgkill
+#define __NR_sys_clone __NR_clone
 
 #if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__)
 #define __NR__llseek __NR_lseek
@@ -166,6 +167,7 @@ _syscall5(int, _llseek,  uint,  fd, ulon
 _syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
 _syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
 _syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
+_syscall5(int,sys_clone, int, flags, void *, child_stack, int *, parent_tidptr, struct user_desc *, newtls, int *, child_tidptr)
 #ifdef __NR_exit_group
 _syscall1(int,exit_group,int,error_code)
 #endif
@@ -2115,29 +2117,109 @@ int do_modify_ldt(CPUX86State *env, int 
     return ret;
 }
 
+int do_set_thread_area(CPUX86State *env, target_ulong ptr)
+{
+    uint64_t *gdt_table = g2h(env->gdt.base);
+    struct target_modify_ldt_ldt_s ldt_info;
+    struct target_modify_ldt_ldt_s *target_ldt_info;
+    int seg_32bit, contents, read_exec_only, limit_in_pages;
+    int seg_not_present, useable;
+    uint32_t *lp, entry_1, entry_2;
+    int i;
+    SegmentCache *sc = &env->segs[R_GS];
+
+    lock_user_struct(target_ldt_info, ptr, 1);
+    ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
+    ldt_info.base_addr = tswapl(target_ldt_info->base_addr);
+    ldt_info.limit = tswap32(target_ldt_info->limit);
+    ldt_info.flags = tswap32(target_ldt_info->flags);
+    if (ldt_info.entry_number == -1) {
+           for (i=6; i<8; i++)
+                   if (gdt_table[i] == 0) {
+                           ldt_info.entry_number = i;
+                           target_ldt_info->entry_number = tswap32(i);
+                           break;
+                   }
+    }
+    unlock_user_struct(target_ldt_info, ptr, 0);
+    
+    if (ldt_info.entry_number < 6 || ldt_info.entry_number > 8)
+           return -EINVAL;
+    seg_32bit = ldt_info.flags & 1;
+    contents = (ldt_info.flags >> 1) & 3;
+    read_exec_only = (ldt_info.flags >> 3) & 1;
+    limit_in_pages = (ldt_info.flags >> 4) & 1;
+    seg_not_present = (ldt_info.flags >> 5) & 1;
+    useable = (ldt_info.flags >> 6) & 1;
+
+    if (contents == 3) {
+        if (seg_not_present == 0)
+            return -EINVAL;
+    }
+
+    /* NOTE: same code as Linux kernel */
+    /* Allow LDTs to be cleared by the user. */
+    if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
+        if ((contents == 0             &&
+             read_exec_only == 1       &&
+             seg_32bit == 0            &&
+             limit_in_pages == 0       &&
+             seg_not_present == 1      &&
+             useable == 0 )) {
+            entry_1 = 0;
+            entry_2 = 0;
+            goto install;
+        }
+    }
+    
+    entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
+        (ldt_info.limit & 0x0ffff);
+    entry_2 = (ldt_info.base_addr & 0xff000000) |
+        ((ldt_info.base_addr & 0x00ff0000) >> 16) |
+        (ldt_info.limit & 0xf0000) |
+        ((read_exec_only ^ 1) << 9) |
+        (contents << 10) |
+        ((seg_not_present ^ 1) << 15) |
+        (seg_32bit << 22) |
+        (limit_in_pages << 23) |
+       (useable << 20) |
+       0x7000;
+
+    /* Install the new entry ...  */
+install:
+    lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
+    lp[0] = tswap32(entry_1);
+    lp[1] = tswap32(entry_2);
+    return 0;
+}
 #endif /* defined(TARGET_I386) */
 
 /* this stack is the equivalent of the kernel stack associated with a
    thread/process */
 #define NEW_STACK_SIZE 8192
 
-static int clone_func(void *arg)
+static int clone_func(CPUState *cloneenv)
 {
-    CPUState *env = arg;
-    cpu_loop(env);
+    cpu_loop(cloneenv);
     /* never exits */
     return 0;
 }
 
-int do_fork(CPUState *env, unsigned int flags, unsigned long newsp)
+int do_fork(CPUState *env, unsigned int flags, target_ulong newsp, target_ulong parent_tidptr, target_ulong newtls, target_ulong child_tidptr)
 {
     int ret;
+    int cpu_index;
+    unsigned long parent_tid=gettid();
     TaskState *ts;
     uint8_t *new_stack;
-    CPUState *new_env;
-    
+    CPUState *new_env, *next_cpu;
+#if defined(TARGET_I386)
+    uint64_t *new_gdt_table;
+#endif
     if (flags & CLONE_VM) {
         ts = malloc(sizeof(TaskState) + NEW_STACK_SIZE);
+        if (!ts)
+                return -ENOMEM;
         memset(ts, 0, sizeof(TaskState));
         new_stack = ts->stack;
         ts->used = 1;
@@ -2149,6 +2231,27 @@ int do_fork(CPUState *env, unsigned int 
 #if defined(TARGET_I386)
         if (!newsp)
             newsp = env->regs[R_ESP];
+        new_gdt_table = malloc(9 * 8);
+        if (!new_gdt_table) {
+                free(new_env);
+                return -ENOMEM;
+        }
+        /* Copy main GDT table from parent, but clear TLS entries */
+        memcpy(new_gdt_table, g2h(env->gdt.base), 6 * 8);
+        memset(&new_gdt_table[6], 0, 3 * 8); 
+        new_env->gdt.base = h2g(new_gdt_table);
+        if (flags & CLONE_SETTLS) {
+               ret = do_set_thread_area(new_env, newtls);
+               if (ret) {
+                       free(new_gdt_table);
+                       free(new_env);
+                       return ret;
+               }
+        }
+	
+	 cpu_x86_load_seg(new_env, R_FS, new_env->segs[R_FS].selector);
+        cpu_x86_load_seg(new_env, R_GS, new_env->segs[R_GS].selector);
+	
         new_env->regs[R_ESP] = newsp;
         new_env->regs[R_EAX] = 0;
 #elif defined(TARGET_ARM)
@@ -2202,15 +2305,27 @@ int do_fork(CPUState *env, unsigned int 
 #endif
         new_env->opaque = ts;
 #ifdef __ia64__
-        ret = __clone2(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
+	ret = __clone2(clone_func, new_stack + NEW_STACK_SIZE, flags & ~(CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID), new_env);
 #else
-	ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
+	ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags & ~(CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID), new_env);
 #endif
     } else {
         /* if no CLONE_VM, we consider it is a fork */
-        if ((flags & ~CSIGNAL) != 0)
-            return -EINVAL;
-        ret = fork();
+	ret = sys_clone(flags & ~(CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID), 0, g2h(parent_tidptr), NULL, g2h(child_tidptr));
+    }
+    /* Store child thread ID at location parent_tidptr in parent and child memory. 
+       Currently this is only done in client memory */
+     if(flags & CLONE_PARENT_SETTID) {
+        tput32(parent_tidptr, parent_tid);
+     }
+ 
+    /* Store child thread ID at location child_tidptr in child memory. */
+    if(flags & CLONE_CHILD_SETTID) {
+      if(ret==0) { // only in client memory for fork()
+        tput32(child_tidptr, gettid());
+      } else if(flags & CLONE_VM) { // real threads need it too
+        tput32(child_tidptr, ret);
+      }
     }
     return ret;
 }
@@ -2458,7 +2573,7 @@ long do_syscall(void *cpu_env, int num, 
         _mcleanup();
 #endif
         gdb_exit(cpu_env, arg1);
-        /* XXX: should free thread stack and CPU env */
+        /* XXX: should free thread stack, GDT and CPU env */
         _exit(arg1);
         ret = 0; /* avoid warning */
         break;
@@ -2487,7 +2602,7 @@ long do_syscall(void *cpu_env, int num, 
         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:
@@ -3651,7 +3766,7 @@ long do_syscall(void *cpu_env, int num, 
         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 */
@@ -4039,7 +4154,7 @@ long do_syscall(void *cpu_env, int num, 
 #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
@@ -4561,12 +4676,12 @@ long do_syscall(void *cpu_env, int num, 
 #ifdef TARGET_NR_set_thread_area
     case TARGET_NR_set_thread_area:
 #ifdef TARGET_MIPS
-      ((CPUMIPSState *) cpu_env)->tls_value = arg1;
-      ret = 0;
-      break;
+        ((CPUMIPSState *) cpu_env)->tls_value = arg1;
+        ret = 0;
 #else
-      goto unimplemented_nowarn;
+        ret = get_errno(do_set_thread_area(cpu_env, arg1));
 #endif
+        break;
 #endif
 #ifdef TARGET_NR_get_thread_area
     case TARGET_NR_get_thread_area:

[-- Attachment #7: qemu-cvs-wine.patch --]
[-- Type: text/x-patch, Size: 388 bytes --]

Index: qemu/linux-user/main.c
===================================================================
--- qemu.orig/linux-user/main.c
+++ qemu/linux-user/main.c
@@ -1933,6 +1933,7 @@ int main(int argc, char **argv)
     cpu_x86_load_seg(env, R_FS, __USER_DS);
     cpu_x86_load_seg(env, R_GS, __USER_DS);
 
+    env->segs[R_FS].selector = 0;
 #elif defined(TARGET_ARM)
     {
         int i;

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH] Fix TLS support on x86
  2007-06-20 16:42   ` Alexander Graf
@ 2007-06-21  5:31     ` David Woodhouse
  2007-06-21  6:01       ` Jakub Jelinek
  2007-06-21  7:11       ` Alexander Graf
       [not found]     ` <20070621225550.GB25967@networkno.de>
  1 sibling, 2 replies; 11+ messages in thread
From: David Woodhouse @ 2007-06-21  5:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: jakub

On Wed, 2007-06-20 at 18:42 +0200, Alexander Graf wrote:
> implements futexes (this is mostly done by David Woodhouse as well,
> FUTEX_WAKE_OP done by me)

#ifdef BSWAP_NEEDED, only FUTEX_OP_CMP_EQ and FUTEX_OP_CMP_NE will work
as expected. If we want to do the rest then we'll need to implement
FUTEX_OP_CMP_LT_WRONGENDIAN &c in the kernel.

Or maybe, since we don't do set_robust_list (and would need wrong-endian
support in the kernel for that too), we can assume that it's all
in-process, and hence all _within_ qemu, and we could actually implement
the futex stuff entirely within qemu with qemu's own locking?

For now I think the safer option is just to leave FUTEX_WAKE_OP
unimplemented. Jakub, what do you think?

-- 
dwmw2

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH] Fix TLS support on x86
  2007-06-21  5:31     ` David Woodhouse
@ 2007-06-21  6:01       ` Jakub Jelinek
  2007-06-21  7:11       ` Alexander Graf
  1 sibling, 0 replies; 11+ messages in thread
From: Jakub Jelinek @ 2007-06-21  6:01 UTC (permalink / raw)
  To: David Woodhouse; +Cc: qemu-devel

On Thu, Jun 21, 2007 at 01:31:07PM +0800, David Woodhouse wrote:
> On Wed, 2007-06-20 at 18:42 +0200, Alexander Graf wrote:
> > implements futexes (this is mostly done by David Woodhouse as well,
> > FUTEX_WAKE_OP done by me)
> 
> #ifdef BSWAP_NEEDED, only FUTEX_OP_CMP_EQ and FUTEX_OP_CMP_NE will work
> as expected. If we want to do the rest then we'll need to implement
> FUTEX_OP_CMP_LT_WRONGENDIAN &c in the kernel.
> 
> Or maybe, since we don't do set_robust_list (and would need wrong-endian
> support in the kernel for that too), we can assume that it's all
> in-process, and hence all _within_ qemu, and we could actually implement
> the futex stuff entirely within qemu with qemu's own locking?
> 
> For now I think the safer option is just to leave FUTEX_WAKE_OP
> unimplemented. Jakub, what do you think?

FUTEX_WAKE_OP is just an optimization and the only op glibc uses is
FUTEX_OP_CLEAR_WAKE_IF_GT_ONE, so something that would need kernel help.
But all glibcs so far if syscall (SYS_futex, ... FUTEX_WAKE_OP, ...)
fails just fall back to syscall (SYS_futex, ... FUTEX_WAKE, ...) +
unlock.

So I think it is safe to leave FUTEX_WAKE_OP not supported for BSWAP_NEEDED.

	Jakub

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH] Fix TLS support on x86
  2007-06-21  5:31     ` David Woodhouse
  2007-06-21  6:01       ` Jakub Jelinek
@ 2007-06-21  7:11       ` Alexander Graf
  1 sibling, 0 replies; 11+ messages in thread
From: Alexander Graf @ 2007-06-21  7:11 UTC (permalink / raw)
  To: qemu-devel


On Jun 21, 2007, at 7:31 AM, David Woodhouse wrote:

> On Wed, 2007-06-20 at 18:42 +0200, Alexander Graf wrote:
>> implements futexes (this is mostly done by David Woodhouse as well,
>> FUTEX_WAKE_OP done by me)
>
> #ifdef BSWAP_NEEDED, only FUTEX_OP_CMP_EQ and FUTEX_OP_CMP_NE will  
> work
> as expected. If we want to do the rest then we'll need to implement
> FUTEX_OP_CMP_LT_WRONGENDIAN &c in the kernel.

Tell me if I'm wrong there, but as far as I could tell from the  
documentation by Ulrich Drapper (http://people.redhat.com/drepper/ 
futex.pdf) and the kernel source, FUTEX_WAKE_OP can be easily  
expressed as two conditional FUTEX_WAKE calls.
Because the only real endianness problems that exist are in the  
conditional checking, we should be on the safe side if that is done  
in qemu (which is what I was implementing).

Alex

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH] Fix TLS support on x86
       [not found]         ` <20070621231612.GC25967@networkno.de>
@ 2007-07-02 10:01           ` Alexander Graf
  2007-11-13 18:44             ` Stefan Weil
  0 siblings, 1 reply; 11+ messages in thread
From: Alexander Graf @ 2007-07-02 10:01 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 916 bytes --]

Hi,

these are the updated patches for TLS support:

qemu-cvs-futex.patch

This patches futex support into qemu-user. It is basically done by David
Woodhouse and I implemented FUTEX_WAKE_OP because actually one
application did not work without (I don't really remember which one
though). If FUTEX_WAKE_OP gets triggered qemu throws a warning though so
if anyone experiences problems with it and it works without we should
disable it then.

qemu-cvs-sched_getaffinity.patch

Flash9 needs sys_get_getaffinity to work properly. As far as I can tell
there should be no need for endianness-conversion, because the
information is written bit-wise.

qemu-cvs-tls.patch

implements set_thread_area for x86 and modifies the do_clone function,
so TLS is evaluated. This is 90% done by David Woodhouse, I only changed
it so it works for me (TID setters, proper segment register setters,
fork() fix, made clone() work).


Alex


[-- Attachment #2: qemu-cvs-futex.patch --]
[-- Type: text/x-patch, Size: 4172 bytes --]

Index: qemu/linux-user/syscall.c
===================================================================
--- qemu.orig/linux-user/syscall.c
+++ qemu/linux-user/syscall.c
@@ -17,6 +17,8 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
+
+#define __user
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdarg.h>
@@ -60,6 +62,7 @@
 #define tchars host_tchars /* same as target */
 #define ltchars host_ltchars /* same as target */
 
+#include <linux/futex.h>
 #include <linux/termios.h>
 #include <linux/unistd.h>
 #include <linux/utsname.h>
@@ -2554,6 +2557,91 @@ static inline void host_to_target_timesp
     unlock_user_struct(target_ts, target_addr, 1);
 }
 
+#ifdef BSWAP_NEEDED
+static int futex_op(int oldval, int op, int oparg)
+{
+	int retval = oparg;
+	switch(op) {
+	    case FUTEX_OP_SET: break;
+	    case FUTEX_OP_ADD: retval += oparg; break;
+	    case FUTEX_OP_OR: retval |= oparg; break;
+	    case FUTEX_OP_ANDN: retval &= oparg; break;
+	    case FUTEX_OP_XOR: retval ^= oparg; break;
+	}
+	return retval;
+}
+
+static int futex_cmp(int oldval, int cmp, int cmparg)
+{
+	switch(cmp) {
+	    case FUTEX_OP_CMP_EQ: return oldval == cmparg;
+	    case FUTEX_OP_CMP_NE: return oldval != cmparg;
+	    case FUTEX_OP_CMP_LT: return oldval <  cmparg;
+	    case FUTEX_OP_CMP_LE: return oldval <= cmparg;
+	    case FUTEX_OP_CMP_GT: return oldval >  cmparg;
+	    case FUTEX_OP_CMP_GE: return oldval >= cmparg;
+	}
+	return -1;
+}
+#endif
+
+static long do_futex(target_ulong uaddr, int op, uint32_t val,
+                    target_ulong utime, target_ulong uaddr2,
+                    uint32_t val3)
+{
+       struct timespec host_utime;
+       unsigned long val2 = utime;
+       long retval;
+
+       if (utime && (op == FUTEX_WAIT || op == FUTEX_LOCK_PI)) {
+               target_to_host_timespec(&host_utime, utime);
+               val2 = (unsigned long)&host_utime;
+       }
+ 
+#ifdef BSWAP_NEEDED
+       switch(op) {
+       case FUTEX_CMP_REQUEUE:
+               val3 = tswap32(val3);
+       case FUTEX_REQUEUE:
+               val2 = tswap32(val2);
+       case FUTEX_WAIT:
+       case FUTEX_WAKE:
+       case FUTEX_WAKE_OP:
+               val = tswap32(val);
+       case FUTEX_LOCK_PI: /* This one's icky, but comes out OK */
+       case FUTEX_UNLOCK_PI:
+               break;
+       default: 
+               gemu_log("qemu: Unsupported futex op %d\n", op);
+               return -ENOSYS;
+       } 
+       if (op == FUTEX_WAKE_OP) {
+               /* Need to munge the secondary operation (val3) */
+	       gemu_log("qemu: Tricky FUTEX_WAKE_OP - trying to emulate it\n");
+               val3 = tswap32(val3);
+               int op2 = (val3 >> 28) & 0xf;
+               int cmp = (val3 >> 24) & 0xf;
+               int oparg = (val3 >> 12) & 0xfff;
+               int cmparg = val3 & 0xfff;
+               int shift = val3 & (FUTEX_OP_OPARG_SHIFT << 28);
+               int oldval = tget32(uaddr2);
+               if (shift)
+                   oparg = 1 << oparg;
+
+              tput32(uaddr2,futex_op(oldval, op2, oparg));
+              retval = syscall(__NR_futex, g2h(uaddr), FUTEX_WAKE, val, 0, 0, 0);
+              if(futex_cmp(oldval, cmp, cmparg)) {
+                  retval = syscall(__NR_futex, g2h(uaddr2), FUTEX_WAKE, val2, 0, 0, 0);
+              }
+       } else {
+              retval = syscall(__NR_futex, g2h(uaddr), op, val, val2, g2h(uaddr2), val3);
+       }
+#else
+       retval = syscall(__NR_futex, g2h(uaddr), op, val, val2, g2h(uaddr2), val3);
+#endif
+       return retval;
+}
+
 long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, 
                 long arg4, long arg5, long arg6)
 {
@@ -4713,6 +4801,11 @@ long do_syscall(void *cpu_env, int num, 
     }
 #endif
 
+#ifdef TARGET_NR_futex
+    case TARGET_NR_futex:
+        ret = get_errno(do_futex(arg1, arg2, arg3, arg4, arg5, arg6));
+        break;
+#endif
 #if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
     case TARGET_NR_set_tid_address:
       ret = get_errno(set_tid_address((int *) arg1));


[-- Attachment #3: qemu-cvs-sched_getaffinity.patch --]
[-- Type: text/x-patch, Size: 1664 bytes --]

Index: qemu/linux-user/syscall.c
===================================================================
--- qemu.orig/linux-user/syscall.c
+++ qemu/linux-user/syscall.c
@@ -149,6 +149,7 @@ type name (type1 arg1,type2 arg2,type3 a
 #define __NR_sys_syslog __NR_syslog
 #define __NR_sys_tgkill __NR_tgkill
 #define __NR_sys_clone __NR_clone
+#define __NR_sys_sched_getaffinity __NR_sched_getaffinity
 
 #if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__)
 #define __NR__llseek __NR_lseek
@@ -171,6 +172,7 @@ _syscall3(int,sys_rt_sigqueueinfo,int,pi
 _syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
 _syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
 _syscall5(int,sys_clone, int, flags, void *, child_stack, int *, parent_tidptr, void *, newtls, int *, child_tidptr)
+_syscall3(int,sys_sched_getaffinity,pid_t,pid,unsigned int,cpusetsize,void*,mask)
 #ifdef __NR_exit_group
 _syscall1(int,exit_group,int,error_code)
 #endif
@@ -4823,6 +4825,17 @@ long do_syscall(void *cpu_env, int num, 
 	goto unimplemented_nowarn;
 #endif
 
+#ifdef TARGET_NR_sched_getaffinity
+    case TARGET_NR_sched_getaffinity:
+    {
+        cpu_set_t *mask;
+        lock_user_struct(mask, arg3, 1);                                                                                                          
+        ret = get_errno(sys_sched_getaffinity((pid_t)arg1, (unsigned int)arg2, mask));
+        unlock_user_struct(mask, arg3, 0);                                                                                                        
+        break;
+    }
+#endif
+
     default:
     unimplemented:
         gemu_log("qemu: Unsupported syscall: %d\n", num);


[-- Attachment #4: qemu-cvs-tls.patch --]
[-- Type: text/x-patch, Size: 9356 bytes --]

Index: qemu/linux-user/main.c
===================================================================
--- qemu.orig/linux-user/main.c
+++ qemu/linux-user/main.c
@@ -156,7 +156,7 @@ static void set_gate(void *ptr, unsigned
     p[1] = tswapl(e2);
 }
 
-uint64_t gdt_table[6];
+uint64_t gdt_table[9];
 uint64_t idt_table[256];
 
 /* only dpl matters as we do only user space emulation */
Index: qemu/linux-user/syscall.c
===================================================================
--- qemu.orig/linux-user/syscall.c
+++ qemu/linux-user/syscall.c
@@ -145,6 +145,7 @@ type name (type1 arg1,type2 arg2,type3 a
 #define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
 #define __NR_sys_syslog __NR_syslog
 #define __NR_sys_tgkill __NR_tgkill
+#define __NR_sys_clone __NR_clone
 
 #if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__)
 #define __NR__llseek __NR_lseek
@@ -166,6 +167,7 @@ _syscall5(int, _llseek,  uint,  fd, ulon
 _syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
 _syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
 _syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
+_syscall5(int,sys_clone, int, flags, void *, child_stack, int *, parent_tidptr, void *, newtls, int *, child_tidptr)
 #ifdef __NR_exit_group
 _syscall1(int,exit_group,int,error_code)
 #endif
@@ -2115,29 +2117,107 @@ int do_modify_ldt(CPUX86State *env, int 
     return ret;
 }
 
+int do_set_thread_area(CPUX86State *env, target_ulong ptr)
+{
+    uint64_t *gdt_table = g2h(env->gdt.base);
+    struct target_modify_ldt_ldt_s ldt_info;
+    struct target_modify_ldt_ldt_s *target_ldt_info;
+    int seg_32bit, contents, read_exec_only, limit_in_pages;
+    int seg_not_present, useable;
+    uint32_t *lp, entry_1, entry_2;
+    int i;
+
+    lock_user_struct(target_ldt_info, ptr, 1);
+    ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
+    ldt_info.base_addr = tswapl(target_ldt_info->base_addr);
+    ldt_info.limit = tswap32(target_ldt_info->limit);
+    ldt_info.flags = tswap32(target_ldt_info->flags);
+    if (ldt_info.entry_number == -1) {
+           for (i=6; i<8; i++)
+                   if (gdt_table[i] == 0) {
+                           ldt_info.entry_number = i;
+                           target_ldt_info->entry_number = tswap32(i);
+                           break;
+                   }
+    }
+    unlock_user_struct(target_ldt_info, ptr, 0);
+    
+    if (ldt_info.entry_number < 6 || ldt_info.entry_number > 8)
+           return -EINVAL;
+    seg_32bit = ldt_info.flags & 1;
+    contents = (ldt_info.flags >> 1) & 3;
+    read_exec_only = (ldt_info.flags >> 3) & 1;
+    limit_in_pages = (ldt_info.flags >> 4) & 1;
+    seg_not_present = (ldt_info.flags >> 5) & 1;
+    useable = (ldt_info.flags >> 6) & 1;
+
+    if (contents == 3) {
+        if (seg_not_present == 0)
+            return -EINVAL;
+    }
+
+    /* NOTE: same code as Linux kernel */
+    /* Allow LDTs to be cleared by the user. */
+    if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
+        if ((contents == 0             &&
+             read_exec_only == 1       &&
+             seg_32bit == 0            &&
+             limit_in_pages == 0       &&
+             seg_not_present == 1      &&
+             useable == 0 )) {
+            entry_1 = 0;
+            entry_2 = 0;
+            goto install;
+        }
+    }
+    
+    entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
+        (ldt_info.limit & 0x0ffff);
+    entry_2 = (ldt_info.base_addr & 0xff000000) |
+        ((ldt_info.base_addr & 0x00ff0000) >> 16) |
+        (ldt_info.limit & 0xf0000) |
+        ((read_exec_only ^ 1) << 9) |
+        (contents << 10) |
+        ((seg_not_present ^ 1) << 15) |
+        (seg_32bit << 22) |
+        (limit_in_pages << 23) |
+       (useable << 20) |
+       0x7000;
+
+    /* Install the new entry ...  */
+install:
+    lp = (uint32_t *)(gdt_table + ldt_info.entry_number);
+    lp[0] = tswap32(entry_1);
+    lp[1] = tswap32(entry_2);
+    return 0;
+}
 #endif /* defined(TARGET_I386) */
 
 /* this stack is the equivalent of the kernel stack associated with a
    thread/process */
 #define NEW_STACK_SIZE 8192
 
-static int clone_func(void *arg)
+static int clone_func(void *cloneenv)
 {
-    CPUState *env = arg;
-    cpu_loop(env);
+    cpu_loop((CPUState *)cloneenv);
     /* never exits */
     return 0;
 }
 
-int do_fork(CPUState *env, unsigned int flags, unsigned long newsp)
+int do_fork(CPUState *env, unsigned int flags, target_ulong newsp, target_ulong parent_tidptr, target_ulong newtls, target_ulong child_tidptr)
 {
     int ret;
+    unsigned long parent_tid=gettid();
     TaskState *ts;
     uint8_t *new_stack;
     CPUState *new_env;
-    
+#if defined(TARGET_I386)
+    uint64_t *new_gdt_table;
+#endif
     if (flags & CLONE_VM) {
         ts = malloc(sizeof(TaskState) + NEW_STACK_SIZE);
+        if (!ts)
+                return -ENOMEM;
         memset(ts, 0, sizeof(TaskState));
         new_stack = ts->stack;
         ts->used = 1;
@@ -2149,6 +2229,27 @@ int do_fork(CPUState *env, unsigned int 
 #if defined(TARGET_I386)
         if (!newsp)
             newsp = env->regs[R_ESP];
+        new_gdt_table = malloc(9 * 8);
+        if (!new_gdt_table) {
+                free(new_env);
+                return -ENOMEM;
+        }
+        /* Copy main GDT table from parent, but clear TLS entries */
+        memcpy(new_gdt_table, g2h(env->gdt.base), 6 * 8);
+        memset(&new_gdt_table[6], 0, 3 * 8); 
+        new_env->gdt.base = h2g(new_gdt_table);
+        if (flags & CLONE_SETTLS) {
+               ret = do_set_thread_area(new_env, newtls);
+               if (ret) {
+                       free(new_gdt_table);
+                       free(new_env);
+                       return ret;
+               }
+        }
+	
+        cpu_x86_load_seg(new_env, R_FS, new_env->segs[R_FS].selector);
+        cpu_x86_load_seg(new_env, R_GS, new_env->segs[R_GS].selector);
+	
         new_env->regs[R_ESP] = newsp;
         new_env->regs[R_EAX] = 0;
 #elif defined(TARGET_ARM)
@@ -2202,15 +2303,27 @@ int do_fork(CPUState *env, unsigned int 
 #endif
         new_env->opaque = ts;
 #ifdef __ia64__
-        ret = __clone2(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
+	ret = __clone2(clone_func, new_stack + NEW_STACK_SIZE, flags & ~(CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID), new_env);
 #else
-	ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
+	ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags & ~(CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID), new_env);
 #endif
     } else {
         /* if no CLONE_VM, we consider it is a fork */
-        if ((flags & ~CSIGNAL) != 0)
-            return -EINVAL;
-        ret = fork();
+	ret = sys_clone(flags & ~(CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID), 0, g2h(parent_tidptr), NULL, g2h(child_tidptr));
+    }
+    /* Store child thread ID at location parent_tidptr in parent and child memory. 
+       Currently this is only done in client memory */
+     if(flags & CLONE_PARENT_SETTID) {
+        tput32(parent_tidptr, parent_tid);
+     }
+ 
+    /* Store child thread ID at location child_tidptr in child memory. */
+    if(flags & CLONE_CHILD_SETTID) {
+      if(ret==0) { /* only in client memory for fork() */
+        tput32(child_tidptr, gettid());
+      } else if(flags & CLONE_VM) { /* real threads need it too */
+        tput32(child_tidptr, ret);
+      }
     }
     return ret;
 }
@@ -2458,7 +2571,7 @@ long do_syscall(void *cpu_env, int num, 
         _mcleanup();
 #endif
         gdb_exit(cpu_env, arg1);
-        /* XXX: should free thread stack and CPU env */
+        /* XXX: should free thread stack, GDT and CPU env */
         _exit(arg1);
         ret = 0; /* avoid warning */
         break;
@@ -2487,7 +2600,7 @@ long do_syscall(void *cpu_env, int num, 
         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:
@@ -3651,7 +3764,7 @@ long do_syscall(void *cpu_env, int num, 
         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 */
@@ -4039,7 +4152,7 @@ long do_syscall(void *cpu_env, int num, 
 #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
@@ -4561,12 +4674,12 @@ long do_syscall(void *cpu_env, int num, 
 #ifdef TARGET_NR_set_thread_area
     case TARGET_NR_set_thread_area:
 #ifdef TARGET_MIPS
-      ((CPUMIPSState *) cpu_env)->tls_value = arg1;
-      ret = 0;
-      break;
+        ((CPUMIPSState *) cpu_env)->tls_value = arg1;
+        ret = 0;
 #else
-      goto unimplemented_nowarn;
+        ret = get_errno(do_set_thread_area(cpu_env, arg1));
 #endif
+        break;
 #endif
 #ifdef TARGET_NR_get_thread_area
     case TARGET_NR_get_thread_area:


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH] Fix TLS support on x86
  2007-07-02 10:01           ` Alexander Graf
@ 2007-11-13 18:44             ` Stefan Weil
  2007-11-13 18:46               ` Thayne Harbaugh
  0 siblings, 1 reply; 11+ messages in thread
From: Stefan Weil @ 2007-11-13 18:44 UTC (permalink / raw)
  To: qemu-devel

Hi,

I'd like to test user mode emulation on MIPS host.

Do you have newer versions of your patches which match
current CVS HEAD? TLS support is still missing there,
so QEMU user mode emulation is not really usable without
working patches.

Regards
Stefan

Alexander Graf schrieb:
> Hi,
>
> these are the updated patches for TLS support:
>
> qemu-cvs-futex.patch
>
> This patches futex support into qemu-user. It is basically done by David
> Woodhouse and I implemented FUTEX_WAKE_OP because actually one
> application did not work without (I don't really remember which one
> though). If FUTEX_WAKE_OP gets triggered qemu throws a warning though so
> if anyone experiences problems with it and it works without we should
> disable it then.
>
> qemu-cvs-sched_getaffinity.patch
>
> Flash9 needs sys_get_getaffinity to work properly. As far as I can tell
> there should be no need for endianness-conversion, because the
> information is written bit-wise.
>
> qemu-cvs-tls.patch
>
> implements set_thread_area for x86 and modifies the do_clone function,
> so TLS is evaluated. This is 90% done by David Woodhouse, I only changed
> it so it works for me (TID setters, proper segment register setters,
> fork() fix, made clone() work).
>
> Alex

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH] Fix TLS support on x86
  2007-11-13 18:44             ` Stefan Weil
@ 2007-11-13 18:46               ` Thayne Harbaugh
  2007-11-13 22:13                 ` Fabrice Bellard
  0 siblings, 1 reply; 11+ messages in thread
From: Thayne Harbaugh @ 2007-11-13 18:46 UTC (permalink / raw)
  To: qemu-devel


On Tue, 2007-11-13 at 19:44 +0100, Stefan Weil wrote:
> Hi,
> 
> I'd like to test user mode emulation on MIPS host.
> 
> Do you have newer versions of your patches which match
> current CVS HEAD? TLS support is still missing there,
> so QEMU user mode emulation is not really usable without
> working patches.

I don't know about anyone else, but I have some patches for TLS for arm
and i386.  The patches are significantly out of date with the recent
linux-user changes.  I won't be updating them until I finish with the
current set of changes to linux-user.

> Alexander Graf schrieb:
> > Hi,
> >
> > these are the updated patches for TLS support:
> >
> > qemu-cvs-futex.patch
> >
> > This patches futex support into qemu-user. It is basically done by David
> > Woodhouse and I implemented FUTEX_WAKE_OP because actually one
> > application did not work without (I don't really remember which one
> > though). If FUTEX_WAKE_OP gets triggered qemu throws a warning though so
> > if anyone experiences problems with it and it works without we should
> > disable it then.
> >
> > qemu-cvs-sched_getaffinity.patch
> >
> > Flash9 needs sys_get_getaffinity to work properly. As far as I can tell
> > there should be no need for endianness-conversion, because the
> > information is written bit-wise.
> >
> > qemu-cvs-tls.patch
> >
> > implements set_thread_area for x86 and modifies the do_clone function,
> > so TLS is evaluated. This is 90% done by David Woodhouse, I only changed
> > it so it works for me (TID setters, proper segment register setters,
> > fork() fix, made clone() work).
> >
> > Alex
> 
> 

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH] Fix TLS support on x86
  2007-11-13 18:46               ` Thayne Harbaugh
@ 2007-11-13 22:13                 ` Fabrice Bellard
  2007-11-14 20:02                   ` Stefan Weil
  0 siblings, 1 reply; 11+ messages in thread
From: Fabrice Bellard @ 2007-11-13 22:13 UTC (permalink / raw)
  To: qemu-devel

Thayne Harbaugh wrote:
> On Tue, 2007-11-13 at 19:44 +0100, Stefan Weil wrote:
>> Hi,
>>
>> I'd like to test user mode emulation on MIPS host.
>>
>> Do you have newer versions of your patches which match
>> current CVS HEAD? TLS support is still missing there,
>> so QEMU user mode emulation is not really usable without
>> working patches.
> 
> I don't know about anyone else, but I have some patches for TLS for arm
> and i386.  The patches are significantly out of date with the recent
> linux-user changes.  I won't be updating them until I finish with the
> current set of changes to linux-user.

I'll try to merge and improve the i386 TLS patch ASAP.

Moreover, after having looked again at the linux-user code and at the
regression tests, my conclusion is that the linux-user QEMU targets must
be statically linked and that it should not depend on host libraries
such as the C library.

Fabrice.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [PATCH] Fix TLS support on x86
  2007-11-13 22:13                 ` Fabrice Bellard
@ 2007-11-14 20:02                   ` Stefan Weil
  0 siblings, 0 replies; 11+ messages in thread
From: Stefan Weil @ 2007-11-14 20:02 UTC (permalink / raw)
  To: qemu-devel

Fabrice Bellard schrieb:
> On Tue, 2007-11-13 at 19:44 +0100, Stefan Weil wrote:
>>> Hi,
>>>
>>> I'd like to test user mode emulation on MIPS host.
>>>
>>> Do you have newer versions of your patches which match
>>> current CVS HEAD? TLS support is still missing there,
>>> so QEMU user mode emulation is not really usable without
>>> working patches.
>> I don't know about anyone else, but I have some patches for TLS for arm
>> and i386. The patches are significantly out of date with the recent
>> linux-user changes. I won't be updating them until I finish with the
>> current set of changes to linux-user.
>
> I'll try to merge and improve the i386 TLS patch ASAP.
>
> Moreover, after having looked again at the linux-user code and at the
> regression tests, my conclusion is that the linux-user QEMU targets must
> be statically linked and that it should not depend on host libraries
> such as the C library.
>
> Fabrice.
Thank you, Fabrice. With your latest changes in QEMU CVS,
the user mode emulation qemu-i386 works again:

* i386 host:
  statically linked hello, Debian echo, Debian top, Debian ls ok

* mips host (le and be QEMU Malta emulation):
  statically linked hello, Debian echo, Debian top ok
  Debian ls fails (segmentation fault)

Debian top complains about 2.4+ kernel w/o ELF notes -
this might be a missing feature in the linux user mode emulation.

Mips hosts need patches (published but still missing in CVS HEAD)
for user mode emulation.

Regards
Stefan

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2007-11-14 20:02 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-06-08 14:17 [Qemu-devel] [PATCH] Fix TLS support on x86 Alexander Graf
2007-06-18 19:21 ` Thiemo Seufer
2007-06-20 16:42   ` Alexander Graf
2007-06-21  5:31     ` David Woodhouse
2007-06-21  6:01       ` Jakub Jelinek
2007-06-21  7:11       ` Alexander Graf
     [not found]     ` <20070621225550.GB25967@networkno.de>
     [not found]       ` <1801E7EE-FF0A-4A43-88ED-4503DEBBC831@suse.de>
     [not found]         ` <20070621231612.GC25967@networkno.de>
2007-07-02 10:01           ` Alexander Graf
2007-11-13 18:44             ` Stefan Weil
2007-11-13 18:46               ` Thayne Harbaugh
2007-11-13 22:13                 ` Fabrice Bellard
2007-11-14 20:02                   ` Stefan Weil

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).