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