PERFORCE change 106389 for review

Roman Divacky rdivacky at FreeBSD.org
Wed Sep 20 04:28:04 PDT 2006


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

Change 106389 by rdivacky at rdivacky_witten on 2006/09/20 11:27:29

	-	Implement tls in amd64 version
	-	change l_desc_struct members from long to int
		ie. from 64bit to 32bit on amd64 [1]
	
	Found by: ssouhlal [1]

Affected files ...

.. //depot/projects/linuxolator/src/sys/amd64/linux32/linux.h#4 edit
.. //depot/projects/linuxolator/src/sys/amd64/linux32/linux32_machdep.c#2 edit

Differences ...

==== //depot/projects/linuxolator/src/sys/amd64/linux32/linux.h#4 (text+ko) ====

@@ -757,7 +757,7 @@
 };
 
 struct l_desc_struct {
-           unsigned long a,b;
+           unsigned int a,b;
 };
 
 

==== //depot/projects/linuxolator/src/sys/amd64/linux32/linux32_machdep.c#2 (text+ko) ====

@@ -62,6 +62,24 @@
 #include <compat/linux/linux_util.h>
 #include <compat/linux/linux_emul.h>
 
+#include <amd64/include/pcb.h>                   /* needed for pcb definition in linux_set_thread_area */
+
+/*
+ * Memory and System segment descriptors
+ */
+struct  segment_descriptor      {
+        unsigned sd_lolimit:16 ;        /* segment extent (lsb) */
+        unsigned sd_lobase:24 __packed; /* segment base address (lsb) */
+        unsigned sd_type:5 ;            /* segment type */
+        unsigned sd_dpl:2 ;             /* segment descriptor priority level */
+        unsigned sd_p:1 ;               /* segment descriptor present */
+        unsigned sd_hilimit:4 ;         /* segment extent (msb) */
+        unsigned sd_xx:2 ;              /* unused */
+        unsigned sd_def32:1 ;           /* default 32 vs 16 bit size */
+        unsigned sd_gran:1 ;            /* limit granularity (byte/page units)*/
+        unsigned sd_hibase:8 ;          /* segment base address  (msb) */
+} ;
+
 struct l_old_select_argv {
 	l_int		nfds;
 	l_uintptr_t	readfds;
@@ -614,7 +632,57 @@
    	   	td2->td_frame->tf_rsp = PTROUT(args->stack);
 
 	if (args->flags & CLONE_SETTLS) {
-	   	/* XXX: todo */
+   	   	struct l_user_desc info;
+   	   	int idx;
+	   	int a[2];
+		struct segment_descriptor sd;
+
+	   	error = copyin((void *)td->td_frame->tf_rsi, &info, sizeof(struct l_user_desc));
+		if (error)
+   		   	return (error);
+		
+		idx = info.entry_number;
+		
+		/* 
+		 * looks like we're getting the idx we returned
+		 * in the set_thread_area() syscall
+		 */
+		if (idx != 6 && idx != 3)
+			return (EINVAL);
+
+		/* this doesnt happen in practice */
+		if (idx == 6) {
+		   	/* we might copy out the entry_number as 3 */
+		   	info.entry_number = 3;
+			error = copyout(&info, (void *) td->td_frame->tf_rsi, sizeof(struct l_user_desc));
+			if (error)
+	   		   	return (error);
+		}
+
+		a[0] = LDT_entry_a(&info);
+		a[1] = LDT_entry_b(&info);
+
+		memcpy(&sd, &a, sizeof(a));
+#ifdef DEBUG
+	if (ldebug(clone))
+	   	printf("Segment created in clone with CLONE_SETTLS: 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 amd64 version of cpu_set_user_tls() */
+		critical_enter();
+		/* set %fs */
+		td->td_pcb->pcb_fsbase = (register_t)((register_t)sd.sd_hibase << 24 | sd.sd_lobase);
+		wrmsr(MSR_FSBASE, td->td_pcb->pcb_fsbase);
+		critical_exit();
 	}
 
 #ifdef DEBUG
@@ -1115,3 +1183,100 @@
 		bsd_args.prot |= PROT_EXEC;
 	return (mprotect(td, &bsd_args));
 }
+
+int
+linux_set_thread_area(struct thread *td, struct linux_set_thread_area_args *args)
+{
+	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(set_thread_area, "%i, %x, %x, %i, %i, %i, %i, %i, %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
+	 * syscall loads one of the selected tls decriptors with a value
+	 * and also loads GDT descriptors 6, 7 and 8 with the content of the per-thread 
+	 * descriptors.
+	 *
+	 * Semantics of fbsd version: I think we can ignore that linux has 3 per-thread
+	 * 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 
+	 * 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: 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 amd64 version of cpu_set_user_tls() */
+	critical_enter();
+	/* set %fs */
+	td->td_pcb->pcb_fsbase = (register_t)((register_t)sd.sd_hibase << 24 | sd.sd_lobase);
+	wrmsr(MSR_FSBASE, td->td_pcb->pcb_fsbase);
+
+	critical_exit();
+   
+	return (0);
+}
+


More information about the p4-projects mailing list