Module Name: src
Committed By: snj
Date: Sat Apr 4 17:39:10 UTC 2009
Modified Files:
src/sys/arch/amd64/amd64 [netbsd-5]: gdt.c machdep.c
src/sys/arch/i386/i386 [netbsd-5]: gdt.c kvm86.c locore.S machdep.c
svr4_sigcode.S vector.S
src/sys/arch/i386/include [netbsd-5]: pcb.h
src/sys/arch/x86/include [netbsd-5]: pmap.h sysarch.h
src/sys/arch/x86/x86 [netbsd-5]: pmap.c sys_machdep.c
src/sys/compat/linux/arch/i386 [netbsd-5]: linux_machdep.c
src/sys/kern [netbsd-5]: init_main.c
Log Message:
Pull up following revision(s) (requested by ad in ticket #656):
sys/arch/amd64/amd64/gdt.c: revision 1.21 via patch
sys/arch/amd64/amd64/machdep.c: revision 1.129 via patch
sys/arch/i386/i386/gdt.c: revision 1.47 via patch
sys/arch/i386/i386/kvm86.c: revision 1.17 via patch
sys/arch/i386/i386/locore.S: revision 1.85 via patch
sys/arch/i386/i386/machdep.c: revision 1.666 via patch
sys/arch/i386/i386/vector.S: revision 1.45 via patch
sys/arch/i386/include/pcb.h: revision 1.47 via patch
sys/arch/x86/include/pmap.h: revision 1.22 via patch
sys/arch/x86/include/sysarch.h: revision 1.8 via patch
sys/arch/x86/x86/pmap.c: revision 1.80 via patch
sys/arch/x86/x86/sys_machdep.c: revision 1.17 via patch
sys/compat/linux/arch/i386/linux_machdep.c: revision 1.143 via patch
sys/kern/init_main.c: revision 1.384 via patch
PR port-i386/40143 Viewing an mpeg transport stream with mplayer causes crash
Fix numerous problems:
1. LDT updates are not atomic.
2. Number of processes running with private LDTs and/or I/O bitmaps
is not capped. System with high maxprocs can be paniced.
3. LDTR can be leaked over context switch.
4. GDT slot allocations can race, giving the same LDT slot to two procs.
5. Incomplete interrupt/trap frames can be stacked.
6. In some rare cases segment faults are not handled correctly.
To generate a diff of this commit:
cvs rdiff -u -r1.19 -r1.19.8.1 src/sys/arch/amd64/amd64/gdt.c
cvs rdiff -u -r1.102.4.9 -r1.102.4.10 src/sys/arch/amd64/amd64/machdep.c
cvs rdiff -u -r1.45 -r1.45.10.1 src/sys/arch/i386/i386/gdt.c
cvs rdiff -u -r1.15 -r1.15.12.1 src/sys/arch/i386/i386/kvm86.c
cvs rdiff -u -r1.78.4.2 -r1.78.4.3 src/sys/arch/i386/i386/locore.S
cvs rdiff -u -r1.644.4.9 -r1.644.4.10 src/sys/arch/i386/i386/machdep.c
cvs rdiff -u -r1.12 -r1.12.10.1 src/sys/arch/i386/i386/svr4_sigcode.S
cvs rdiff -u -r1.42.6.1 -r1.42.6.2 src/sys/arch/i386/i386/vector.S
cvs rdiff -u -r1.46 -r1.46.4.1 src/sys/arch/i386/include/pcb.h
cvs rdiff -u -r1.20 -r1.20.4.1 src/sys/arch/x86/include/pmap.h
cvs rdiff -u -r1.7 -r1.7.10.1 src/sys/arch/x86/include/sysarch.h
cvs rdiff -u -r1.74 -r1.74.4.1 src/sys/arch/x86/x86/pmap.c
cvs rdiff -u -r1.15 -r1.15.8.1 src/sys/arch/x86/x86/sys_machdep.c
cvs rdiff -u -r1.141 -r1.141.4.1 \
src/sys/compat/linux/arch/i386/linux_machdep.c
cvs rdiff -u -r1.371.2.2 -r1.371.2.3 src/sys/kern/init_main.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/amd64/amd64/gdt.c
diff -u src/sys/arch/amd64/amd64/gdt.c:1.19 src/sys/arch/amd64/amd64/gdt.c:1.19.8.1
--- src/sys/arch/amd64/amd64/gdt.c:1.19 Sun May 11 15:32:20 2008
+++ src/sys/arch/amd64/amd64/gdt.c Sat Apr 4 17:39:09 2009
@@ -1,11 +1,11 @@
-/* $NetBSD: gdt.c,v 1.19 2008/05/11 15:32:20 ad Exp $ */
+/* $NetBSD: gdt.c,v 1.19.8.1 2009/04/04 17:39:09 snj Exp $ */
/*-
- * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
+ * Copyright (c) 1996, 1997, 2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by John T. Kohl and Charles M. Hannum.
+ * by John T. Kohl, by Charles M. Hannum, and by Andrew Doran.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: gdt.c,v 1.19 2008/05/11 15:32:20 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: gdt.c,v 1.19.8.1 2009/04/04 17:39:09 snj Exp $");
#include "opt_multiprocessor.h"
#include "opt_xen.h"
@@ -47,6 +47,7 @@
#include <sys/proc.h>
#include <sys/mutex.h>
#include <sys/user.h>
+#include <sys/cpu.h>
#include <uvm/uvm.h>
@@ -63,38 +64,11 @@
int gdt_next; /* next available slot for sweeping */
int gdt_free; /* next free slot; terminated with GNULL_SEL */
-kmutex_t gdt_lock_store;
-
-static inline void gdt_lock(void);
-static inline void gdt_unlock(void);
void gdt_init(void);
void gdt_grow(void);
int gdt_get_slot(void);
void gdt_put_slot(int);
-/*
- * Lock and unlock the GDT, to avoid races in case gdt_{ge,pu}t_slot() sleep
- * waiting for memory.
- *
- * Note that the locking done here is not sufficient for multiprocessor
- * systems. A freshly allocated slot will still be of type SDT_SYSNULL for
- * some time after the GDT is unlocked, so gdt_compact() could attempt to
- * reclaim it.
- */
-static inline void
-gdt_lock(void)
-{
-
- mutex_enter(&gdt_lock_store);
-}
-
-static inline void
-gdt_unlock(void)
-{
-
- mutex_exit(&gdt_lock_store);
-}
-
void
set_mem_gdt(struct mem_segment_descriptor *sd, void *base, size_t limit,
int type, int dpl, int gran, int def32, int is64)
@@ -149,8 +123,6 @@
vaddr_t va;
struct cpu_info *ci = &cpu_info_primary;
- mutex_init(&gdt_lock_store, MUTEX_DEFAULT, IPL_NONE);
-
gdt_size = MINGDTSIZ;
gdt_dyncount = 0;
gdt_next = 0;
@@ -279,7 +251,7 @@
gdt = (struct sys_segment_descriptor *)&gdtstore[DYNSEL_START];
- gdt_lock();
+ KASSERT(mutex_owned(&cpu_lock));
if (gdt_free != GNULL_SEL) {
slot = gdt_free;
@@ -300,7 +272,6 @@
}
gdt_dyncount++;
- gdt_unlock();
return (slot);
}
@@ -312,16 +283,14 @@
{
struct sys_segment_descriptor *gdt;
+ KASSERT(mutex_owned(&cpu_lock));
+
gdt = (struct sys_segment_descriptor *)&gdtstore[DYNSEL_START];
- gdt_lock();
gdt_dyncount--;
-
gdt[slot].sd_type = SDT_SYSNULL;
gdt[slot].sd_xx3 = gdt_free;
gdt_free = slot;
-
- gdt_unlock();
}
int
@@ -333,12 +302,14 @@
gdt = (struct sys_segment_descriptor *)&gdtstore[DYNSEL_START];
+ 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,
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",
@@ -366,7 +337,9 @@
tss_free(int sel)
{
#ifndef XEN
+ mutex_enter(&cpu_lock);
gdt_put_slot(IDXDYNSEL(sel));
+ mutex_exit(&cpu_lock);
#else
KASSERT(sel == GSEL(GNULL_SEL, SEL_KPL));
#endif
@@ -378,6 +351,8 @@
int slot;
struct sys_segment_descriptor *gdt;
+ KASSERT(mutex_owned(&cpu_lock));
+
gdt = (struct sys_segment_descriptor *)&gdtstore[DYNSEL_START];
slot = gdt_get_slot();
@@ -390,6 +365,8 @@
{
int slot;
+ KASSERT(mutex_owned(&cpu_lock));
+
slot = IDXDYNSEL(pmap->pm_ldt_sel);
gdt_put_slot(slot);
Index: src/sys/arch/amd64/amd64/machdep.c
diff -u src/sys/arch/amd64/amd64/machdep.c:1.102.4.9 src/sys/arch/amd64/amd64/machdep.c:1.102.4.10
--- src/sys/arch/amd64/amd64/machdep.c:1.102.4.9 Mon Mar 2 20:00:20 2009
+++ src/sys/arch/amd64/amd64/machdep.c Sat Apr 4 17:39:09 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: machdep.c,v 1.102.4.9 2009/03/02 20:00:20 snj Exp $ */
+/* $NetBSD: machdep.c,v 1.102.4.10 2009/04/04 17:39:09 snj Exp $ */
/*-
* Copyright (c) 1996, 1997, 1998, 2000, 2006, 2007, 2008
@@ -112,7 +112,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.102.4.9 2009/03/02 20:00:20 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.102.4.10 2009/04/04 17:39:09 snj Exp $");
/* #define XENDEBUG_LOW */
@@ -2042,7 +2042,7 @@
if (((gr[_REG_RFLAGS] ^ tf->tf_rflags) & PSL_USERSTATIC) != 0)
return EINVAL;
- if (__predict_false((pmap->pm_flags & PMF_USER_LDT) != 0)) {
+ if (__predict_false(pmap->pm_ldt != NULL)) {
error = valid_user_selector(l, gr[_REG_ES], NULL, 0);
if (error != 0)
return error;
@@ -2134,7 +2134,7 @@
if (ldtp != NULL) {
dt = ldtp;
len = llen;
- } else if (pmap->pm_flags & PMF_USER_LDT) {
+ } else if (pmap->pm_ldt != NULL) {
len = pmap->pm_ldt_len; /* XXX broken */
dt = (char *)pmap->pm_ldt;
} else {
Index: src/sys/arch/i386/i386/gdt.c
diff -u src/sys/arch/i386/i386/gdt.c:1.45 src/sys/arch/i386/i386/gdt.c:1.45.10.1
--- src/sys/arch/i386/i386/gdt.c:1.45 Mon Apr 28 20:23:24 2008
+++ src/sys/arch/i386/i386/gdt.c Sat Apr 4 17:39:09 2009
@@ -1,11 +1,11 @@
-/* $NetBSD: gdt.c,v 1.45 2008/04/28 20:23:24 martin Exp $ */
+/* $NetBSD: gdt.c,v 1.45.10.1 2009/04/04 17:39:09 snj Exp $ */
/*-
- * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
+ * Copyright (c) 1996, 1997, 2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by John T. Kohl and Charles M. Hannum.
+ * by John T. Kohl, by Charles M. Hannum, and by Andrew Doran.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: gdt.c,v 1.45 2008/04/28 20:23:24 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: gdt.c,v 1.45.10.1 2009/04/04 17:39:09 snj Exp $");
#include "opt_multiprocessor.h"
#include "opt_xen.h"
@@ -40,6 +40,7 @@
#include <sys/proc.h>
#include <sys/mutex.h>
#include <sys/user.h>
+#include <sys/cpu.h>
#include <uvm/uvm.h>
@@ -57,40 +58,14 @@
int gdt_free[2]; /* next free slot; terminated with GNULL_SEL */
#endif
+static int ldt_count; /* number of LDTs */
+static int ldt_max = 1000;/* max number of LDTs */
-static kmutex_t gdt_lock_store;
-
-static inline void gdt_lock(void);
-static inline void gdt_unlock(void);
void gdt_init(void);
void gdt_grow(int);
int gdt_get_slot1(int);
void gdt_put_slot1(int, int);
-/*
- * Lock and unlock the GDT, to avoid races in case gdt_{ge,pu}t_slot() sleep
- * waiting for memory.
- *
- * Note that the locking done here is not sufficient for multiprocessor
- * systems. A freshly allocated slot will still be of type SDT_SYSNULL for
- * some time after the GDT is unlocked, so gdt_compact() could attempt to
- * reclaim it.
- */
-static inline void
-gdt_lock()
-{
-
- mutex_enter(&gdt_lock_store);
-}
-
-static inline void
-gdt_unlock()
-{
-
- mutex_exit(&gdt_lock_store);
-}
-
-
static void
update_descriptor(union descriptor *table, union descriptor *entry)
{
@@ -141,8 +116,6 @@
vaddr_t va;
struct cpu_info *ci = &cpu_info_primary;
- mutex_init(&gdt_lock_store, MUTEX_DEFAULT, IPL_NONE);
-
max_len = MAXGDTSIZ * sizeof(gdt[0]);
min_len = MINGDTSIZ * sizeof(gdt[0]);
@@ -325,6 +298,9 @@
int
gdt_get_slot()
{
+
+ KASSERT(mutex_owned(&cpu_lock));
+
return gdt_get_slot1(0);
}
@@ -334,7 +310,7 @@
int slot;
size_t offset;
- gdt_lock();
+ KASSERT(mutex_owned(&cpu_lock));
if (gdt_free[which] != GNULL_SEL) {
slot = gdt_free[which];
@@ -352,7 +328,6 @@
}
gdt_count[which]++;
- gdt_unlock();
return (slot);
}
@@ -362,6 +337,9 @@
void
gdt_put_slot(int slot)
{
+
+ KASSERT(mutex_owned(&cpu_lock));
+
gdt_put_slot1(slot, 0);
}
@@ -372,7 +350,8 @@
d.raw[0] = 0;
d.raw[1] = 0;
- gdt_lock();
+ KASSERT(mutex_owned(&cpu_lock));
+
gdt_count[which]--;
d.gd.gd_type = SDT_SYSNULL;
@@ -380,8 +359,6 @@
update_descriptor(&gdt[slot], &d);
gdt_free[which] = slot;
-
- gdt_unlock();
}
#ifndef XEN
@@ -390,9 +367,12 @@
{
int slot;
+ mutex_enter(&cpu_lock);
slot = gdt_get_slot();
setgdt(slot, tss, sizeof(struct i386tss) + IOMAPSIZE - 1,
SDT_SYS386TSS, SEL_KPL, 0, 0);
+ mutex_exit(&cpu_lock);
+
return GSEL(slot, SEL_KPL);
}
@@ -400,17 +380,24 @@
tss_free(int sel)
{
+ mutex_enter(&cpu_lock);
gdt_put_slot(IDXSEL(sel));
+ mutex_exit(&cpu_lock);
}
#endif
-/*
- * Caller must have pmap locked for both of these functions.
- */
int
ldt_alloc(union descriptor *ldtp, size_t len)
{
int slot;
+
+ KASSERT(mutex_owned(&cpu_lock));
+
+ if (ldt_count >= ldt_max) {
+ return -1;
+ }
+ ldt_count++;
+
#ifndef XEN
slot = gdt_get_slot();
setgdt(slot, ldtp, len - 1, SDT_SYSLDT, SEL_KPL, 0, 0);
@@ -420,6 +407,7 @@
cpu_info_primary.ci_gdt[slot].ld.ld_entries =
len / sizeof(union descriptor);
#endif
+
return GSEL(slot, SEL_KPL);
}
@@ -428,10 +416,14 @@
{
int slot;
+ KASSERT(mutex_owned(&cpu_lock));
+ KASSERT(ldt_count > 0);
+
slot = IDXSEL(sel);
#ifndef XEN
gdt_put_slot(slot);
#else
gdt_put_slot1(slot, 1);
#endif
+ ldt_count--;
}
Index: src/sys/arch/i386/i386/kvm86.c
diff -u src/sys/arch/i386/i386/kvm86.c:1.15 src/sys/arch/i386/i386/kvm86.c:1.15.12.1
--- src/sys/arch/i386/i386/kvm86.c:1.15 Sun Apr 27 11:37:48 2008
+++ src/sys/arch/i386/i386/kvm86.c Sat Apr 4 17:39:09 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: kvm86.c,v 1.15 2008/04/27 11:37:48 ad Exp $ */
+/* $NetBSD: kvm86.c,v 1.15.12.1 2009/04/04 17:39:09 snj Exp $ */
/*
* Copyright (c) 2002
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kvm86.c,v 1.15 2008/04/27 11:37:48 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kvm86.c,v 1.15.12.1 2009/04/04 17:39:09 snj Exp $");
#include "opt_multiprocessor.h"
@@ -113,11 +113,13 @@
vmd->iomap[i] = 0;
tss->tss_iobase = ((char *)vmd->iomap - (char *)tss) << 16;
+ /* setup TSS descriptor (including our iomap) */
+ mutex_enter(&cpu_lock);
slot = gdt_get_slot();
kvm86_tss_sel = GSEL(slot, SEL_KPL);
- /* setup TSS descriptor (including our iomap) */
setgdt(slot, tss, sizeof(*tss) + sizeof(vmd->iomap) - 1,
SDT_SYS386TSS, SEL_KPL, 0, 0);
+ mutex_exit(&cpu_lock);
/* prepare VM for BIOS calls */
kvm86_mapbios(vmd);
Index: src/sys/arch/i386/i386/locore.S
diff -u src/sys/arch/i386/i386/locore.S:1.78.4.2 src/sys/arch/i386/i386/locore.S:1.78.4.3
--- src/sys/arch/i386/i386/locore.S:1.78.4.2 Mon Feb 2 03:22:55 2009
+++ src/sys/arch/i386/i386/locore.S Sat Apr 4 17:39:09 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: locore.S,v 1.78.4.2 2009/02/02 03:22:55 snj Exp $ */
+/* $NetBSD: locore.S,v 1.78.4.3 2009/04/04 17:39:09 snj Exp $ */
/*
* Copyright-o-rama!
@@ -134,7 +134,7 @@
*/
#include <machine/asm.h>
-__KERNEL_RCSID(0, "$NetBSD: locore.S,v 1.78.4.2 2009/02/02 03:22:55 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: locore.S,v 1.78.4.3 2009/04/04 17:39:09 snj Exp $");
#include "opt_compat_oldboot.h"
#include "opt_ddb.h"
@@ -1078,8 +1078,10 @@
* Old call gate entry for syscall
*/
IDTVEC(osyscall)
+ cli # must be first instruction
pushfl # set eflags in trap frame
popl 8(%esp)
+ orl $PSL_I,(%esp) # re-enable ints on return to user
pushl $7 # size of instruction for restart
jmp syscall1
IDTVEC_END(osyscall)
@@ -1094,6 +1096,7 @@
syscall1:
pushl $T_ASTFLT # trap # for doing ASTs
INTRENTRY
+ STI(%eax)
#ifdef DIAGNOSTIC
movl CPUVAR(ILEVEL),%ebx
testl %ebx,%ebx
Index: src/sys/arch/i386/i386/machdep.c
diff -u src/sys/arch/i386/i386/machdep.c:1.644.4.9 src/sys/arch/i386/i386/machdep.c:1.644.4.10
--- src/sys/arch/i386/i386/machdep.c:1.644.4.9 Mon Mar 2 20:09:04 2009
+++ src/sys/arch/i386/i386/machdep.c Sat Apr 4 17:39:09 2009
@@ -1,12 +1,14 @@
-/* $NetBSD: machdep.c,v 1.644.4.9 2009/03/02 20:09:04 snj Exp $ */
+/* $NetBSD: machdep.c,v 1.644.4.10 2009/04/04 17:39:09 snj Exp $ */
/*-
- * Copyright (c) 1996, 1997, 1998, 2000, 2004, 2006, 2008 The NetBSD Foundation, Inc.
+ * Copyright (c) 1996, 1997, 1998, 2000, 2004, 2006, 2008, 2009
+ * The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Charles M. Hannum, by Jason R. Thorpe of the Numerical Aerospace
- * Simulation Facility, NASA Ames Research Center and by Julio M. Merino Vidal.
+ * Simulation Facility NASA Ames Research Center, by Julio M. Merino Vidal,
+ * and by Andrew Doran.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -65,7 +67,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.644.4.9 2009/03/02 20:09:04 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.644.4.10 2009/04/04 17:39:09 snj Exp $");
#include "opt_beep.h"
#include "opt_compat_ibcs2.h"
@@ -538,7 +540,7 @@
l = &lwp0;
pcb = &l->l_addr->u_pcb;
- pcb->pcb_ldt_sel = pmap_kernel()->pm_ldt_sel = GSEL(GLDT_SEL, SEL_KPL);
+ pmap_kernel()->pm_ldt_sel = GSEL(GLDT_SEL, SEL_KPL);
pcb->pcb_cr0 = rcr0() & ~CR0_TS;
pcb->pcb_esp0 = USER_TO_UAREA(l->l_addr) + KSTACK_SIZE - 16;
pcb->pcb_iopl = SEL_KPL;
@@ -547,7 +549,7 @@
memcpy(pcb->pcb_gsd, &gdt[GUDATA_SEL], sizeof(pcb->pcb_gsd));
#ifndef XEN
- lldt(pcb->pcb_ldt_sel);
+ lldt(pmap_kernel()->pm_ldt_sel);
#else
HYPERVISOR_fpu_taskswitch();
XENPRINTF(("lwp tss sp %p ss %04x/%04x\n",
@@ -1876,19 +1878,18 @@
/* exceptions */
for (x = 0; x < 32; x++) {
idt_vec_reserve(x);
- setgate(&idt[x], IDTVEC(exceptions)[x], 0,
- (x == 7 || x == 16) ? SDT_SYS386IGT : SDT_SYS386TGT,
+ setgate(&idt[x], IDTVEC(exceptions)[x], 0, SDT_SYS386IGT,
(x == 3 || x == 4) ? SEL_UPL : SEL_KPL,
GSEL(GCODE_SEL, SEL_KPL));
}
/* new-style interrupt gate for syscalls */
idt_vec_reserve(128);
- setgate(&idt[128], &IDTVEC(syscall), 0, SDT_SYS386TGT, SEL_UPL,
+ setgate(&idt[128], &IDTVEC(syscall), 0, SDT_SYS386IGT, SEL_UPL,
GSEL(GCODE_SEL, SEL_KPL));
#ifdef COMPAT_SVR4
idt_vec_reserve(0xd2);
- setgate(&idt[0xd2], &IDTVEC(svr4_fasttrap), 0, SDT_SYS386TGT,
+ setgate(&idt[0xd2], &IDTVEC(svr4_fasttrap), 0, SDT_SYS386IGT,
SEL_UPL, GSEL(GCODE_SEL, SEL_KPL));
#endif /* COMPAT_SVR4 */
Index: src/sys/arch/i386/i386/svr4_sigcode.S
diff -u src/sys/arch/i386/i386/svr4_sigcode.S:1.12 src/sys/arch/i386/i386/svr4_sigcode.S:1.12.10.1
--- src/sys/arch/i386/i386/svr4_sigcode.S:1.12 Mon Apr 28 20:23:24 2008
+++ src/sys/arch/i386/i386/svr4_sigcode.S Sat Apr 4 17:39:09 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: svr4_sigcode.S,v 1.12 2008/04/28 20:23:24 martin Exp $ */
+/* $NetBSD: svr4_sigcode.S,v 1.12.10.1 2009/04/04 17:39:09 snj Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -64,7 +64,7 @@
*/
#include <machine/asm.h>
-__KERNEL_RCSID(0, "$NetBSD: svr4_sigcode.S,v 1.12 2008/04/28 20:23:24 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: svr4_sigcode.S,v 1.12.10.1 2009/04/04 17:39:09 snj Exp $");
#if defined(_KERNEL_OPT)
#include "opt_vm86.h"
@@ -100,6 +100,7 @@
pushl $2 # size of instruction for restart
pushl $T_ASTFLT # trap # for doing ASTs
INTRENTRY
+ STI(%eax)
call _C_LABEL(svr4_fasttrap)
2: /* Check for ASTs on exit to user mode. */
cli
Index: src/sys/arch/i386/i386/vector.S
diff -u src/sys/arch/i386/i386/vector.S:1.42.6.1 src/sys/arch/i386/i386/vector.S:1.42.6.2
--- src/sys/arch/i386/i386/vector.S:1.42.6.1 Fri Mar 27 17:25:15 2009
+++ src/sys/arch/i386/i386/vector.S Sat Apr 4 17:39:09 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: vector.S,v 1.42.6.1 2009/03/27 17:25:15 msaitoh Exp $ */
+/* $NetBSD: vector.S,v 1.42.6.2 2009/04/04 17:39:09 snj Exp $ */
/*
* Copyright 2002 (c) Wasabi Systems, Inc.
@@ -65,7 +65,7 @@
*/
#include <machine/asm.h>
-__KERNEL_RCSID(0, "$NetBSD: vector.S,v 1.42.6.1 2009/03/27 17:25:15 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vector.S,v 1.42.6.2 2009/04/04 17:39:09 snj Exp $");
#include "opt_ddb.h"
#include "opt_multiprocessor.h"
@@ -886,6 +886,7 @@
IDTVEC(trap0e)
pushl $T_PAGEFLT
INTRENTRY
+ STI(%eax)
testb $PGEX_U,TF_ERR(%esp)
jnz calltrap
movl %cr2,%eax
@@ -996,6 +997,7 @@
pushl $0 # dummy error code
pushl $T_ASTFLT
INTRENTRY
+ STI(%eax)
#ifdef DIAGNOSTIC
movl CPUVAR(ILEVEL),%ebx
#endif
@@ -1084,6 +1086,7 @@
/* LINTSTUB: Ignore */
NENTRY(alltraps)
INTRENTRY
+ STI(%eax)
calltrap:
#ifdef DIAGNOSTIC
movl CPUVAR(ILEVEL),%ebx
Index: src/sys/arch/i386/include/pcb.h
diff -u src/sys/arch/i386/include/pcb.h:1.46 src/sys/arch/i386/include/pcb.h:1.46.4.1
--- src/sys/arch/i386/include/pcb.h:1.46 Sun Oct 26 06:57:30 2008
+++ src/sys/arch/i386/include/pcb.h Sat Apr 4 17:39:09 2009
@@ -1,11 +1,11 @@
-/* $NetBSD: pcb.h,v 1.46 2008/10/26 06:57:30 mrg Exp $ */
+/* $NetBSD: pcb.h,v 1.46.4.1 2009/04/04 17:39:09 snj Exp $ */
/*-
- * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by Charles M. Hannum.
+ * by Charles M. Hannum, and by Andrew Doran.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -85,7 +85,7 @@
int pcb_esp0; /* ring0 esp */
int pcb_esp; /* kernel esp */
int pcb_ebp; /* kernel ebp */
- int pcb_ldt_sel;
+ int pcb_unused; /* unused */
int pcb_cr0; /* saved image of CR0 */
int pcb_cr2; /* page fault address (CR2) */
int pcb_cr3; /* page directory pointer */
Index: src/sys/arch/x86/include/pmap.h
diff -u src/sys/arch/x86/include/pmap.h:1.20 src/sys/arch/x86/include/pmap.h:1.20.4.1
--- src/sys/arch/x86/include/pmap.h:1.20 Tue Sep 16 19:55:31 2008
+++ src/sys/arch/x86/include/pmap.h Sat Apr 4 17:39:09 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.h,v 1.20 2008/09/16 19:55:31 bouyer Exp $ */
+/* $NetBSD: pmap.h,v 1.20.4.1 2009/04/04 17:39:09 snj Exp $ */
/*
*
@@ -162,16 +162,13 @@
int pm_flags; /* see below */
union descriptor *pm_ldt; /* user-set LDT */
- int pm_ldt_len; /* number of LDT entries */
+ size_t pm_ldt_len; /* size of LDT in bytes */
int pm_ldt_sel; /* LDT selector */
uint32_t pm_cpus; /* mask of CPUs using pmap */
uint32_t pm_kernel_cpus; /* mask of CPUs using kernel part
of pmap */
};
-/* pm_flags */
-#define PMF_USER_LDT 0x01 /* pmap has user-set LDT */
-
/* macro to access pm_pdirpa */
#ifdef PAE
#define pmap_pdirpa(pmap, index) \
@@ -225,6 +222,7 @@
void pmap_load(void);
paddr_t pmap_init_tmp_pgtbl(paddr_t);
void pmap_remove_all(struct pmap *);
+void pmap_ldt_sync(struct pmap *);
vaddr_t reserve_dumppages(vaddr_t); /* XXX: not a pmap fn */
Index: src/sys/arch/x86/include/sysarch.h
diff -u src/sys/arch/x86/include/sysarch.h:1.7 src/sys/arch/x86/include/sysarch.h:1.7.10.1
--- src/sys/arch/x86/include/sysarch.h:1.7 Mon Apr 28 20:23:40 2008
+++ src/sys/arch/x86/include/sysarch.h Sat Apr 4 17:39:09 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: sysarch.h,v 1.7 2008/04/28 20:23:40 martin Exp $ */
+/* $NetBSD: sysarch.h,v 1.7.10.1 2009/04/04 17:39:09 snj Exp $ */
/*-
* Copyright (c) 2007 The NetBSD Foundation, Inc.
@@ -174,7 +174,6 @@
int x86_iopl(struct lwp *, void *, register_t *);
int x86_get_mtrr(struct lwp *, void *, register_t *);
int x86_set_mtrr(struct lwp *, void *, register_t *);
-int x86_get_ldt_len(struct lwp *l);
int x86_get_ldt(struct lwp *l, void *, register_t *);
int x86_get_ldt1(struct lwp *l, struct x86_get_ldt_args *, union descriptor *);
int x86_set_ldt(struct lwp *l, void *, register_t *);
Index: src/sys/arch/x86/x86/pmap.c
diff -u src/sys/arch/x86/x86/pmap.c:1.74 src/sys/arch/x86/x86/pmap.c:1.74.4.1
--- src/sys/arch/x86/x86/pmap.c:1.74 Sat Oct 25 14:16:35 2008
+++ src/sys/arch/x86/x86/pmap.c Sat Apr 4 17:39:09 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.c,v 1.74 2008/10/25 14:16:35 yamt Exp $ */
+/* $NetBSD: pmap.c,v 1.74.4.1 2009/04/04 17:39:09 snj Exp $ */
/*
* Copyright (c) 2007 Manuel Bouyer.
@@ -154,7 +154,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.74 2008/10/25 14:16:35 yamt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.74.4.1 2009/04/04 17:39:09 snj Exp $");
#include "opt_user_ldt.h"
#include "opt_lockdebug.h"
@@ -174,6 +174,7 @@
#include <sys/atomic.h>
#include <sys/cpu.h>
#include <sys/intr.h>
+#include <sys/xcall.h>
#include <uvm/uvm.h>
@@ -2276,7 +2277,7 @@
pool_cache_put(&pmap_pdp_cache, pmap->pm_pdir);
#ifdef USER_LDT
- if (pmap->pm_flags & PMF_USER_LDT) {
+ if (pmap->pm_ldt != NULL) {
/*
* no need to switch the LDT; this address space is gone,
* nothing is using it.
@@ -2284,9 +2285,11 @@
* No need to lock the pmap for ldt_free (or anything else),
* we're the last one to use it.
*/
+ mutex_enter(&cpu_lock);
ldt_free(pmap->pm_ldt_sel);
+ mutex_exit(&cpu_lock);
uvm_km_free(kernel_map, (vaddr_t)pmap->pm_ldt,
- pmap->pm_ldt_len * sizeof(union descriptor), UVM_KMF_WIRED);
+ pmap->pm_ldt_len, UVM_KMF_WIRED);
}
#endif
@@ -2324,60 +2327,94 @@
size_t len;
int sel;
+ if (__predict_true(pmap1->pm_ldt == NULL)) {
+ return;
+ }
+
retry:
- if (pmap1->pm_flags & PMF_USER_LDT) {
- len = pmap1->pm_ldt_len * sizeof(union descriptor);
- new_ldt = (union descriptor *)uvm_km_alloc(kernel_map,
- len, 0, UVM_KMF_WIRED);
+ if (pmap1->pm_ldt != NULL) {
+ len = pmap1->pm_ldt_len;
+ new_ldt = (union descriptor *)uvm_km_alloc(kernel_map, len, 0,
+ UVM_KMF_WIRED);
+ mutex_enter(&cpu_lock);
sel = ldt_alloc(new_ldt, len);
+ if (sel == -1) {
+ mutex_exit(&cpu_lock);
+ uvm_km_free(kernel_map, (vaddr_t)new_ldt, len,
+ UVM_KMF_WIRED);
+ printf("WARNING: pmap_fork: unable to allocate LDT\n");
+ return;
+ }
} else {
len = -1;
new_ldt = NULL;
sel = -1;
- }
-
- if ((uintptr_t) pmap1 < (uintptr_t) pmap2) {
- mutex_enter(&pmap1->pm_lock);
- mutex_enter(&pmap2->pm_lock);
- } else {
- mutex_enter(&pmap2->pm_lock);
- mutex_enter(&pmap1->pm_lock);
+ mutex_enter(&cpu_lock);
}
/* Copy the LDT, if necessary. */
- if (pmap1->pm_flags & PMF_USER_LDT) {
- if (len != pmap1->pm_ldt_len * sizeof(union descriptor)) {
- mutex_exit(&pmap2->pm_lock);
- mutex_exit(&pmap1->pm_lock);
+ if (pmap1->pm_ldt != NULL) {
+ if (len != pmap1->pm_ldt_len) {
if (len != -1) {
ldt_free(sel);
uvm_km_free(kernel_map, (vaddr_t)new_ldt,
len, UVM_KMF_WIRED);
}
+ mutex_exit(&cpu_lock);
goto retry;
}
memcpy(new_ldt, pmap1->pm_ldt, len);
pmap2->pm_ldt = new_ldt;
pmap2->pm_ldt_len = pmap1->pm_ldt_len;
- pmap2->pm_flags |= PMF_USER_LDT;
pmap2->pm_ldt_sel = sel;
len = -1;
}
- mutex_exit(&pmap2->pm_lock);
- mutex_exit(&pmap1->pm_lock);
-
if (len != -1) {
ldt_free(sel);
uvm_km_free(kernel_map, (vaddr_t)new_ldt, len,
UVM_KMF_WIRED);
}
+ mutex_exit(&cpu_lock);
#endif /* USER_LDT */
}
#endif /* PMAP_FORK */
#ifdef USER_LDT
+
+/*
+ * pmap_ldt_xcall: cross call used by pmap_ldt_sync. if the named pmap
+ * is active, reload LDTR.
+ */
+static void
+pmap_ldt_xcall(void *arg1, void *arg2)
+{
+ struct pmap *pm;
+
+ kpreempt_disable();
+ pm = arg1;
+ if (curcpu()->ci_pmap == pm) {
+ lldt(pm->pm_ldt_sel);
+ }
+ kpreempt_enable();
+}
+
+/*
+ * pmap_ldt_sync: LDT selector for the named pmap is changing. swap
+ * in the new selector on all CPUs.
+ */
+void
+pmap_ldt_sync(struct pmap *pm)
+{
+ uint64_t where;
+
+ KASSERT(mutex_owned(&cpu_lock));
+
+ where = xc_broadcast(0, pmap_ldt_xcall, pm, NULL);
+ xc_wait(where);
+}
+
/*
* pmap_ldt_cleanup: if the pmap has a local LDT, deallocate it, and
* restore the default.
@@ -2386,35 +2423,28 @@
void
pmap_ldt_cleanup(struct lwp *l)
{
- struct pcb *pcb = &l->l_addr->u_pcb;
pmap_t pmap = l->l_proc->p_vmspace->vm_map.pmap;
- union descriptor *old_ldt = NULL;
+ union descriptor *dp = NULL;
size_t len = 0;
int sel = -1;
- mutex_enter(&pmap->pm_lock);
- kpreempt_disable();
+ if (__predict_true(pmap->pm_ldt == NULL)) {
+ return;
+ }
- if (pmap->pm_flags & PMF_USER_LDT) {
+ mutex_enter(&cpu_lock);
+ if (pmap->pm_ldt != NULL) {
sel = pmap->pm_ldt_sel;
+ dp = pmap->pm_ldt;
+ len = pmap->pm_ldt_len;
pmap->pm_ldt_sel = GSYSSEL(GLDT_SEL, SEL_KPL);
- pcb->pcb_ldt_sel = pmap->pm_ldt_sel;
- if (l == curlwp)
- lldt(pcb->pcb_ldt_sel);
- old_ldt = pmap->pm_ldt;
- len = pmap->pm_ldt_len * sizeof(union descriptor);
pmap->pm_ldt = NULL;
pmap->pm_ldt_len = 0;
- pmap->pm_flags &= ~PMF_USER_LDT;
- }
-
- kpreempt_enable();
- mutex_exit(&pmap->pm_lock);
-
- if (sel != -1)
+ pmap_ldt_sync(pmap);
ldt_free(sel);
- if (old_ldt != NULL)
- uvm_km_free(kernel_map, (vaddr_t)old_ldt, len, UVM_KMF_WIRED);
+ uvm_km_free(kernel_map, (vaddr_t)dp, len, UVM_KMF_WIRED);
+ }
+ mutex_exit(&cpu_lock);
}
#endif /* USER_LDT */
@@ -2462,8 +2492,6 @@
}
pcb = &l->l_addr->u_pcb;
- pcb->pcb_ldt_sel = pmap->pm_ldt_sel;
-
ci->ci_want_pmapload = 1;
#if defined(__x86_64__)
@@ -2566,10 +2594,7 @@
pmap = vm_map_pmap(&l->l_proc->p_vmspace->vm_map);
KASSERT(pmap != pmap_kernel());
oldpmap = ci->ci_pmap;
-
pcb = &l->l_addr->u_pcb;
- /* loaded by pmap_activate */
- KASSERT(pcb->pcb_ldt_sel == pmap->pm_ldt_sel);
if (pmap == oldpmap) {
if (!pmap_reactivate(pmap)) {
@@ -2676,11 +2701,11 @@
/* lldt() does pmap_pte_flush() */
#else /* XEN */
#if defined(i386)
- ci->ci_tss.tss_ldt = pcb->pcb_ldt_sel;
+ ci->ci_tss.tss_ldt = pmap->pm_ldt_sel;
ci->ci_tss.tss_cr3 = pcb->pcb_cr3;
#endif
#endif /* XEN */
- lldt(pcb->pcb_ldt_sel);
+ lldt(pmap->pm_ldt_sel);
#ifdef PAE
{
paddr_t l3_pd = xpmap_ptom_masked(pmap_l3paddr);
Index: src/sys/arch/x86/x86/sys_machdep.c
diff -u src/sys/arch/x86/x86/sys_machdep.c:1.15 src/sys/arch/x86/x86/sys_machdep.c:1.15.8.1
--- src/sys/arch/x86/x86/sys_machdep.c:1.15 Sun May 11 16:13:34 2008
+++ src/sys/arch/x86/x86/sys_machdep.c Sat Apr 4 17:39:09 2009
@@ -1,7 +1,7 @@
-/* $NetBSD: sys_machdep.c,v 1.15 2008/05/11 16:13:34 ad Exp $ */
+/* $NetBSD: sys_machdep.c,v 1.15.8.1 2009/04/04 17:39:09 snj Exp $ */
/*-
- * Copyright (c) 1998, 2007 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 2007, 2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sys_machdep.c,v 1.15 2008/05/11 16:13:34 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sys_machdep.c,v 1.15.8.1 2009/04/04 17:39:09 snj Exp $");
#include "opt_compat_netbsd.h"
#include "opt_mtrr.h"
@@ -53,13 +53,12 @@
#include <sys/malloc.h>
#include <sys/kmem.h>
#include <sys/kauth.h>
-
+#include <sys/cpu.h>
#include <sys/mount.h>
#include <sys/syscallargs.h>
#include <uvm/uvm_extern.h>
-#include <machine/cpu.h>
#include <machine/cpufunc.h>
#include <machine/gdt.h>
#include <machine/psl.h>
@@ -112,28 +111,6 @@
#endif
int
-x86_get_ldt_len(struct lwp *l)
-{
-#ifndef USER_LDT
- return -1;
-#else
- pmap_t pmap = l->l_proc->p_vmspace->vm_map.pmap;
- int nldt;
-
- mutex_enter(&pmap->pm_lock);
-
- if (pmap->pm_flags & PMF_USER_LDT) {
- nldt = pmap->pm_ldt_len;
- } else {
- nldt = NLDT;
- }
- mutex_exit(&pmap->pm_lock);
- return nldt;
-#endif
-}
-
-
-int
x86_get_ldt(struct lwp *l, void *args, register_t *retval)
{
#ifndef USER_LDT
@@ -189,10 +166,10 @@
ua->start + ua->num > 8192)
return (EINVAL);
- mutex_enter(&pmap->pm_lock);
+ mutex_enter(&cpu_lock);
- if (pmap->pm_flags & PMF_USER_LDT) {
- nldt = pmap->pm_ldt_len;
+ if (pmap->pm_ldt != NULL) {
+ nldt = pmap->pm_ldt_len / sizeof(*lp);
lp = pmap->pm_ldt;
} else {
nldt = NLDT;
@@ -200,7 +177,7 @@
}
if (ua->start > nldt) {
- mutex_exit(&pmap->pm_lock);
+ mutex_exit(&cpu_lock);
return (EINVAL);
}
@@ -216,7 +193,7 @@
#endif
memcpy(cp, lp, num * sizeof(union descriptor));
- mutex_exit(&pmap->pm_lock);
+ mutex_exit(&cpu_lock);
return 0;
#endif
@@ -259,12 +236,11 @@
#ifndef USER_LDT
return EINVAL;
#else
- int error, i, n, sel, free_sel;
+ int error, i, n, old_sel, new_sel;
struct proc *p = l->l_proc;
- struct pcb *pcb = &l->l_addr->u_pcb;
pmap_t pmap = p->p_vmspace->vm_map.pmap;
- size_t old_len, new_len, ldt_len, free_len;
- union descriptor *old_ldt, *new_ldt, *free_ldt;
+ size_t old_len, new_len;
+ union descriptor *old_ldt, *new_ldt;
error = kauth_authorize_machdep(l->l_cred, KAUTH_MACHDEP_LDT_SET,
NULL, NULL, NULL, NULL);
@@ -337,89 +313,72 @@
}
}
- /* allocate user ldt */
- free_sel = -1;
- new_ldt = NULL;
- new_len = 0;
- free_ldt = NULL;
- free_len = 0;
- mutex_enter(&pmap->pm_lock);
- kpreempt_disable();
- if (pmap->pm_ldt == 0 || (ua->start + ua->num) > pmap->pm_ldt_len) {
- if (pmap->pm_flags & PMF_USER_LDT)
- ldt_len = pmap->pm_ldt_len;
- else
- ldt_len = 512;
- while ((ua->start + ua->num) > ldt_len)
- ldt_len *= 2;
- new_len = ldt_len * sizeof(union descriptor);
-
- mutex_exit(&pmap->pm_lock);
+ /*
+ * Install selected changes. We perform a copy, write, swap dance
+ * here to ensure that all updates happen atomically.
+ */
+
+ /* Allocate a new LDT. */
+ for (;;) {
+ new_len = (ua->start + ua->num) * sizeof(union descriptor);
+ new_len = max(new_len, pmap->pm_ldt_len);
+ new_len = max(new_len, NLDT * sizeof(union descriptor));
+ new_len = round_page(new_len);
new_ldt = (union descriptor *)uvm_km_alloc(kernel_map,
- new_len, 0, UVM_KMF_WIRED);
- memset(new_ldt, 0, new_len);
- sel = ldt_alloc(new_ldt, new_len);
- mutex_enter(&pmap->pm_lock);
-
- if (pmap->pm_ldt != NULL && ldt_len <= pmap->pm_ldt_len) {
- /*
- * Another thread (re)allocated the LDT to
- * sufficient size while we were blocked in
- * uvm_km_alloc. Oh well. The new entries
- * will quite probably not be right, but
- * hey.. not our problem if user applications
- * have race conditions like that.
- */
- goto copy;
+ new_len, 0, UVM_KMF_WIRED | UVM_KMF_ZERO);
+ mutex_enter(&cpu_lock);
+ if (pmap->pm_ldt_len <= new_len) {
+ break;
}
+ mutex_exit(&cpu_lock);
+ uvm_km_free(kernel_map, (vaddr_t)new_ldt, new_len,
+ UVM_KMF_WIRED);
+ }
+ /* Copy existing entries, if any. */
+ if (pmap->pm_ldt != NULL) {
old_ldt = pmap->pm_ldt;
- free_ldt = old_ldt;
- free_len = pmap->pm_ldt_len * sizeof(union descriptor);
-
- if (old_ldt != NULL) {
- old_len = pmap->pm_ldt_len * sizeof(union descriptor);
- } else {
- old_len = NLDT * sizeof(union descriptor);
- old_ldt = ldt;
- }
-
+ old_len = pmap->pm_ldt_len;
+ old_sel = pmap->pm_ldt_sel;
memcpy(new_ldt, old_ldt, old_len);
- memset((char *)new_ldt + old_len, 0, new_len - old_len);
-
- pmap->pm_ldt = new_ldt;
- pmap->pm_ldt_len = ldt_len;
-
- if (pmap->pm_flags & PMF_USER_LDT)
- free_sel = pmap->pm_ldt_sel;
- else {
- pmap->pm_flags |= PMF_USER_LDT;
- free_sel = -1;
- }
- pmap->pm_ldt_sel = sel;
- pcb->pcb_ldt_sel = pmap->pm_ldt_sel;
- if (pcb == curpcb)
- lldt(pcb->pcb_ldt_sel);
- new_ldt = NULL;
- }
-copy:
- /* Now actually replace the descriptors. */
- for (i = 0, n = ua->start; i < ua->num; i++, n++)
- pmap->pm_ldt[n] = descv[i];
+ } else {
+ old_ldt = NULL;
+ old_len = 0;
+ old_sel = -1;
+ memcpy(new_ldt, ldt, NLDT * sizeof(union descriptor));
+ }
- kpreempt_enable();
- mutex_exit(&pmap->pm_lock);
+ /* Apply requested changes. */
+ for (i = 0, n = ua->start; i < ua->num; i++, n++) {
+ new_ldt[n] = descv[i];
+ }
- if (new_ldt != NULL)
+ /* Allocate LDT selector. */
+ new_sel = ldt_alloc(new_ldt, new_len);
+ if (new_sel == -1) {
+ mutex_exit(&cpu_lock);
uvm_km_free(kernel_map, (vaddr_t)new_ldt, new_len,
UVM_KMF_WIRED);
- if (free_sel != -1)
- ldt_free(free_sel);
- if (free_ldt != NULL)
- uvm_km_free(kernel_map, (vaddr_t)free_ldt, free_len,
+ return ENOMEM;
+ }
+
+ /* All changes are now globally visible. Swap in the new LDT. */
+ pmap->pm_ldt = new_ldt;
+ pmap->pm_ldt_len = new_len;
+ pmap->pm_ldt_sel = new_sel;
+
+ /* Switch existing users onto new LDT. */
+ pmap_ldt_sync(pmap);
+
+ /* Free existing LDT (if any). */
+ if (old_ldt != NULL) {
+ ldt_free(old_sel);
+ uvm_km_free(kernel_map, (vaddr_t)old_ldt, old_len,
UVM_KMF_WIRED);
+ }
+ mutex_exit(&cpu_lock);
- return (error);
+ return error;
#endif
}
Index: src/sys/compat/linux/arch/i386/linux_machdep.c
diff -u src/sys/compat/linux/arch/i386/linux_machdep.c:1.141 src/sys/compat/linux/arch/i386/linux_machdep.c:1.141.4.1
--- src/sys/compat/linux/arch/i386/linux_machdep.c:1.141 Sat Oct 25 23:38:28 2008
+++ src/sys/compat/linux/arch/i386/linux_machdep.c Sat Apr 4 17:39:09 2009
@@ -1,11 +1,11 @@
-/* $NetBSD: linux_machdep.c,v 1.141 2008/10/25 23:38:28 christos Exp $ */
+/* $NetBSD: linux_machdep.c,v 1.141.4.1 2009/04/04 17:39:09 snj Exp $ */
/*-
- * Copyright (c) 1995, 2000, 2008 The NetBSD Foundation, Inc.
+ * Copyright (c) 1995, 2000, 2008, 2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by Frank van der Linden.
+ * by Frank van der Linden, and by Andrew Doran.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: linux_machdep.c,v 1.141 2008/10/25 23:38:28 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: linux_machdep.c,v 1.141.4.1 2009/04/04 17:39:09 snj Exp $");
#if defined(_KERNEL_OPT)
#include "opt_vm86.h"
@@ -62,6 +62,7 @@
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/kauth.h>
+#include <sys/kmem.h>
#include <miscfs/specfs/specdev.h>
@@ -553,8 +554,8 @@
{
struct x86_get_ldt_args gl;
int error;
- int num_ldt;
union descriptor *ldt_buf;
+ size_t sz;
/*
* I've checked the linux code - this function is asymetric with
@@ -564,19 +565,11 @@
DPRINTF(("linux_read_ldt!"));
- num_ldt = x86_get_ldt_len(l);
- if (num_ldt <= 0)
- return EINVAL;
-
+ sz = 8192 * sizeof(*ldt_buf);
+ ldt_buf = kmem_zalloc(sz, KM_SLEEP);
gl.start = 0;
gl.desc = NULL;
gl.num = SCARG(uap, bytecount) / sizeof(union descriptor);
-
- if (gl.num > num_ldt)
- gl.num = num_ldt;
-
- ldt_buf = malloc(gl.num * sizeof *ldt, M_TEMP, M_WAITOK);
-
error = x86_get_ldt1(l, &gl, ldt_buf);
/* NB gl.num might have changed */
if (error == 0) {
@@ -584,7 +577,7 @@
error = copyout(ldt_buf, SCARG(uap, ptr),
gl.num * sizeof *ldt_buf);
}
- free(ldt_buf, M_TEMP);
+ kmem_free(ldt_buf, sz);
return error;
}
Index: src/sys/kern/init_main.c
diff -u src/sys/kern/init_main.c:1.371.2.2 src/sys/kern/init_main.c:1.371.2.3
--- src/sys/kern/init_main.c:1.371.2.2 Tue Mar 31 23:23:15 2009
+++ src/sys/kern/init_main.c Sat Apr 4 17:39:10 2009
@@ -1,7 +1,7 @@
-/* $NetBSD: init_main.c,v 1.371.2.2 2009/03/31 23:23:15 snj Exp $ */
+/* $NetBSD: init_main.c,v 1.371.2.3 2009/04/04 17:39:10 snj Exp $ */
/*-
- * Copyright (c) 2008 The NetBSD Foundation, Inc.
+ * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -97,7 +97,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.371.2.2 2009/03/31 23:23:15 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.371.2.3 2009/04/04 17:39:10 snj Exp $");
#include "opt_ddb.h"
#include "opt_ipsec.h"
@@ -294,6 +294,7 @@
kernel_lock_init();
once_init();
+ mutex_init(&cpu_lock, MUTEX_DEFAULT, IPL_NONE);
uvm_init();
@@ -363,7 +364,6 @@
time_init();
/* Initialize the run queues, turnstiles and sleep queues. */
- mutex_init(&cpu_lock, MUTEX_DEFAULT, IPL_NONE);
sched_rqinit();
turnstile_init();
sleeptab_init(&sleeptab);