Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch add the guts of TLS support on amd64. based on joe...



details:   https://anonhg.NetBSD.org/src/rev/125dc7eee639
branches:  trunk
changeset: 756121:125dc7eee639
user:      chs <chs%NetBSD.org@localhost>
date:      Wed Jul 07 01:14:52 2010 +0000

description:
add the guts of TLS support on amd64.  based on joerg's patch,
reworked by me to support 32-bit processes as well.
we now keep %fs and %gs loaded with the user values
while in the kernel, which means we don't need to
reload them when returning to user mode.

diffstat:

 sys/arch/amd64/amd64/cpufunc.S          |   15 +++-
 sys/arch/amd64/amd64/gdt.c              |  134 ++++++++++++++-----------------
 sys/arch/amd64/amd64/genassym.cf        |    8 +-
 sys/arch/amd64/amd64/locore.S           |   65 ++++++++++++--
 sys/arch/amd64/amd64/machdep.c          |  119 ++++++++++++++++++++++++++-
 sys/arch/amd64/amd64/netbsd32_machdep.c |   62 ++++++++-----
 sys/arch/amd64/amd64/vector.S           |    6 +-
 sys/arch/amd64/include/frameasm.h       |   13 +-
 sys/arch/amd64/include/gdt.h            |    7 +-
 sys/arch/amd64/include/pcb.h            |    7 +-
 sys/arch/amd64/include/segments.h       |   19 +++-
 sys/arch/x86/include/cpufunc.h          |    4 +-
 sys/arch/x86/include/sysarch.h          |   12 +-
 sys/arch/x86/x86/pmap.c                 |   14 +--
 14 files changed, 322 insertions(+), 163 deletions(-)

diffs (truncated from 1010 to 300 lines):

diff -r c4bae5f113be -r 125dc7eee639 sys/arch/amd64/amd64/cpufunc.S
--- a/sys/arch/amd64/amd64/cpufunc.S    Wed Jul 07 01:13:29 2010 +0000
+++ b/sys/arch/amd64/amd64/cpufunc.S    Wed Jul 07 01:14:52 2010 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: cpufunc.S,v 1.16 2009/10/01 09:13:54 skrll Exp $       */
+/*     $NetBSD: cpufunc.S,v 1.17 2010/07/07 01:14:52 chs Exp $ */
 
 /*-
  * Copyright (c) 1998, 2007, 2008 The NetBSD Foundation, Inc.
@@ -34,6 +34,7 @@
  */
 
 #include <machine/asm.h>
+#include <machine/frameasm.h>
 #include <machine/specialreg.h>
 #include <machine/segments.h>
 
@@ -513,3 +514,15 @@
        rep
        outsl
        ret
+
+ENTRY(setfs)
+       movw    %di, %fs
+       ret
+
+ENTRY(setusergs)
+       CLI(ax)
+       swapgs
+       movw    %di, %gs
+       swapgs
+       STI(ax)
+       ret
diff -r c4bae5f113be -r 125dc7eee639 sys/arch/amd64/amd64/gdt.c
--- a/sys/arch/amd64/amd64/gdt.c        Wed Jul 07 01:13:29 2010 +0000
+++ b/sys/arch/amd64/amd64/gdt.c        Wed Jul 07 01:14:52 2010 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: gdt.c,v 1.23 2009/11/21 03:11:01 rmind Exp $   */
+/*     $NetBSD: gdt.c,v 1.24 2010/07/07 01:14:52 chs Exp $     */
 
 /*-
  * Copyright (c) 1996, 1997, 2009 The NetBSD Foundation, Inc.
@@ -37,10 +37,11 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: gdt.c,v 1.23 2009/11/21 03:11:01 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: gdt.c,v 1.24 2010/07/07 01:14:52 chs Exp $");
 
 #include "opt_multiprocessor.h"
 #include "opt_xen.h"
+#include "opt_user_ldt.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -56,7 +57,6 @@
 #include <xen/hypervisor.h>
 #endif 
 
-
 int gdt_size;          /* size of GDT in bytes */
 int gdt_dyncount;      /* number of dyn. allocated GDT entries in use */
 int gdt_dynavail;
@@ -69,48 +69,45 @@
 void gdt_put_slot(int);
 
 void
-set_mem_gdt(struct mem_segment_descriptor *sd, void *base, size_t limit,
-           int type, int dpl, int gran, int def32, int is64)
+update_descriptor(void *tp, void *ep)
 {
-#if 0
-       CPU_INFO_ITERATOR cii;
-       struct cpu_info *ci;
-       int off;
-#endif
+       uint64_t *table, *entry;
+
+       table = tp;
+       entry = ep;
 
-        set_mem_segment(sd, base, limit, type, dpl, gran, def32, is64);
-#if 0
-       off = (char *)sd - gdtstore;
-        for (CPU_INFO_FOREACH(cii, ci)) {
-                if (ci->ci_gdt != NULL)
-                       *(struct mem_segment_descriptor *)(ci->ci_gdt + off) =
-                           *sd;
-        }
+#ifndef XEN
+       *table = *entry;
+#else
+       paddr_t pa;
+
+       if (!pmap_extract_ma(pmap_kernel(), (vaddr_t)table, &pa) ||
+           HYPERVISOR_update_descriptor(pa, *entry))
+               panic("HYPERVISOR_update_descriptor failed\n");
 #endif
 }
 
 void
-set_sys_gdt(struct sys_segment_descriptor *sd, void *base, size_t limit,
+set_sys_gdt(int slot, void *base, size_t limit,
            int type, int dpl, int gran)
 {
-#if 0
+       union {
+               struct sys_segment_descriptor sd;
+               uint64_t bits[2];
+       } d;
        CPU_INFO_ITERATOR cii;
        struct cpu_info *ci;
-       int off;
-#endif
+       int idx;
 
-        set_sys_segment(sd, base, limit, type, dpl, gran);
-#if 0
-       off = (char *)sd - gdtstore;
+        set_sys_segment(&d.sd, base, limit, type, dpl, gran);
+       idx = IDXSEL(GDYNSEL(slot, SEL_KPL));
         for (CPU_INFO_FOREACH(cii, ci)) {
-                if (ci->ci_gdt != NULL)
-                       *(struct sys_segment_descriptor *)(ci->ci_gdt + off) =
-                           *sd;
+                KASSERT(ci->ci_gdt != NULL);
+               update_descriptor(&ci->ci_gdt[idx + 0], &d.bits[0]);
+               update_descriptor(&ci->ci_gdt[idx + 1], &d.bits[1]);
         }
-#endif
 }
 
-
 /*
  * Initialize the GDT.
  */
@@ -157,16 +154,25 @@
 void
 gdt_alloc_cpu(struct cpu_info *ci)
 {
-#if 0
-        ci->ci_gdt = (void *)uvm_km_valloc(kernel_map, MAXGDTSIZ);
-        uvm_map_pageable(kernel_map, (vaddr_t)ci->ci_gdt,
-            (vaddr_t)ci->ci_gdt + MINGDTSIZ, false, false);
-        memset(ci->ci_gdt, 0, MINGDTSIZ);
-        memcpy(ci->ci_gdt, gdtstore,
-          DYNSEL_START + gdt_dyncount * sizeof(struct sys_segment_descriptor));
-#else
-       ci->ci_gdt = (void *)gdtstore;
-#endif
+       int max_len = MAXGDTSIZ;
+       int min_len = MINGDTSIZ;
+       struct vm_page *pg;
+       vaddr_t va;
+
+       ci->ci_gdt = (union descriptor *)uvm_km_alloc(kernel_map, max_len,
+           0, UVM_KMF_VAONLY);
+       for (va = (vaddr_t)ci->ci_gdt; va < (vaddr_t)ci->ci_gdt + min_len;
+           va += PAGE_SIZE) {
+               while ((pg = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_ZERO))
+                   == NULL) {
+                       uvm_wait("gdt_alloc_cpu");
+               }
+               pmap_kenter_pa(va, VM_PAGE_TO_PHYS(pg),
+                   VM_PROT_READ | VM_PROT_WRITE, 0);
+       }
+       pmap_update(pmap_kernel());
+       memset(ci->ci_gdt, 0, min_len);
+       memcpy(ci->ci_gdt, gdtstore, gdt_size);
 }
 
 
@@ -182,14 +188,12 @@
 #ifndef XEN
        setregion(&region, ci->ci_gdt, (uint16_t)(MAXGDTSIZ - 1));
 #else
-       /* Enter only allocated frames */
        setregion(&region, ci->ci_gdt, (uint16_t)(gdt_size - 1));
 #endif
        lgdt(&region);
 }
 
 #ifdef MULTIPROCESSOR
-
 void
 gdt_reload_cpu(struct cpu_info *ci)
 {
@@ -198,7 +202,6 @@
 #ifndef XEN
        setregion(&region, ci->ci_gdt, MAXGDTSIZ - 1);
 #else
-       /* Enter only allocated frames */
        setregion(&region, ci->ci_gdt, gdt_size - 1);
 #endif
        lgdt(&region);
@@ -303,28 +306,9 @@
 
        mutex_enter(&cpu_lock);
        slot = gdt_get_slot();
-#if 0
-       printf("tss_alloc: slot %d addr %p\n", slot, &gdt[slot]);
-#endif
-       set_sys_gdt(&gdt[slot], tss, sizeof (struct x86_64_tss)-1,
+       set_sys_gdt(slot, tss, sizeof (struct x86_64_tss) - 1,
            SDT_SYS386TSS, SEL_KPL, 0);
        mutex_exit(&cpu_lock);
-#if 0
-       printf("lolimit %lx lobase %lx type %lx dpl %lx p %lx hilimit %lx\n"
-              "xx1 %lx gran %lx hibase %lx xx2 %lx zero %lx xx3 %lx pad %lx\n",
-               (unsigned long)gdt[slot].sd_lolimit,
-               (unsigned long)gdt[slot].sd_lobase,
-               (unsigned long)gdt[slot].sd_type,
-               (unsigned long)gdt[slot].sd_dpl,
-               (unsigned long)gdt[slot].sd_p,
-               (unsigned long)gdt[slot].sd_hilimit,
-               (unsigned long)gdt[slot].sd_xx1,
-               (unsigned long)gdt[slot].sd_gran,
-               (unsigned long)gdt[slot].sd_hibase,
-               (unsigned long)gdt[slot].sd_xx2,
-               (unsigned long)gdt[slot].sd_zero,
-               (unsigned long)gdt[slot].sd_xx3);
-#endif
        return GDYNSEL(slot, SEL_KPL);
 #else  /* XEN */
        /* TSS, what for? */
@@ -344,6 +328,7 @@
 #endif
 }
 
+#ifdef USER_LDT
 void
 ldt_alloc(struct pmap *pmap, char *ldt, size_t len)
 {
@@ -355,7 +340,7 @@
        gdt = (struct sys_segment_descriptor *)&gdtstore[DYNSEL_START];
 
        slot = gdt_get_slot();
-       set_sys_gdt(&gdt[slot], ldt, len - 1, SDT_SYSLDT, SEL_KPL, 0);
+       set_sys_gdt(slot, ldt, len - 1, SDT_SYSLDT, SEL_KPL, 0);
        pmap->pm_ldt_sel = GSEL(slot, SEL_KPL);
 }
 
@@ -370,6 +355,7 @@
 
        gdt_put_slot(slot);
 }
+#endif
 
 #ifdef XEN
 void
@@ -380,22 +366,22 @@
        vaddr_t va;
 
        /*
-       * XXX: Xen even checks descriptors AFTER limit.
-       * Zero out last frame after limit if needed.
-       */
+        * XXX: Xen even checks descriptors AFTER limit.
+        * Zero out last frame after limit if needed.
+        */
        va = desc->rd_base + desc->rd_limit + 1;
        __PRINTK(("memset 0x%lx -> 0x%lx\n", va, roundup(va, PAGE_SIZE)));
        memset((void *) va, 0, roundup(va, PAGE_SIZE) - va);
-       for  (i = 0; i < roundup(desc->rd_limit,PAGE_SIZE) >> PAGE_SHIFT; i++) {
+       for (i = 0; i < roundup(desc->rd_limit, PAGE_SIZE) >> PAGE_SHIFT; i++) {
+
                /*
-               * The lgdt instr uses virtual addresses, do some translation fo
-r Xen.
-               * Mark pages R/O too, else Xen will refuse to use them
-               */
+                * The lgdt instruction uses virtual addresses,
+                * do some translation for Xen.
+                * Mark pages R/O too, else Xen will refuse to use them.
+                */
 
                frames[i] = ((paddr_t) xpmap_ptetomach(
-                               (pt_entry_t *) (desc->rd_base + (i << PAGE_SHIFT
-))))
+                               (pt_entry_t *) (desc->rd_base + (i << PAGE_SHIFT))))
                        >> PAGE_SHIFT;
                __PRINTK(("frames[%d] = 0x%lx (pa 0x%lx)\n", i, frames[i],
                    xpmap_mtop(frames[i] << PAGE_SHIFT)));
diff -r c4bae5f113be -r 125dc7eee639 sys/arch/amd64/amd64/genassym.cf
--- a/sys/arch/amd64/amd64/genassym.cf  Wed Jul 07 01:13:29 2010 +0000
+++ b/sys/arch/amd64/amd64/genassym.cf  Wed Jul 07 01:14:52 2010 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: genassym.cf,v 1.44 2010/04/28 19:17:03 dyoung Exp $
+#      $NetBSD: genassym.cf,v 1.45 2010/07/07 01:14:52 chs Exp $
 
 #
 # Copyright (c) 1998, 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -188,6 +188,10 @@
 define PCB_CR0                 offsetof(struct pcb, pcb_cr0)
 define PCB_ONFAULT             offsetof(struct pcb, pcb_onfault)
 define PCB_FPCPU               offsetof(struct pcb, pcb_fpcpu)
+define PCB_FLAGS               offsetof(struct pcb, pcb_flags)
+define PCB_COMPAT32            PCB_COMPAT32
+define PCB_FS                  offsetof(struct pcb, pcb_fs)
+define PCB_GS                  offsetof(struct pcb, pcb_gs)



Home | Main Index | Thread Index | Old Index