From owner-p4-projects@FreeBSD.ORG Sun Jul 2 13:54:18 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 48B7B16A492; Sun, 2 Jul 2006 13:54:18 +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 1C69E16A47C for ; Sun, 2 Jul 2006 13:54:18 +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 9DC5A43D45 for ; Sun, 2 Jul 2006 13:54:17 +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 k62DsHro024968 for ; Sun, 2 Jul 2006 13:54:17 GMT (envelope-from rdivacky@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.6/8.13.4/Submit) id k62DsH1e024965 for perforce@freebsd.org; Sun, 2 Jul 2006 13:54:17 GMT (envelope-from rdivacky@FreeBSD.org) Date: Sun, 2 Jul 2006 13:54:17 GMT Message-Id: <200607021354.k62DsH1e024965@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 100435 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: Sun, 02 Jul 2006 13:54:18 -0000 http://perforce.freebsd.org/chv.cgi?CH=100435 Change 100435 by rdivacky@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 #include +#include /* 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); }