From 38fc9e283dc64f944a5afd6ffeea247e4969131a Mon Sep 17 00:00:00 2001 From: matt Date: Sat, 16 Jun 2001 03:32:48 +0000 Subject: [PATCH] Fix pte_spill to set the index on the proper pvo. Deal with recursion in pmap_syncicache. --- sys/arch/powerpc/mpc6xx/pmap.c | 124 ++++++++++++++++++++++----------- 1 file changed, 85 insertions(+), 39 deletions(-) diff --git a/sys/arch/powerpc/mpc6xx/pmap.c b/sys/arch/powerpc/mpc6xx/pmap.c index f5393de736c4..79f0c43e7956 100644 --- a/sys/arch/powerpc/mpc6xx/pmap.c +++ b/sys/arch/powerpc/mpc6xx/pmap.c @@ -1,4 +1,4 @@ -/* $NetBSD: pmap.c,v 1.11 2001/06/15 22:28:54 matt Exp $ */ +/* $NetBSD: pmap.c,v 1.12 2001/06/16 03:32:48 matt Exp $ */ /*- * Copyright (c) 2001 The NetBSD Foundation, Inc. * All rights reserved. @@ -120,13 +120,17 @@ struct pvo_entry { pmap_t pvo_pmap; /* ptr to owning pmap */ vaddr_t pvo_vaddr; /* VA of entry */ #define PVO_PTEGIDX_MASK 0x0007 /* which PTEG slot */ +#define PVO_PTEGIDX_VALID 0x0008 /* slot is valid */ #define PVO_WIRED 0x0010 /* PVO entry is wired */ #define PVO_MANAGED 0x0020 /* PVO entyy for managed page */ }; #define PVO_VADDR(pvo) ((pvo)->pvo_vaddr & ~ADDR_POFF) #define PVO_PTEGIDX_GET(pvo) ((pvo)->pvo_vaddr & PVO_PTEGIDX_MASK) -#define PVO_PTEGIDX_CLR(pvo) ((void)((pvo)->pvo_vaddr &= ~PVO_PTEGIDX_MASK)) -#define PVO_PTEGIDX_SET(pvo,i) ((void)((pvo)->pvo_vaddr |= (i))) +#define PVO_PTEGIDX_ISSET(pvo) ((pvo)->pvo_vaddr & PVO_PTEGIDX_VALID) +#define PVO_PTEGIDX_CLR(pvo) \ + ((void)((pvo)->pvo_vaddr &= ~(PVO_PTEGIDX_VALID|PVO_PTEGIDX_MASK))) +#define PVO_PTEGIDX_SET(pvo,i) \ + ((void)((pvo)->pvo_vaddr |= (i)|PVO_PTEGIDX_VALID)) struct pvo_head *pmap_pvo_table; /* pvo entries by ptegroup index */ struct pvo_head pmap_pvo_kunmanaged = LIST_HEAD_INITIALIZER(pmap_pvo_kunmanaged); /* list of unmanaged pages */ @@ -184,8 +188,8 @@ STATIC struct pvo_entry *pmap_pvo_find_va(pmap_t, vaddr_t, int *); STATIC volatile pte_t *pmap_pvo_to_pte(const struct pvo_entry *, int); STATIC struct pvo_entry *pmap_rkva_alloc(int); -STATIC void pmap_pa_map(struct pvo_entry *, paddr_t, pte_t *saved_pt); -STATIC void pmap_pa_unmap(struct pvo_entry *, pte_t *saved_pt); +STATIC void pmap_pa_map(struct pvo_entry *, paddr_t, pte_t *, int *); +STATIC void pmap_pa_unmap(struct pvo_entry *, pte_t *, int *); STATIC void tlbia(void); STATIC void pmap_syncicache(paddr_t); @@ -566,7 +570,7 @@ pmap_pte_spill(vaddr_t addr) */ i = pmap_pte_insert(ptegidx, &pvo->pvo_pte); if (i >= 0) { - source_pvo->pvo_vaddr |= i; + PVO_PTEGIDX_SET(pvo, i); pmap_pte_overflow--; return 1; } @@ -849,7 +853,7 @@ pmap_zero_page(paddr_t pa) } else if (pmap_initialized) { if (__predict_false(pmap_pvo_zeropage == NULL)) pmap_pvo_zeropage = pmap_rkva_alloc(VM_PROT_READ|VM_PROT_WRITE); - pmap_pa_map(pmap_pvo_zeropage, pa, NULL); + pmap_pa_map(pmap_pvo_zeropage, pa, NULL, NULL); va = (caddr_t) PVO_VADDR(pmap_pvo_zeropage); } else { panic("pmap_zero_page: can't zero pa %#lx", pa); @@ -864,7 +868,7 @@ pmap_zero_page(paddr_t pa) } #endif if (pa >= SEGMENT_LENGTH) - pmap_pa_unmap(pmap_pvo_zeropage, NULL); + pmap_pa_unmap(pmap_pvo_zeropage, NULL, NULL); } /* @@ -883,15 +887,15 @@ pmap_copy_page(paddr_t src, paddr_t dst) if (__predict_false(pmap_pvo_copypage_dst == NULL)) pmap_pvo_copypage_dst = pmap_rkva_alloc(VM_PROT_READ|VM_PROT_WRITE); - pmap_pa_map(pmap_pvo_copypage_src, src, NULL); - pmap_pa_map(pmap_pvo_copypage_dst, dst, NULL); + pmap_pa_map(pmap_pvo_copypage_src, src, NULL, NULL); + pmap_pa_map(pmap_pvo_copypage_dst, dst, NULL, NULL); memcpy((caddr_t)PVO_VADDR(pmap_pvo_copypage_dst), (caddr_t)PVO_VADDR(pmap_pvo_copypage_src), NBPG); - pmap_pa_unmap(pmap_pvo_copypage_src, NULL); - pmap_pa_unmap(pmap_pvo_copypage_dst, NULL); + pmap_pa_unmap(pmap_pvo_copypage_src, NULL, NULL); + pmap_pa_unmap(pmap_pvo_copypage_dst, NULL, NULL); return; } panic("pmap_copy_page: failed to copy contents of pa %#lx to pa %#lx", src, dst); @@ -929,6 +933,17 @@ pmap_pvo_to_pte(const struct pvo_entry *pvo, int pteidx) pt = &pmap_pteg_table[pteidx >> 3].pt[pteidx & 7]; +#ifdef DIAGNOSTIC + if ((pvo->pvo_pte.pte_hi & PTE_VALID) && !PVO_PTEGIDX_ISSET(pvo)) { + panic("pmap_pvo_to_pte: pvo %p: has valid pte in " + "pvo but valid pte index", pvo); + } + if ((pvo->pvo_pte.pte_hi & PTE_VALID) == 0 && PVO_PTEGIDX_ISSET(pvo)) { + panic("pmap_pvo_to_pte: pvo %p: has valid pte index in " + "pvo but no valid pte", pvo); + } +#endif + if ((pt->pte_hi ^ (pvo->pvo_pte.pte_hi & ~PTE_VALID)) == PTE_VALID) { #ifdef DIAGNOSTIC if ((pvo->pvo_pte.pte_hi & PTE_VALID) == 0) { @@ -990,7 +1005,7 @@ pmap_pvo_find_va(pmap_t pm, vaddr_t va, int *pteidx_p) } void -pmap_pa_map(struct pvo_entry *pvo, paddr_t pa, pte_t *saved_pt) +pmap_pa_map(struct pvo_entry *pvo, paddr_t pa, pte_t *saved_pt, int *depth_p) { int s; @@ -1004,26 +1019,36 @@ pmap_pa_map(struct pvo_entry *pvo, paddr_t pa, pte_t *saved_pt) volatile pte_t *pt; pt = pmap_pvo_to_pte(pvo, -1); if (pt != NULL) { + if (depth_p != NULL && *depth_p == 0) + panic("pmap_pa_map: pvo %p: valid pt %p" + " on 0 depth", pvo, pt); pmap_pte_unset(pt, &pvo->pvo_pte, pvo->pvo_vaddr); - *saved_pt = pvo->pvo_pte; - pvo->pvo_pte.pte_lo &= ~PTE_RPGN; - pvo->pvo_pte.pte_lo |= pa; - pmap_pte_set(pt, &pvo->pvo_pte); - splx(s); - return; + PVO_PTEGIDX_CLR(pvo); + pmap_pte_overflow++; } *saved_pt = pvo->pvo_pte; - } else if (pvo->pvo_pte.pte_hi & PTE_VALID) { + DPRINTFN(3,("pmap_pa_map: saved pte %#x/%#x va %#lx\n", + pvo->pvo_pte.pte_hi, pvo->pvo_pte.pte_lo, + pvo->pvo_vaddr)); + pvo->pvo_pte.pte_lo &= ~PTE_RPGN; + } else if ((pvo->pvo_pte.pte_hi & PTE_VALID) || + (depth_p != NULL && (*depth_p) > 0)) { panic("pmap_pa_map: unprotected recursive use of pvo %p", pvo); } pvo->pvo_pte.pte_lo |= pa; if (!pmap_pte_spill(pvo->pvo_vaddr)) panic("pmap_pa_map: could not spill pvo %p", pvo); + if ((pvo->pvo_pte.pte_hi & PTE_VALID) == 0) + panic("pmap_pa_map: pvo %p: pte not valid after spill", pvo); + if (PVO_PTEGIDX_ISSET(pvo) == 0) + panic("pmap_pa_map: pvo %p: no pte index spill", pvo); + if (depth_p != NULL) + (*depth_p)++; splx(s); } void -pmap_pa_unmap(struct pvo_entry *pvo, pte_t *saved_pt) +pmap_pa_unmap(struct pvo_entry *pvo, pte_t *saved_pt, int *depth_p) { volatile pte_t *pt; int s; @@ -1032,26 +1057,46 @@ pmap_pa_unmap(struct pvo_entry *pvo, pte_t *saved_pt) pt = pmap_pvo_to_pte(pvo, -1); if (pt != NULL) { pmap_pte_unset(pt, &pvo->pvo_pte, pvo->pvo_vaddr); - /* - * If there is a saved PTE and its valid, restore it - * and return. Otherwise clear the entry. - */ - if (saved_pt != NULL && (saved_pt->pte_hi & PTE_VALID)) { - pvo->pvo_pte = *saved_pt; - pmap_pte_set(pt, saved_pt); - } else { - PVO_PTEGIDX_CLR(pvo); - pmap_pte_overflow++; - pvo->pvo_pte.pte_lo &= ~PTE_RPGN; - } + PVO_PTEGIDX_CLR(pvo); + pmap_pte_overflow++; } + pvo->pvo_pte.pte_lo &= ~PTE_RPGN; + + /* + * If there is a saved PTE and its valid, restore it + * and return. + */ + if (saved_pt != NULL && (saved_pt->pte_lo & PTE_RPGN) != 0) { + if (pvo->pvo_pte.pte_hi != saved_pt->pte_hi) + panic("pmap_pa_unmap: pvo %p pte_hi %#x " + "!= saved pte_hi %#x", pvo, pvo->pvo_pte.pte_hi, + saved_pt->pte_hi); + if (depth_p != NULL && --(*depth_p) == 0) + panic("pmap_pa_unmap: restoring but depth == 0"); + pvo->pvo_pte = *saved_pt; + DPRINTFN(3,("pmap_pa_unmap: restored pte %#x/%#x " + "va %#lx\n", pvo->pvo_pte.pte_hi, + pvo->pvo_pte.pte_lo, pvo->pvo_vaddr)); + if (!pmap_pte_spill(pvo->pvo_vaddr)) + panic("pmap_pa_unmap: could not spill pvo %p", pvo); + if ((pvo->pvo_pte.pte_hi & PTE_VALID) == 0) + panic("pmap_pa_unmap: pvo %p: pte not valid after " + "spill", pvo); + } else { + if (depth_p != NULL && --(*depth_p) != 0) + panic("pmap_pa_unmap: reseting but depth (%u) > 0", + *depth_p); + } + splx(s); } void pmap_syncicache(paddr_t pa) { - DPRINTFN(6,("pmap_syncicache: pa %#lx\n", pa)); + static int depth; + static u_int calls; + DPRINTFN(6,("pmap_syncicache[%d]: pa %#lx\n", depth, pa)); if (pa < SEGMENT_LENGTH) { __syncicache((void *)pa, NBPG); return; @@ -1060,9 +1105,10 @@ pmap_syncicache(paddr_t pa) pte_t saved_pte; if (__predict_false(pmap_pvo_syncicache == NULL)) pmap_pvo_syncicache = pmap_rkva_alloc(VM_PROT_READ|VM_PROT_WRITE); - pmap_pa_map(pmap_pvo_syncicache, pa, &saved_pte); + calls++; + pmap_pa_map(pmap_pvo_syncicache, pa, &saved_pte, &depth); __syncicache((void *)PVO_VADDR(pmap_pvo_syncicache), NBPG); - pmap_pa_unmap(pmap_pvo_syncicache, &saved_pte); + pmap_pa_unmap(pmap_pvo_syncicache, &saved_pte, &depth); return; } panic("pmap_syncicache: can't sync the icache @ pa %#lx", pa); @@ -1226,7 +1272,7 @@ pmap_pvo_enter(pmap_t pm, struct pool *pl, struct pvo_head *pvo_head, if (pvo->pvo_pmap == pm && PVO_VADDR(pvo) == va) { #ifdef DEBUG if (((pvo->pvo_pte.pte_lo ^ (pa|pte_lo)) & - (PTE_RPGN|PTE_W|PTE_M|PTE_I|PTE_G|PTE_PP)) == 0 && + ~(PTE_REF|PTE_CHG)) == 0 && va < VM_MIN_KERNEL_ADDRESS) { printf("pmap_pvo_enter: pvo %p: dup %#x/%#lx\n", pvo, pvo->pvo_pte.pte_lo, pte_lo|pa); @@ -1234,7 +1280,7 @@ pmap_pvo_enter(pmap_t pm, struct pool *pl, struct pvo_head *pvo_head, pvo->pvo_pte.pte_hi, pm->pm_sr[va >> ADDR_SR_SHFT]); pmap_pte_print(pmap_pvo_to_pte(pvo, -1)); -#ifdef DDB +#ifdef DDBX Debugger(); #endif } @@ -2126,7 +2172,7 @@ pmap_pvo_verify(void) struct pvo_entry *pvo; LIST_FOREACH(pvo, &pmap_pvo_table[ptegidx], pvo_olink) { if ((uintptr_t) pvo >= SEGMENT_LENGTH) - panic("pmap_pvo_find_va: invalid pvo %p " + panic("pmap_pvo_verify: invalid pvo %p " "on list %#x", pvo, ptegidx); pmap_pvo_check(pvo); }