From owner-p4-projects@FreeBSD.ORG Wed Sep 20 11:28:03 2006 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id B883B16A622; Wed, 20 Sep 2006 11:28:03 +0000 (UTC) X-Original-To: perforce@FreeBSD.org Delivered-To: perforce@FreeBSD.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 83ADF16A61B for ; Wed, 20 Sep 2006 11:28:03 +0000 (UTC) (envelope-from rdivacky@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id 9477B43D8B for ; Wed, 20 Sep 2006 11:27:56 +0000 (GMT) (envelope-from rdivacky@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.6/8.13.6) with ESMTP id k8KBRuAY008200 for ; Wed, 20 Sep 2006 11:27:56 GMT (envelope-from rdivacky@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.6/8.13.4/Submit) id k8KBRu1N008197 for perforce@freebsd.org; Wed, 20 Sep 2006 11:27:56 GMT (envelope-from rdivacky@FreeBSD.org) Date: Wed, 20 Sep 2006 11:27:56 GMT Message-Id: <200609201127.k8KBRu1N008197@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to rdivacky@FreeBSD.org using -f From: Roman Divacky To: Perforce Change Reviews Cc: Subject: PERFORCE change 106389 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 20 Sep 2006 11:28:04 -0000 http://perforce.freebsd.org/chv.cgi?CH=106389 Change 106389 by rdivacky@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 #include +#include /* 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); +} +