On multiprocessor systems, it is possible that a lev1map might be in use

by two processors concurrently.  This means that we cannot modify the
lev1map in use by the processor which wishes to use the PROM.

Fix this by creating a separate lev1map for PROM users.  This lev1map
is a copy of the kernel_lev1map, with the exception of the necessary
PROM mapping.  When a processor wishes to use the PROM, it switches
its PTBR to point at the prom_lev1map, performs the PROM operation,
and switches back to its previous lev1map.

Note that kernels without multiprocessor support use the old method
of modifying the current lev1map.

Also, serialize access to the PROM via a spin lock.
This commit is contained in:
thorpej 1999-02-25 03:43:14 +00:00
parent 1b92119539
commit 07304bd858
2 changed files with 105 additions and 49 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: pmap.c,v 1.81 1999/02/24 19:36:04 thorpej Exp $ */
/* $NetBSD: pmap.c,v 1.82 1999/02/25 03:43:14 thorpej Exp $ */
/*-
* Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
@ -156,7 +156,7 @@
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.81 1999/02/24 19:36:04 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.82 1999/02/25 03:43:14 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -793,26 +793,6 @@ pmap_bootstrap(ptaddr, maxasn, ncpuids)
* Set up level 1 page table
*/
#ifdef _PMAP_MAY_USE_PROM_CONSOLE
{
extern pt_entry_t rom_pte; /* XXX */
extern int prom_mapped; /* XXX */
if (pmap_uses_prom_console()) {
/* XXX save old pte so that we can remap prom if necessary */
rom_pte = *(pt_entry_t *)ptaddr & ~PG_ASM; /* XXX */
}
prom_mapped = 0;
/*
* Actually, this code lies. The prom is still mapped, and will
* remain so until the context switch after alpha_init() returns.
* Printfs using the firmware before then will end up frobbing
* kernel_lev1map unnecessarily, but that's OK.
*/
}
#endif
/* Map all of the level 2 pte pages */
for (i = 0; i < howmany(lev2mapsize, NPTEPG); i++) {
pte = (ALPHA_K0SEG_TO_PHYS(((vaddr_t)lev2map) +
@ -829,6 +809,44 @@ pmap_bootstrap(ptaddr, maxasn, ncpuids)
kernel_lev1map[l1pte_index(VPTBASE)] = pte;
VPT = (pt_entry_t *)VPTBASE;
#ifdef _PMAP_MAY_USE_PROM_CONSOLE
{
#if defined(MULTIPROCESSOR)
extern pt_entry_t *prom_lev1map; /* XXX */
#else
extern pt_entry_t prom_pte; /* XXX */
#endif
extern int prom_mapped; /* XXX */
if (pmap_uses_prom_console()) {
/*
* XXX Save old PTE so we can remap the PROM, if
* XXX necessary.
* XXX
* XXX On MP systems, the processor using the PROM
* XXX actually has to switch to another page table
* XXX so as to avoid stomping on an existing mapping
* XXX which may be shared with another processor.
*/
#if defined(MULTIPROCESSOR)
prom_lev1map = (pt_entry_t *)
pmap_steal_memory(sizeof(pt_entry_t) * NPTEPG, NULL, NULL);
memcpy(prom_lev1map, kernel_lev1map,
sizeof(pt_entry_t) * NPTEPG);
prom_lev1map[0] = *(pt_entry_t *)ptaddr & ~PG_ASM;
#else
prom_pte = *(pt_entry_t *)ptaddr & ~PG_ASM;
#endif
}
prom_mapped = 0;
/*
* Actually, this code lies. The prom is still mapped, and will
* remain so until the context switch after alpha_init() returns.
*/
}
#endif
/*
* Set up level 2 page table.
*/

View File

@ -1,4 +1,4 @@
/* $NetBSD: prom.c,v 1.33 1999/02/24 19:25:56 thorpej Exp $ */
/* $NetBSD: prom.c,v 1.34 1999/02/25 03:43:14 thorpej Exp $ */
/*
* Copyright (c) 1992, 1994, 1995, 1996 Carnegie Mellon University
@ -27,11 +27,14 @@
#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
__KERNEL_RCSID(0, "$NetBSD: prom.c,v 1.33 1999/02/24 19:25:56 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: prom.c,v 1.34 1999/02/25 03:43:14 thorpej Exp $");
#include "opt_multiprocessor.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <vm/vm.h>
#include <sys/lock.h>
#include <sys/proc.h>
#include <sys/user.h>
@ -55,23 +58,35 @@ extern struct prom_vec prom_dispatch_v;
#ifdef _PMAP_MAY_USE_PROM_CONSOLE
int prom_mapped = 1; /* Is PROM still mapped? */
pt_entry_t rom_pte, saved_pte[1]; /* XXX */
static pt_entry_t *rom_lev1map __P((void));
struct simplelock prom_slock;
#if defined(MULTIPROCESSOR)
pt_entry_t *prom_lev1map, *saved_lev1map;
static pt_entry_t *prom_swaplev1map __P((pt_entry_t *));
static pt_entry_t *
rom_lev1map()
prom_swaplev1map(l1map)
pt_entry_t *l1map;
{
struct alpha_pcb *apcb;
extern pt_entry_t *kernel_lev1map;
pt_entry_t *rl1map;
/*
* We may be called before the first context switch
* after alpha_init(), in which case we just need
* to use the kernel kernel_lev1map.
*/
if (curpcb == 0)
return (kernel_lev1map);
apcb = (struct alpha_pcb *)ALPHA_PHYS_TO_K0SEG(curpcb);
rl1map = (pt_entry_t *)ALPHA_PHYS_TO_K0SEG(apcb->apcb_ptbr << PGSHIFT);
apcb->apcb_ptbr = ALPHA_K0SEG_TO_PHYS((vaddr_t)l1map) >> PGSHIFT;
(void) alpha_pal_swpctx(curpcb);
return (rl1map);
}
#else /* ! MULTIPROCESSOR */
pt_entry_t prom_pte, saved_pte[1]; /* XXX */
static pt_entry_t *prom_lev1map __P((void));
static pt_entry_t *
prom_lev1map()
{
struct alpha_pcb *apcb;
/*
* Find the level 1 map that we're currently running on.
@ -80,6 +95,7 @@ rom_lev1map()
return ((pt_entry_t *)ALPHA_PHYS_TO_K0SEG(apcb->apcb_ptbr << PGSHIFT));
}
#endif /* MULTIPROCESSOR */
#endif /* _PMAP_MAY_USE_PROM_CONSOLE */
void
@ -92,6 +108,8 @@ init_prom_interface(rpb)
prom_dispatch_v.routine_arg = c->crb_v_dispatch;
prom_dispatch_v.routine = c->crb_v_dispatch->entry_va;
simple_lock_init(&prom_slock);
}
void
@ -115,21 +133,31 @@ static void prom_cache_sync __P((void));
int
prom_enter()
{
int s = splhigh();
int s;
s = splhigh();
simple_lock(&prom_slock);
#ifdef _PMAP_MAY_USE_PROM_CONSOLE
pt_entry_t *lev1map;
/*
* XXX THIS IS COMPLETELY BROKEN ON MULTIPROCESSOR SYSTEMS!
* If we have not yet switched out of the PROM's context
* (i.e. the first one after alpha_init()), then the PROM
* is still mapped, regardless of the `prom_mapped' setting.
*/
if (!prom_mapped) {
if (prom_mapped == 0 && curpcb != 0) {
if (!pmap_uses_prom_console())
panic("prom_enter");
lev1map = rom_lev1map(); /* XXX */
saved_pte[0] = lev1map[0]; /* XXX */
lev1map[0] = rom_pte; /* XXX */
#if defined(MULTIPROCESSOR)
saved_lev1map = prom_swaplev1map(prom_lev1map);
#else
{
pt_entry_t *lev1map;
lev1map = prom_lev1map(); /* XXX */
saved_pte[0] = lev1map[0]; /* XXX */
lev1map[0] = prom_pte; /* XXX */
}
#endif
prom_cache_sync(); /* XXX */
}
#endif
@ -142,16 +170,26 @@ prom_leave(s)
{
#ifdef _PMAP_MAY_USE_PROM_CONSOLE
pt_entry_t *lev1map;
if (!prom_mapped) {
/*
* See comment above.
*/
if (prom_mapped == 0 && curpcb != 0) {
if (!pmap_uses_prom_console())
panic("prom_leave");
lev1map = rom_lev1map(); /* XXX */
lev1map[0] = saved_pte[0]; /* XXX */
#if defined(MULTIPROCESSOR)
(void) prom_swaplev1map(saved_lev1map);
#else
{
pt_entry_t *lev1map;
lev1map = prom_lev1map(); /* XXX */
lev1map[0] = saved_pte[0]; /* XXX */
}
#endif
prom_cache_sync(); /* XXX */
}
#endif
simple_unlock(&prom_slock);
splx(s);
}