PERFORCE change 100435 for review

Roman Divacky rdivacky at FreeBSD.org
Sun Jul 2 13:54:18 UTC 2006


http://perforce.freebsd.org/chv.cgi?CH=100435

Change 100435 by rdivacky at rdivacky_witten on 2006/07/02 13:54:12

	Kernel side TLS implementation. This implementes a bit crippled version of
	set_thread_area() syscall. We support just 1 thread area (linux does 3) but
	this should not matter much. Still this code might be altered later. This is 
	for i386 only now as I want to fully implement NPTL first and then focus on amd64.
	
	With this we pass tls_test.c test and are able to run /bin/bash (which uses this)
	with 2.6.x emulation. Full run of bash (ie. running program from within it) is not
	possible because we lack TID handling and futexes.

Affected files ...

.. //depot/projects/soc2006/rdivacky_linuxolator/i386/linux/linux.h#3 edit
.. //depot/projects/soc2006/rdivacky_linuxolator/i386/linux/linux_machdep.c#6 edit

Differences ...

==== //depot/projects/soc2006/rdivacky_linuxolator/i386/linux/linux.h#3 (text+ko) ====

@@ -718,5 +718,31 @@
 	l_uint		useable:1;
 };
 
+/* macros from linux include/asm-um/ldt-i386.h */
+#define LDT_entry_a(info) \
+        ((((info)->base_addr & 0x0000ffff) << 16) | ((info)->limit & 0x0ffff))
+
+#define LDT_entry_b(info) \
+        (((info)->base_addr & 0xff000000) | \
+        (((info)->base_addr & 0x00ff0000) >> 16) | \
+        ((info)->limit & 0xf0000) | \
+        (((info)->read_exec_only ^ 1) << 9) | \
+        ((info)->contents << 10) | \
+        (((info)->seg_not_present ^ 1) << 15) | \
+        ((info)->seg_32bit << 22) | \
+        ((info)->limit_in_pages << 23) | \
+        ((info)->useable << 20) | \
+        0x7000)
+
+#define LDT_empty(info) (\
+        (info)->base_addr       == 0    && \
+        (info)->limit           == 0    && \
+        (info)->contents        == 0    && \
+        (info)->read_exec_only  == 1    && \
+        (info)->seg_32bit       == 0    && \
+        (info)->limit_in_pages  == 0    && \
+        (info)->seg_not_present == 1    && \
+        (info)->useable         == 0    )
+
 
 #endif /* !_I386_LINUX_LINUX_H_ */

==== //depot/projects/soc2006/rdivacky_linuxolator/i386/linux/linux_machdep.c#6 (text+ko) ====

@@ -59,6 +59,8 @@
 #include <compat/linux/linux_signal.h>
 #include <compat/linux/linux_util.h>
 
+#include <i386/include/pcb.h>			/* needed for pcb definition in linux_set_thread_area */
+
 struct l_descriptor {
 	l_uint		entry_number;
 	l_ulong		base_addr;
@@ -851,11 +853,30 @@
 	struct l_user_desc info;
 	int error;
 	int idx;
+	int a[2];
+	struct segment_descriptor sd;
 
 	error = copyin(args->desc, &info, sizeof(struct l_user_desc));
 	if (error)
 		return (error);
 
+#ifdef DEBUG
+	if (ldebug(set_thread_area))
+	   	printf("Args passed to the set_thread_area:\n
+		      entry number: %i, base address: %i, limit: %i, 
+		      seg32bit: %i, contents: %i, read_exec_only: %i, 
+		      limit in pages: %i, seg_not_present: %i, useable: %i\n", 
+		      info.entry_number,
+      		      info.base_addr,
+      		      info.limit,
+      		      info.seg_32bit,
+		      info.contents,
+      		      info.read_exec_only,
+      		      info.limit_in_pages,
+      		      info.seg_not_present,
+      		      info.useable);
+#endif
+
 	idx = info.entry_number;
 	/* Semantics of linux version: every thread in the system has array
 	 * of 3 tls descriptors. 1st is GLIBC TLS, 2nd is WINE, 3rd unknown. This
@@ -864,15 +885,63 @@
 	 * descriptors.
 	 *
 	 * Semantics of fbsd version: I think we can ignore that linux has 3 per-thread
-	 * descriptors and use just the 1st one (TODO: davidxu will report us where we get this).
-	 * The tls_array[] is used only in set/get-thread_area() syscalls and for loading the
-	 * GDT descriptors. In fbsd we use just one GDT descriptor for TLS so we will load
-	 * just one.
+	 * descriptors and use just the 1st one. The tls_array[] is used only in 
+	 * set/get-thread_area() syscalls and for loading the GDT descriptors. In fbsd 
+	 * we use just one GDT descriptor for TLS so we will load just one. 
+	 * XXX: this doesnt work when user-space process tries to use more then 1 TLS segment
+	 * comment in the linux sources says wine might do that.
 	 */
 
-	/* we support just GLIBC TLS now */
-	if (idx != 6 && idx != -1)
+	/* we support just GLIBC TLS now 
+	 * we should let 3 proceed as well because we use this segment so
+	 * if code does two subsequent calls it should succeed
+	 */
+	if (idx != 6 && idx != -1 && idx != 3)
 		return (EINVAL);
+
+	/* we have to copy out the GDT entry we use
+	 * FreeBSD uses GDT entry #3 for storing %gs so load that 
+	 * XXX: what if userspace program doesnt check this value and tries
+	 * to use 6, 7 or 8? 
+	 */
+	idx = info.entry_number = 3;
+	error = copyout(&info, args->desc, sizeof(struct l_user_desc));
+	if (error)
+		return (error);
+
+	if (LDT_empty(&info)) {
+		a[0] = 0;
+		a[1] = 0;
+	} else {
+		a[0] = LDT_entry_a(&info);
+		a[1] = LDT_entry_b(&info);
+	}
+
+	memcpy(&sd, &a, sizeof(a));
+#ifdef DEBUG
+	if (ldebug(set_thread_area))
+	   	printf("Segment created in set_thread_area: \n
+   			lobase: %x, hibase: %x, lolimit: %x, 
+			hilimit: %x, type: %i, dpl: %i, 
+			p: %i, xx: %i, def32: %i, gran: %i\n", sd.sd_lobase,
+			sd.sd_hibase,
+			sd.sd_lolimit,
+			sd.sd_hilimit,
+			sd.sd_type,
+			sd.sd_dpl,
+			sd.sd_p,
+			sd.sd_xx,
+			sd.sd_def32,
+			sd.sd_gran);
+#endif
+
+	/* this is taken from i386 version of cpu_set_user_tls() */
+	critical_enter();
+	/* set %gs */
+	td->td_pcb->pcb_gsd = sd;
+	PCPU_GET(fsgs_gdt)[1] = sd;
+	load_gs(GSEL(GUGS_SEL, SEL_UPL));
+	critical_exit();
    
 	return (0);
 }


More information about the p4-projects mailing list