Fix two more bugs. Seems to work now!

This commit is contained in:
gwr 1994-07-12 05:18:53 +00:00
parent ba188a61a0
commit 32ec36897f
1 changed files with 167 additions and 52 deletions

View File

@ -28,7 +28,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: pmap.c,v 1.29 1994/07/11 03:38:11 gwr Exp $
* $Id: pmap.c,v 1.30 1994/07/12 05:18:53 gwr Exp $
*/
#include <sys/param.h>
#include <sys/systm.h>
@ -50,7 +50,7 @@
extern void printf __P((const char *, ...));
#define VA_SEGNUM(x) ((x >> SEGSHIFT) & SEGOFSET)
#define VA_SEGNUM(x) ((u_int)(x) >> SEGSHIFT)
/*
* globals needed by the vm system
@ -294,8 +294,8 @@ void pmeg_steal __P((int pmeg_num));
void pmeg_flush __P((pmeg_t pmegp));
pmeg_t pmeg_allocate_invalid __P((pmap_t pmap, vm_offset_t va));
void pmeg_release __P((pmeg_t pmegp));
void pmeg_release_empty __P((pmeg_t pmegp, int segnum, int update));
pmeg_t pmeg_cache __P((pmap_t pmap, vm_offset_t va, int update));
void pmeg_release_empty __P((pmeg_t pmegp, int segnum));
pmeg_t pmeg_cache __P((pmap_t pmap, vm_offset_t va));
void pmeg_wire __P((pmeg_t pmegp));
void pmeg_unwire __P((pmeg_t pmegp));
void pmeg_init __P((void));
@ -440,7 +440,7 @@ int get_pte_val(pmap, va, ptep)
set_context(saved_context);
} else {
/* we don't have a context */
pmegp = pmeg_cache(pmap, sun3_trunc_seg(va), PM_UPDATE_CACHE);
pmegp = pmeg_cache(pmap, sun3_trunc_seg(va));
if (pmegp) {
*ptep = get_pte_pmeg(pmegp->pmeg_index, VA_PTE_NUM(va));
pmeg_release(pmegp);
@ -474,7 +474,7 @@ void set_pte_val(pmap, va, pte)
set_context(saved_context);
} else {
/* we don't have a context */
pmegp = pmeg_cache(pmap, sun3_trunc_seg(va), PM_UPDATE_CACHE);
pmegp = pmeg_cache(pmap, sun3_trunc_seg(va));
if (!pmegp) panic("pmap: no pmeg to set pte in");
set_pte_pmeg(pmegp->pmeg_index, VA_PTE_NUM(va), pte);
pmeg_release(pmegp);
@ -541,6 +541,8 @@ void context_free(pmap) /* :) */
saved_context = get_context();
context = pmap->pm_context;
set_context(context->context_num);
/* Unload MMU (but keep in SW segmap). */
va = 0;
for (i=0; i < NUSEG; i++) {
if (pmap->pm_segmap[i] != SEGINV) {
@ -559,8 +561,11 @@ void context_free(pmap) /* :) */
set_segmap(va, SEGINV);
pmeg_release(pmeg_p(sme));
}
pmap->pm_segmap[i] = SEGINV;
}
#ifdef DIAGNOSTIC
if (get_segmap(va) != SEGINV)
panic("context_free: did not clean pmap=%x va=%x", pmap, va);
#endif
va += NBSG;
}
set_context(saved_context);
@ -691,38 +696,63 @@ void pmeg_clean_free()
PMEG_UNLK();
}
/*
* Clean out an inactive pmeg in preparation for a new owner.
* (Inactive means referenced in pm_segmap but not hardware.)
*/
void pmeg_flush(pmegp)
pmeg_t pmegp;
{
vm_offset_t pte;
vm_offset_t pte, va;
pmap_t pmap;
int i;
pmap = pmegp->pmeg_owner;
#ifdef DIAGNOSTIC
if (pmap == NULL)
panic("pmeg_flush: no owner, pmeg=0x%x", pmegp);
if (pmap == kernel_pmap)
panic("pmeg_flush: kernel_pmap, pmeg=0x%x", pmegp);
#endif
#if 0
#if 0 /* XXX */
if (!pmegp->pmeg_vpages)
printf("pmap: pmeg_flush() on clean pmeg\n");
#endif
for (i = 0; i < NPAGSEG; i++) {
if (pmegp->pmeg_owner) {
#ifdef PMAP_DEBUG
if (pmegp->pmeg_owner == kernel_pmap)
panic("pmeg_flush: kernel_pmap, pmeg=0x%x", pmegp);
#endif
pte = get_pte_pmeg(pmegp->pmeg_index, i);
if (pte & PG_VALID) {
if (pv_initialized)
save_modified_bits(pte);
pv_unlink(pmegp->pmeg_owner, PG_PA(pte), pmegp->pmeg_va);
pmegp->pmeg_vpages--;
set_pte_pmeg(pmegp->pmeg_index, i, PG_INVAL);
}
}
else {
pmegp->pmeg_vpages = 0;
va = pmegp->pmeg_va;
for (i = 0; i < NPAGSEG; i++, va += NBPG) {
pte = get_pte_pmeg(pmegp->pmeg_index, i);
if (pte & PG_VALID) {
if (pv_initialized)
save_modified_bits(pte);
pv_unlink(pmap, PG_PA(pte), va);
pmegp->pmeg_vpages--;
set_pte_pmeg(pmegp->pmeg_index, i, PG_INVAL);
}
}
if (pmegp->pmeg_vpages != 0)
#ifdef PMAP_DEBUG
if (pmegp->pmeg_vpages != 0) {
printf("pmap: pmeg_flush() didn't result in a clean pmeg\n");
Debugger(); /* XXX */
}
#endif
/* Invalidate owner's software segmap. (XXX - paranoid) */
if (pmap->pm_segmap) {
i = VA_SEGNUM(pmegp->pmeg_va);
#ifdef DIAGNOSTIC
if (i >= NUSEG)
panic("pmeg_flush: bad va, pmeg=%x", pmegp);
#endif
#ifdef PMAP_DEBUG
if (pmap_debug & PMD_SEGMAP) {
printf("pm_segmap: pmap=%x i=%x old=%x new=ff (flsh)\n",
pmap, i, pmap->pm_segmap[i]);
}
#endif
pmap->pm_segmap[i] = SEGINV;
}
pmegp->pmeg_owner = NULL; /* more paranoia */
}
#ifdef PMAP_DEBUG
@ -800,8 +830,12 @@ pmeg_t pmeg_allocate_invalid(pmap, va)
Debugger();
}
#endif
#ifdef DIAGNOSTIC
if (pmegp->pmeg_index == SEGINV)
panic("pmeg_alloc_inv: pmeg_index=ff");
if (pmegp->pmeg_vpages)
panic("pmeg_alloc_inv: vpages!=0, pmegp=%x", pmegp);
#endif
pmegp->pmeg_owner = pmap;
pmegp->pmeg_owner_version = pmap->pm_version;
@ -815,6 +849,14 @@ pmeg_t pmeg_allocate_invalid(pmap, va)
} else {
TAILQ_INSERT_TAIL(&pmeg_active_queue, pmegp, pmeg_link);
pmegp->pmeg_qstate = PMEGQ_ACTIVE;
#ifdef PMAP_DEBUG
if (pmap_debug & PMD_SEGMAP) {
printf("pm_segmap: pmap=%x i=%x old=%x new=%x (ainv)\n",
pmap, VA_SEGNUM(va),
pmap->pm_segmap[VA_SEGNUM(va)],
pmegp->pmeg_index);
}
#endif
pmap->pm_segmap[VA_SEGNUM(va)] = pmegp->pmeg_index;
}
/* XXX - Make sure pmeg is clean (in caller). */
@ -853,10 +895,9 @@ void pmeg_release(pmegp)
* Put pmeg on the free queue.
* The pmeg might be in kernel_pmap
*/
void pmeg_release_empty(pmegp, segnum, update)
void pmeg_release_empty(pmegp, segnum)
pmeg_t pmegp;
int segnum;
int update;
{
#ifdef PMAP_DEBUG
/* XXX - Caller should verify that it's empty. */
@ -874,7 +915,6 @@ void pmeg_release_empty(pmegp, segnum, update)
break;
case PMEGQ_KERNEL:
TAILQ_REMOVE(&pmeg_kernel_queue, pmegp, pmeg_link);
update = 0;
break;
default:
panic("pmeg_release_empty: releasing bad pmeg");
@ -888,21 +928,39 @@ void pmeg_release_empty(pmegp, segnum, update)
Debugger();
}
#endif
pmegp->pmeg_qstate = PMEGQ_NONE;
if (pmegp->pmeg_owner->pm_segmap) {
#ifdef PMAP_DEBUG
if (pmap_debug & PMD_SEGMAP) {
printf("pm_segmap: pmap=%x i=%x old=%x new=ff (rele)\n",
pmegp->pmeg_owner, segnum,
pmegp->pmeg_owner->pm_segmap[segnum]);
}
#endif
pmegp->pmeg_owner->pm_segmap[segnum] = SEGINV;
}
#ifdef PMAP_DEBUG
else {
if (pmegp->pmeg_owner != kernel_pmap) {
printf("pmeg_release_empty: null segmap\n");
Debugger();
}
}
#endif
pmegp->pmeg_owner = NULL; /* XXX - paranoia */
TAILQ_INSERT_TAIL(&pmeg_free_queue, pmegp, pmeg_link);
pmegp->pmeg_qstate = PMEGQ_FREE;
if (update)
pmegp->pmeg_owner->pm_segmap[segnum] = SEGINV;
PMEG_UNLK();
}
pmeg_t pmeg_cache(pmap, va, update)
pmeg_t pmeg_cache(pmap, va)
pmap_t pmap;
vm_offset_t va;
int update;
{
unsigned char seg;
int segnum;
pmeg_t pmegp;
#ifdef PMAP_DEBUG
@ -912,13 +970,13 @@ pmeg_t pmeg_cache(pmap, va, update)
if (pmap->pm_segmap == NULL)
return PMEG_NULL;
seg = VA_SEGNUM(va);
if (seg > NUSEG) /* out of range */
segnum = VA_SEGNUM(va);
if (segnum > NUSEG) /* out of range */
return PMEG_NULL;
if (pmap->pm_segmap[seg] == SEGINV) /* nothing cached */
if (pmap->pm_segmap[segnum] == SEGINV) /* nothing cached */
return PMEG_NULL;
pmegp = pmeg_p(pmap->pm_segmap[seg]);
pmegp = pmeg_p(pmap->pm_segmap[segnum]);
#ifdef PMAP_DEBUG
if (pmegp->pmeg_index == pmap_db_watchpmeg) {
@ -930,9 +988,25 @@ pmeg_t pmeg_cache(pmap, va, update)
/* Found a valid pmeg, make sure it's still ours. */
if ((pmegp->pmeg_owner != pmap) ||
(pmegp->pmeg_owner_version != pmap->pm_version) ||
(pmegp->pmeg_va != va)) {
if (update)
pmap->pm_segmap[seg] = SEGINV;
(pmegp->pmeg_va != va))
{
#ifdef PMAP_DEBUG
if (pmap_debug & PMD_SEGMAP) {
printf("pm_segmap: pmap=%x i=%x old=%x new=ff (cach)\n",
pmap, segnum, pmap->pm_segmap[segnum]);
}
/* XXX - Make sure it's not in the MMU? */
if (pmap->pm_context) {
int c, sme;
c = get_context();
set_context(pmap->pm_context->context_num);
sme = get_segmap(va);
set_context(c);
if (sme != SEGINV)
panic("pmeg_cache: about to orphan pmeg");
}
#endif
pmap->pm_segmap[segnum] = SEGINV;
return PMEG_NULL; /* cache lookup failed */
}
@ -1578,10 +1652,15 @@ void pmap_remove_range_mmu(pmap, sva, eva)
sme = get_segmap(sva);
if (sme != SEGINV) {
pmegp = pmeg_p(sme);
#ifdef DIAGNOSTIC
/* Make sure it is in our software segmap (cache). */
if (pmap->pm_segmap && (pmap->pm_segmap[VA_SEGNUM(sva)] != sme))
panic("pmap_remove_range_mmu: MMU has bad pmeg %x", sme);
#endif
} else {
if (pmap == kernel_pmap)
return;
pmegp = pmeg_cache(pmap, sun3_trunc_seg(sva), PM_UPDATE_CACHE);
pmegp = pmeg_cache(pmap, sun3_trunc_seg(sva));
if (!pmegp)
goto outta_here;
#ifdef PMAP_DEBUG
@ -1635,11 +1714,12 @@ void pmap_remove_range_mmu(pmap, sva, eva)
}
}
if (pmegp->pmeg_vpages <= 0) {
/* We are done with this pmeg. */
if (is_pmeg_wired(pmegp)) {
printf("pmap: removing wired pmeg: 0x%x\n", pmegp);
Debugger(); /* XXX */
}
pmeg_release_empty(pmegp, VA_SEGNUM(sva), PM_UPDATE_CACHE);
/* First, remove it from the MMU. */
if (kernel_pmap == pmap) {
for (i=0; i < NCONTEXT; i++) { /* map out of all segments */
set_context(i);
@ -1655,6 +1735,8 @@ void pmap_remove_range_mmu(pmap, sva, eva)
#endif
set_segmap(sva, SEGINV);
}
/* Now, put it on the free list. */
pmeg_release_empty(pmegp, VA_SEGNUM(sva));
}
outta_here:
set_context(saved_context);
@ -1694,7 +1776,7 @@ void pmap_remove_range_contextless(pmap, sva, eva, pmegp)
if (pmegp->pmeg_vpages <= 0) {
if (is_pmeg_wired(pmegp))
panic("pmap: removing wired");
pmeg_release_empty(pmegp,VA_SEGNUM(sva), PM_UPDATE_CACHE);
pmeg_release_empty(pmegp, VA_SEGNUM(sva));
}
else pmeg_release(pmegp);
}
@ -1729,8 +1811,21 @@ void pmap_remove_range(pmap, sva, eva)
#endif
return;
}
if (get_pmeg_cache(pmap, VA_SEGNUM(sva)) == SEGINV)
if (get_pmeg_cache(pmap, VA_SEGNUM(sva)) == SEGINV) {
#ifdef PMAP_DEBUG
/* XXX - Make sure it's not in the MMU? */
if (pmap->pm_context) {
int c, sme;
c = get_context();
set_context(pmap->pm_context->context_num);
sme = get_segmap(sva);
set_context(c);
if (sme != SEGINV)
panic("pmap_remove_range: not in cache");
}
#endif
return;
}
}
if ((pmap == kernel_pmap) || (pmap->pm_context)) {
@ -1741,7 +1836,7 @@ void pmap_remove_range(pmap, sva, eva)
* operate upon
*
*/
pmegp = pmeg_cache(pmap, sun3_trunc_seg(sva),PM_UPDATE_CACHE);
pmegp = pmeg_cache(pmap, sun3_trunc_seg(sva));
if (!pmegp) return;
pmap_remove_range_contextless(pmap, sva, eva, pmegp);
}
@ -1846,6 +1941,11 @@ void pmap_enter_kernel(va, pa, prot, wired, pte_proto, mem_type)
else {
/* Found an existing pmeg. Modify it... */
pmegp = pmeg_p(sme);
#ifdef DIAGNOSTIC
/* Make sure it is ours. */
if (pmegp->pmeg_owner && (pmegp->pmeg_owner != kernel_pmap))
panic("pmap_enter_kernel: MMU has bad pmeg %x", sme);
#endif
/* Don't try to unlink if in DVMA map. */
if (va >= VM_MAX_KERNEL_ADDRESS)
goto add_pte;
@ -1914,10 +2014,12 @@ void pmap_enter_user(pmap, va, pa, prot, wired, pte_proto, mem_type)
if ((va+NBPG) > VM_MAXUSER_ADDRESS)
panic("pmap: user trying to allocate virtual space above itself\n");
if (wired) {
#ifdef PMAP_DEBUG
if ((pmap_debug & PMD_ENTER) && wired) {
printf("pmap_enter_user: attempt to wire user page, ignored\n");
printf("pmap=0x%x va=0x%x pa=0x%x\n", pmap, va, pa);
}
#endif
pte_proto |= MAKE_PGTYPE(PG_MMEM); /* unnecessary */
PMAP_LOCK();
@ -1937,8 +2039,14 @@ void pmap_enter_user(pmap, va, pa, prot, wired, pte_proto, mem_type)
if (sme != SEGINV) {
/* Found an existing pmeg. */
pmegp = pmeg_p(sme);
#ifdef DIAGNOSTIC
/* Make sure it is in our software segmap (cache). */
/* XXX - We are hitting this one! -gwr */
if (pmap->pm_segmap[VA_SEGNUM(va)] != sme)
panic("pmap_enter_user: MMU has bad pmeg %x", sme);
#endif
} else {
pmegp = pmeg_cache(pmap, sun3_trunc_seg(va), PM_UPDATE_CACHE);
pmegp = pmeg_cache(pmap, sun3_trunc_seg(va));
if (pmegp) {
/* found cached pmeg - just reinstall in segmap */
#ifdef PMAP_DEBUG
@ -1962,6 +2070,8 @@ void pmap_enter_user(pmap, va, pa, prot, wired, pte_proto, mem_type)
set_segmap(va, pmegp->pmeg_index);
#ifdef PMAP_DEBUG
pmeg_verify_empty(sun3_trunc_seg(va));
if (pmap->pm_segmap[VA_SEGNUM(va)] != pmegp->pmeg_index)
panic("pmap_enter_user: pmeg_alloc_inv broken?");
#endif
}
}
@ -2375,10 +2485,15 @@ void pmap_protect_range_mmu(pmap, sva, eva, pte_proto)
sme = get_segmap(sva);
if (sme != SEGINV) {
pmegp = pmeg_p(sme);
#ifdef DIAGNOSTIC
/* Make sure it is in our software segmap (cache). */
if (pmap->pm_segmap[VA_SEGNUM(sva)] != sme)
panic("pmap_protect_range_mmu: MMU has bad pmeg %x", sme);
#endif
} else {
if (pmap == kernel_pmap)
return;
pmegp = pmeg_cache(pmap, VA_SEGNUM(sva), PM_UPDATE_CACHE);
pmegp = pmeg_cache(pmap, sun3_trunc_seg(sva));
if (!pmegp)
goto out;
#ifdef PMAP_DEBUG
@ -2437,7 +2552,7 @@ void pmap_protect_range(pmap, sva, eva, pte_proto)
if ((pmap == kernel_pmap) || (pmap->pm_context))
pmap_protect_range_mmu(pmap, sva, eva,pte_proto);
else {
pmegp = pmeg_cache(pmap, sun3_trunc_seg(sva), PM_UPDATE_CACHE);
pmegp = pmeg_cache(pmap, sun3_trunc_seg(sva));
if (!pmegp) return;
pmap_protect_range_contextless(pmap, sva, eva, pte_proto, pmegp);
}