Source-Changes-HG archive

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

[src/trunk]: src/sys/arch Give the ldt a fixed size of one page (512 slots), ...



details:   https://anonhg.NetBSD.org/src/rev/8a28fbe889cb
branches:  trunk
changeset: 931234:8a28fbe889cb
user:      maxv <maxv%NetBSD.org@localhost>
date:      Fri Apr 24 16:27:27 2020 +0000

description:
Give the ldt a fixed size of one page (512 slots), and drop the variable-
sized mechanism that was too complex.

This fixes a race between USER_LDT and SVS: during context switches, the
way SVS installs the new ldt relies on the ldt pointer AND the ldt size,
but both cannot be accessed atomically at the same time.

diffstat:

 sys/arch/amd64/amd64/netbsd32_machdep.c |   9 ++-
 sys/arch/amd64/include/gdt.h            |   7 +-
 sys/arch/i386/include/gdt.h             |   7 +-
 sys/arch/x86/include/pmap.h             |  11 +++-
 sys/arch/x86/x86/pmap.c                 |  78 ++++++++++++++------------------
 sys/arch/x86/x86/svs.c                  |  27 ++++++++--
 sys/arch/x86/x86/sys_machdep.c          |  58 +++++++++---------------
 7 files changed, 98 insertions(+), 99 deletions(-)

diffs (truncated from 514 to 300 lines):

diff -r 3a5ef7cec4e3 -r 8a28fbe889cb sys/arch/amd64/amd64/netbsd32_machdep.c
--- a/sys/arch/amd64/amd64/netbsd32_machdep.c   Fri Apr 24 14:29:19 2020 +0000
+++ b/sys/arch/amd64/amd64/netbsd32_machdep.c   Fri Apr 24 16:27:27 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: netbsd32_machdep.c,v 1.134 2020/04/23 16:16:14 christos Exp $  */
+/*     $NetBSD: netbsd32_machdep.c,v 1.135 2020/04/24 16:27:27 maxv Exp $      */
 
 /*
  * Copyright (c) 2001 Wasabi Systems, Inc.
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.134 2020/04/23 16:16:14 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: netbsd32_machdep.c,v 1.135 2020/04/24 16:27:27 maxv Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_compat_netbsd.h"
@@ -74,6 +74,7 @@
 #include <machine/netbsd32_machdep.h>
 #include <machine/sysarch.h>
 #include <machine/userret.h>
+#include <machine/gdt.h>
 
 #include <compat/netbsd32/netbsd32.h>
 #include <compat/netbsd32/netbsd32_exec.h>
@@ -628,7 +629,7 @@
        ua.start = ua32.start;
        ua.num = ua32.num;
 
-       if (ua.num < 0 || ua.num > 8192)
+       if (ua.num < 0 || ua.num > MAX_USERLDT_SLOTS)
                return EINVAL;
 
        descv = malloc(sizeof(*descv) * ua.num, M_TEMP, M_WAITOK);
@@ -656,7 +657,7 @@
        ua.start = ua32.start;
        ua.num = ua32.num;
 
-       if (ua.num < 0 || ua.num > 8192)
+       if (ua.num < 0 || ua.num > MAX_USERLDT_SLOTS)
                return EINVAL;
 
        cp = malloc(ua.num * sizeof(union descriptor), M_TEMP, M_WAITOK);
diff -r 3a5ef7cec4e3 -r 8a28fbe889cb sys/arch/amd64/include/gdt.h
--- a/sys/arch/amd64/include/gdt.h      Fri Apr 24 14:29:19 2020 +0000
+++ b/sys/arch/amd64/include/gdt.h      Fri Apr 24 16:27:27 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: gdt.h,v 1.10 2017/02/08 10:08:26 maxv Exp $    */
+/*     $NetBSD: gdt.h,v 1.11 2020/04/24 16:27:28 maxv Exp $    */
 
 /*-
  * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
@@ -45,5 +45,6 @@
 void ldt_free(int);
 #endif
 
-#define MINGDTSIZ       PAGE_SIZE
-#define MAXGDTSIZ       65536
+#define MAXGDTSIZ              65536
+#define MAX_USERLDT_SIZE       PAGE_SIZE
+#define MAX_USERLDT_SLOTS      (int)(MAX_USERLDT_SIZE / sizeof(union descriptor))
diff -r 3a5ef7cec4e3 -r 8a28fbe889cb sys/arch/i386/include/gdt.h
--- a/sys/arch/i386/include/gdt.h       Fri Apr 24 14:29:19 2020 +0000
+++ b/sys/arch/i386/include/gdt.h       Fri Apr 24 16:27:27 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: gdt.h,v 1.16 2017/07/02 09:02:06 maxv Exp $    */
+/*     $NetBSD: gdt.h,v 1.17 2020/04/24 16:27:28 maxv Exp $    */
 
 /*-
  * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
@@ -44,5 +44,6 @@
 
 #endif /* LOCORE */
 
-#define        MINGDTSIZ       PAGE_SIZE
-#define        MAXGDTSIZ       65536
+#define MAXGDTSIZ              65536
+#define MAX_USERLDT_SIZE       PAGE_SIZE
+#define MAX_USERLDT_SLOTS      (int)(MAX_USERLDT_SIZE / sizeof(union descriptor))
diff -r 3a5ef7cec4e3 -r 8a28fbe889cb sys/arch/x86/include/pmap.h
--- a/sys/arch/x86/include/pmap.h       Fri Apr 24 14:29:19 2020 +0000
+++ b/sys/arch/x86/include/pmap.h       Fri Apr 24 16:27:27 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pmap.h,v 1.117 2020/04/05 00:21:11 ad Exp $    */
+/*     $NetBSD: pmap.h,v 1.118 2020/04/24 16:27:28 maxv Exp $  */
 
 /*
  * Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -191,9 +191,13 @@
 #define MAXGDTSIZ 65536 /* XXX */
 #endif
 
+#ifndef MAX_USERLDT_SIZE
+#define MAX_USERLDT_SIZE PAGE_SIZE /* XXX */
+#endif
+
 struct pcpu_entry {
        uint8_t gdt[MAXGDTSIZ];
-       uint8_t ldt[MAXGDTSIZ];
+       uint8_t ldt[MAX_USERLDT_SIZE];
        uint8_t tss[PAGE_SIZE];
        uint8_t ist0[PAGE_SIZE];
        uint8_t ist1[PAGE_SIZE];
@@ -268,8 +272,9 @@
 #endif /* !defined(__x86_64__) */
 
        union descriptor *pm_ldt;       /* user-set LDT */
-       size_t pm_ldt_len;              /* size of LDT in bytes */
+       size_t pm_ldt_len;              /* XXX unused, remove */
        int pm_ldt_sel;                 /* LDT selector */
+
        kcpuset_t *pm_cpus;             /* mask of CPUs using pmap */
        kcpuset_t *pm_kernel_cpus;      /* mask of CPUs using kernel part
                                         of pmap */
diff -r 3a5ef7cec4e3 -r 8a28fbe889cb sys/arch/x86/x86/pmap.c
--- a/sys/arch/x86/x86/pmap.c   Fri Apr 24 14:29:19 2020 +0000
+++ b/sys/arch/x86/x86/pmap.c   Fri Apr 24 16:27:27 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pmap.c,v 1.381 2020/04/05 00:21:11 ad Exp $    */
+/*     $NetBSD: pmap.c,v 1.382 2020/04/24 16:27:28 maxv Exp $  */
 
 /*
  * Copyright (c) 2008, 2010, 2016, 2017, 2019, 2020 The NetBSD Foundation, Inc.
@@ -130,7 +130,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.381 2020/04/05 00:21:11 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.382 2020/04/24 16:27:28 maxv Exp $");
 
 #include "opt_user_ldt.h"
 #include "opt_lockdebug.h"
@@ -1208,7 +1208,6 @@
        kcpuset_create(&kpm->pm_kernel_cpus, true);
 
        kpm->pm_ldt = NULL;
-       kpm->pm_ldt_len = 0;
        kpm->pm_ldt_sel = GSYSSEL(GLDT_SEL, SEL_KPL);
 
        /*
@@ -2857,7 +2856,6 @@
 
        /* init the LDT */
        pmap->pm_ldt = NULL;
-       pmap->pm_ldt_len = 0;
        pmap->pm_ldt_sel = GSYSSEL(GLDT_SEL, SEL_KPL);
 
        return (pmap);
@@ -2952,7 +2950,7 @@
 #ifdef USER_LDT
        if (pmap->pm_ldt != NULL) {
                /*
-                * no need to switch the LDT; this address space is gone,
+                * No need to switch the LDT; this address space is gone,
                 * nothing is using it.
                 *
                 * No need to lock the pmap for ldt_free (or anything else),
@@ -2963,7 +2961,7 @@
                ldt_free(pmap->pm_ldt_sel);
                mutex_exit(&cpu_lock);
                uvm_km_free(kernel_map, (vaddr_t)pmap->pm_ldt,
-                   pmap->pm_ldt_len, UVM_KMF_WIRED);
+                   MAX_USERLDT_SIZE, UVM_KMF_WIRED);
        }
 #endif
 
@@ -3209,7 +3207,6 @@
 {
 #ifdef USER_LDT
        union descriptor *new_ldt;
-       size_t len;
        int sel;
 
        if (__predict_true(pmap1->pm_ldt == NULL)) {
@@ -3219,18 +3216,16 @@
        /*
         * Copy the LDT into the new process.
         *
-        * Read pmap1's ldt pointer and length unlocked; if it changes
-        * behind our back we'll retry. This will starve if there's a
-        * stream of LDT changes in another thread but that should not
-        * happen.
+        * Read pmap1's ldt pointer unlocked; if it changes behind our back
+        * we'll retry. This will starve if there's a stream of LDT changes
+        * in another thread but that should not happen.
         */
 
- retry:
+retry:
        if (pmap1->pm_ldt != NULL) {
-               len = pmap1->pm_ldt_len;
                /* Allocate space for the new process's LDT */
-               new_ldt = (union descriptor *)uvm_km_alloc(kernel_map, len, 0,
-                   UVM_KMF_WIRED);
+               new_ldt = (union descriptor *)uvm_km_alloc(kernel_map,
+                   MAX_USERLDT_SIZE, 0, UVM_KMF_WIRED);
                if (new_ldt == NULL) {
                        printf("WARNING: %s: unable to allocate LDT space\n",
                            __func__);
@@ -3238,51 +3233,48 @@
                }
                mutex_enter(&cpu_lock);
                /* Get a GDT slot for it */
-               sel = ldt_alloc(new_ldt, len);
+               sel = ldt_alloc(new_ldt, MAX_USERLDT_SIZE);
                if (sel == -1) {
                        mutex_exit(&cpu_lock);
-                       uvm_km_free(kernel_map, (vaddr_t)new_ldt, len,
-                           UVM_KMF_WIRED);
+                       uvm_km_free(kernel_map, (vaddr_t)new_ldt,
+                           MAX_USERLDT_SIZE, UVM_KMF_WIRED);
                        printf("WARNING: %s: unable to allocate LDT selector\n",
                            __func__);
                        return;
                }
        } else {
                /* Wasn't anything there after all. */
-               len = -1;
                new_ldt = NULL;
                sel = -1;
                mutex_enter(&cpu_lock);
        }
 
-       /* If there's still something there now that we have cpu_lock... */
+       /*
+        * Now that we have cpu_lock, ensure the LDT status is the same.
+        */
        if (pmap1->pm_ldt != NULL) {
-               if (len != pmap1->pm_ldt_len) {
-                       /* Oops, it changed. Drop what we did and try again */
-                       if (len != -1) {
-                               ldt_free(sel);
-                               uvm_km_free(kernel_map, (vaddr_t)new_ldt,
-                                   len, UVM_KMF_WIRED);
-                       }
+               if (new_ldt == NULL) {
+                       /* A wild LDT just appeared. */
                        mutex_exit(&cpu_lock);
                        goto retry;
                }
 
                /* Copy the LDT data and install it in pmap2 */
-               memcpy(new_ldt, pmap1->pm_ldt, len);
+               memcpy(new_ldt, pmap1->pm_ldt, MAX_USERLDT_SIZE);
                pmap2->pm_ldt = new_ldt;
-               pmap2->pm_ldt_len = pmap1->pm_ldt_len;
                pmap2->pm_ldt_sel = sel;
-               len = -1;
-       }
-
-       if (len != -1) {
-               /* There wasn't still something there, so mop up */
-               ldt_free(sel);
                mutex_exit(&cpu_lock);
-               uvm_km_free(kernel_map, (vaddr_t)new_ldt, len,
-                   UVM_KMF_WIRED);
        } else {
+               if (new_ldt != NULL) {
+                       /* The LDT disappeared, drop what we did. */
+                       ldt_free(sel);
+                       mutex_exit(&cpu_lock);
+                       uvm_km_free(kernel_map, (vaddr_t)new_ldt,
+                           MAX_USERLDT_SIZE, UVM_KMF_WIRED);
+                       return;
+               }
+
+               /* We're good, just leave. */
                mutex_exit(&cpu_lock);
        }
 #endif /* USER_LDT */
@@ -3337,9 +3329,8 @@
 pmap_ldt_cleanup(struct lwp *l)
 {
        pmap_t pmap = l->l_proc->p_vmspace->vm_map.pmap;
-       union descriptor *dp = NULL;
-       size_t len = 0;
-       int sel = -1;
+       union descriptor *ldt;
+       int sel;
 
        if (__predict_true(pmap->pm_ldt == NULL)) {
                return;
@@ -3348,14 +3339,13 @@
        mutex_enter(&cpu_lock);
        if (pmap->pm_ldt != NULL) {
                sel = pmap->pm_ldt_sel;
-               dp = pmap->pm_ldt;
-               len = pmap->pm_ldt_len;
+               ldt = pmap->pm_ldt;
                pmap->pm_ldt_sel = GSYSSEL(GLDT_SEL, SEL_KPL);
                pmap->pm_ldt = NULL;
-               pmap->pm_ldt_len = 0;
                pmap_ldt_sync(pmap);
                ldt_free(sel);
-               uvm_km_free(kernel_map, (vaddr_t)dp, len, UVM_KMF_WIRED);
+               uvm_km_free(kernel_map, (vaddr_t)ldt, MAX_USERLDT_SIZE,
+                   UVM_KMF_WIRED);
        }
        mutex_exit(&cpu_lock);



Home | Main Index | Thread Index | Old Index