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/bf29fadeb4eb
branches: trunk
changeset: 1009491:bf29fadeb4eb
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 95fbca53685d -r bf29fadeb4eb 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 95fbca53685d -r bf29fadeb4eb 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 95fbca53685d -r bf29fadeb4eb 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 95fbca53685d -r bf29fadeb4eb 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 95fbca53685d -r bf29fadeb4eb 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