Move the TSS selector out of the PCB and put it into mdproc. We

need to access this when we have the proclist locked for reading,
and thus cannot store it in the PCB (which may be swapped out).

As part of this, call pmap_activate() from cpu_switch() to switch
to the new address space, and refresh the PCB's copy of the LDT
selector from the pmap structure (see above paragraph).  We need
to do this for MP support anyhow.

Fixes a "panic: spinlock_switchcheck: CPU 0 has 1 spin locks" via
gdt_compact() reported by Nathan Williams.
This commit is contained in:
thorpej 2000-08-16 04:44:35 +00:00
parent 5a7793edd9
commit b0dc085df7
9 changed files with 48 additions and 53 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: gdt.c,v 1.22 2000/06/29 08:44:51 mrg Exp $ */
/* $NetBSD: gdt.c,v 1.23 2000/08/16 04:44:35 thorpej Exp $ */
/*-
* Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
@ -104,15 +104,13 @@ void
gdt_compact()
{
struct proc *p;
struct pcb *pcb;
pmap_t pmap;
int slot = NGDT, oslot;
proclist_lock_read();
for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
pcb = &p->p_addr->u_pcb;
pmap = p->p_vmspace->vm_map.pmap;
oslot = IDXSEL(pcb->pcb_tss_sel);
oslot = IDXSEL(p->p_md.md_tss_sel);
if (oslot >= gdt_count) {
while (gdt[slot].sd.sd_type != SDT_SYSNULL) {
if (++slot >= gdt_count)
@ -120,7 +118,7 @@ gdt_compact()
}
gdt[slot] = gdt[oslot];
gdt[oslot].gd.gd_type = SDT_SYSNULL;
pcb->pcb_tss_sel = GSEL(slot, SEL_KPL);
p->p_md.md_tss_sel = GSEL(slot, SEL_KPL);
}
simple_lock(&pmap->pm_lock);
oslot = IDXSEL(pmap->pm_ldt_sel);
@ -132,16 +130,10 @@ gdt_compact()
gdt[slot] = gdt[oslot];
gdt[oslot].gd.gd_type = SDT_SYSNULL;
pmap->pm_ldt_sel = GSEL(slot, SEL_KPL);
/* Refresh the PCB. */
pcb->pcb_pmap = pmap;
pcb->pcb_ldt_sel = pmap->pm_ldt_sel;
/*
* XXX We don't need to re-load the LDT on this
* XXX processor, but if this pmap/pcb is in use
* XXX on _another_ processor, we need to notify
* XXX it!
* XXXSMP: if the pmap is in use on other
* processors, they need to reload thier
* LDT!
*/
}
simple_unlock(&pmap->pm_lock);
@ -280,23 +272,24 @@ gdt_put_slot(slot)
}
void
tss_alloc(pcb)
struct pcb *pcb;
tss_alloc(p)
struct proc *p;
{
struct pcb *pcb = &p->p_addr->u_pcb;
int slot;
slot = gdt_get_slot();
setsegment(&gdt[slot].sd, &pcb->pcb_tss, sizeof(struct pcb) - 1,
SDT_SYS386TSS, SEL_KPL, 0, 0);
pcb->pcb_tss_sel = GSEL(slot, SEL_KPL);
p->p_md.md_tss_sel = GSEL(slot, SEL_KPL);
}
void
tss_free(pcb)
struct pcb *pcb;
tss_free(p)
struct proc *p;
{
gdt_put_slot(IDXSEL(pcb->pcb_tss_sel));
gdt_put_slot(IDXSEL(p->p_md.md_tss_sel));
}
void

View File

@ -1,4 +1,4 @@
# $NetBSD: genassym.cf,v 1.20 2000/06/29 08:44:51 mrg Exp $
# $NetBSD: genassym.cf,v 1.21 2000/08/16 04:44:35 thorpej Exp $
#
# Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -134,8 +134,8 @@ define P_FORW offsetof(struct proc, p_forw)
define P_PRIORITY offsetof(struct proc, p_priority)
define P_STAT offsetof(struct proc, p_stat)
define P_WCHAN offsetof(struct proc, p_wchan)
define P_VMSPACE offsetof(struct proc, p_vmspace)
define P_FLAG offsetof(struct proc, p_flag)
define P_MD_TSS_SEL offsetof(struct proc, p_md.md_tss_sel)
define P_SYSTEM P_SYSTEM
@ -153,7 +153,6 @@ define PCB_FS offsetof(struct pcb, pcb_fs)
define PCB_GS offsetof(struct pcb, pcb_gs)
define PCB_CR0 offsetof(struct pcb, pcb_cr0)
define PCB_LDT_SEL offsetof(struct pcb, pcb_ldt_sel)
define PCB_TSS_SEL offsetof(struct pcb, pcb_tss_sel)
define PCB_ONFAULT offsetof(struct pcb, pcb_onfault)
define TF_CS offsetof(struct trapframe, tf_cs)

View File

@ -1,4 +1,4 @@
/* $NetBSD: locore.s,v 1.222 2000/05/31 05:09:16 thorpej Exp $ */
/* $NetBSD: locore.s,v 1.223 2000/08/16 04:44:35 thorpej Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -2009,13 +2009,19 @@ switch_exited:
jnz switch_restored
#endif
/*
* Activate the address space. We're curproc, so %cr3 will
* be reloaded, but we're not yet curpcb, so the LDT won't
* be reloaded, although the PCB copy of the selector will
* be refreshed from the pmap.
*/
pushl %edi
call _C_LABEL(pmap_activate)
addl $4,%esp
/* Load TSS info. */
movl _C_LABEL(gdt),%eax
movl PCB_TSS_SEL(%esi),%edx
/* Switch address space. */
movl PCB_CR3(%esi),%ecx
movl %ecx,%cr3
movl P_MD_TSS_SEL(%edi),%edx
/* Switch TSS. Reset "task busy" flag before */
andl $~0x0200,4(%eax,%edx, 1)
@ -2087,7 +2093,7 @@ ENTRY(switch_exit)
/* Load TSS info. */
movl _C_LABEL(gdt),%eax
movl PCB_TSS_SEL(%esi),%edx
movl P_MD_TSS_SEL(%ebx),%edx
/* Switch address space. */
movl PCB_CR3(%esi),%ecx

View File

@ -1,4 +1,4 @@
/* $NetBSD: machdep.c,v 1.393 2000/08/15 18:21:44 fvdl Exp $ */
/* $NetBSD: machdep.c,v 1.394 2000/08/16 04:44:35 thorpej Exp $ */
/*-
* Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
@ -393,13 +393,13 @@ i386_proc0_tss_ldt_init()
for (x = 0; x < sizeof(pcb->pcb_iomap) / 4; x++)
pcb->pcb_iomap[x] = 0xffffffff;
pcb->pcb_ldt_sel = GSEL(GLDT_SEL, SEL_KPL);
pcb->pcb_ldt_sel = pmap_kernel()->pm_ldt_sel = GSEL(GLDT_SEL, SEL_KPL);
pcb->pcb_cr0 = rcr0();
pcb->pcb_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL);
pcb->pcb_tss.tss_esp0 = (int)proc0.p_addr + USPACE - 16;
tss_alloc(pcb);
tss_alloc(&proc0);
ltr(pcb->pcb_tss_sel);
ltr(proc0.p_md.md_tss_sel);
lldt(pcb->pcb_ldt_sel);
proc0.p_md.md_regs = (struct trapframe *)pcb->pcb_tss.tss_esp0 - 1;

View File

@ -1,4 +1,4 @@
/* $NetBSD: pmap.c,v 1.96 2000/06/29 08:44:53 mrg Exp $ */
/* $NetBSD: pmap.c,v 1.97 2000/08/16 04:44:36 thorpej Exp $ */
/*
*
@ -1948,9 +1948,9 @@ pmap_ldt_cleanup(p)
#endif /* USER_LDT */
/*
* pmap_activate: activate a process' pmap (fill in %cr3 info)
* pmap_activate: activate a process' pmap (fill in %cr3 and LDT info)
*
* => called from cpu_fork()
* => called from cpu_switch()
* => if proc is the curproc, then load it into the MMU
*/

View File

@ -1,4 +1,4 @@
/* $NetBSD: vm_machdep.c,v 1.91 2000/06/29 08:44:54 mrg Exp $ */
/* $NetBSD: vm_machdep.c,v 1.92 2000/08/16 04:44:36 thorpej Exp $ */
/*-
* Copyright (c) 1995 Charles M. Hannum. All rights reserved.
@ -132,19 +132,15 @@ cpu_fork(p1, p2, stack, stacksize, func, arg)
* Preset these so that gdt_compact() doesn't get confused if called
* during the allocations below.
*
* Note: pcb_ldt_sel is handled in the pmap_activate() call below.
* Note: pcb_ldt_sel is handled in the pmap_activate() call when
* we run the new process.
*/
pcb->pcb_tss_sel = GSEL(GNULL_SEL, SEL_KPL);
/*
* Activate the addres space. Note this will refresh pcb_ldt_sel.
*/
pmap_activate(p2);
p2->p_md.md_tss_sel = GSEL(GNULL_SEL, SEL_KPL);
/* Fix up the TSS. */
pcb->pcb_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL);
pcb->pcb_tss.tss_esp0 = (int)p2->p_addr + USPACE - 16;
tss_alloc(pcb);
tss_alloc(p2);
/*
* Copy the trapframe.
@ -219,7 +215,7 @@ cpu_wait(p)
{
/* Nuke the TSS. */
tss_free(&p->p_addr->u_pcb);
tss_free(p);
}
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: gdt.h,v 1.7 1999/05/12 19:28:30 thorpej Exp $ */
/* $NetBSD: gdt.h,v 1.8 2000/08/16 04:44:37 thorpej Exp $ */
/*-
* Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
@ -36,10 +36,11 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
struct proc;
struct pmap;
void gdt_init __P((void));
void tss_alloc __P((struct pcb *));
void tss_free __P((struct pcb *));
void tss_alloc __P((struct proc *));
void tss_free __P((struct proc *));
void ldt_alloc __P((struct pmap *, union descriptor *, size_t));
void ldt_free __P((struct pmap *));

View File

@ -1,4 +1,4 @@
/* $NetBSD: pcb.h,v 1.26 1999/09/12 01:17:07 chs Exp $ */
/* $NetBSD: pcb.h,v 1.27 2000/08/16 04:44:37 thorpej Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -98,7 +98,6 @@ struct pcb {
#define pcb_fs pcb_tss.tss_fs
#define pcb_gs pcb_tss.tss_gs
#define pcb_ldt_sel pcb_tss.tss_ldt
int pcb_tss_sel;
int pcb_cr0; /* saved image of CR0 */
struct save87 pcb_savefpu; /* floating point state for 287/387 */
struct emcsts pcb_saveemc; /* Cyrix EMC state */

View File

@ -1,4 +1,4 @@
/* $NetBSD: proc.h,v 1.10 1995/08/06 05:33:23 mycroft Exp $ */
/* $NetBSD: proc.h,v 1.11 2000/08/16 04:44:37 thorpej Exp $ */
/*
* Copyright (c) 1991 Regents of the University of California.
@ -41,6 +41,7 @@
struct mdproc {
struct trapframe *md_regs; /* registers on current frame */
int md_flags; /* machine-dependent flags */
int md_tss_sel; /* TSS selector */
};
/* md_flags */