diff options
Diffstat (limited to 'sys/arch/m68k')
-rw-r--r-- | sys/arch/m68k/m68k/pmap_motorola.c | 146 |
1 files changed, 135 insertions, 11 deletions
diff --git a/sys/arch/m68k/m68k/pmap_motorola.c b/sys/arch/m68k/m68k/pmap_motorola.c index 292dfcb26f5..b4d2433cf01 100644 --- a/sys/arch/m68k/m68k/pmap_motorola.c +++ b/sys/arch/m68k/m68k/pmap_motorola.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pmap_motorola.c,v 1.49 2007/02/17 19:08:58 miod Exp $ */ +/* $OpenBSD: pmap_motorola.c,v 1.50 2007/03/04 16:59:03 miod Exp $ */ /* * Copyright (c) 1999 The NetBSD Foundation, Inc. @@ -308,6 +308,7 @@ void pmap_changebit(struct vm_page *, int, int); int pmap_enter_ptpage(pmap_t, vaddr_t); void pmap_ptpage_addref(vaddr_t); int pmap_ptpage_delref(vaddr_t); +void pmap_collect1(paddr_t, paddr_t); #ifdef PMAP_DEBUG @@ -777,6 +778,7 @@ void pmap_remove_flags(pmap, sva, eva, flags) pmap_t pmap; vaddr_t sva, eva; + int flags; { vaddr_t nssva; pt_entry_t *pte; @@ -1671,16 +1673,138 @@ pmap_collect(pmap) PMAP_DPRINTF(PDB_FOLLOW, ("pmap_collect(%p)\n", pmap)); - /* - * This process is about to be swapped out; free all of - * the PT pages by removing the physical mappings for its - * entire address space. Note: pmap_remove() performs - * all necessary locking. - */ - flags = active_pmap(pmap) ? PRM_TFLUSH : 0; - pmap_remove_flags(pmap, VM_MIN_ADDRESS, VM_MAX_ADDRESS, - flags | PRM_SKIPWIRED); - pmap_update(pmap); + if (pmap == pmap_kernel()) { + int bank, s; + + /* + * XXX This is very bogus. We should handle kernel PT + * XXX pages much differently. + */ + + s = splvm(); + for (bank = 0; bank < vm_nphysseg; bank++) + pmap_collect1(ptoa(vm_physmem[bank].start), + ptoa(vm_physmem[bank].end)); + splx(s); + } else { + /* + * This process is about to be swapped out; free all of + * the PT pages by removing the physical mappings for its + * entire address space. Note: pmap_remove() performs + * all necessary locking. + */ + flags = active_pmap(pmap) ? PRM_TFLUSH : 0; + pmap_remove_flags(pmap, VM_MIN_ADDRESS, VM_MAX_ADDRESS, + flags | PRM_SKIPWIRED); + pmap_update(pmap); + } +} + +/* + * pmap_collect1: + * + * Garbage-collect KPT pages. Helper for the above (bogus) + * pmap_collect(). + * + * Note: THIS SHOULD GO AWAY, AND BE REPLACED WITH A BETTER + * WAY OF HANDLING PT PAGES! + */ +void +pmap_collect1(startpa, endpa) + paddr_t startpa, endpa; +{ + paddr_t pa; + struct pv_entry *pv; + pt_entry_t *pte; + paddr_t kpa; +#ifdef PMAP_DEBUG + st_entry_t *ste; + int opmapdebug = 0 /* XXX initialize to quiet gcc -Wall */; +#endif + + for (pa = startpa; pa < endpa; pa += PAGE_SIZE) { + struct kpt_page *kpt, **pkpt; + + /* + * Locate physical pages which are being used as kernel + * page table pages. + */ + pv = pa_to_pvh(pa); + if (pv->pv_pmap != pmap_kernel() || !(pv->pv_flags & PV_PTPAGE)) + continue; + do { + if (pv->pv_ptste && pv->pv_ptpmap == pmap_kernel()) + break; + } while ((pv = pv->pv_next)); + if (pv == NULL) + continue; +#ifdef PMAP_DEBUG + if (pv->pv_va < (vaddr_t)Sysmap || + pv->pv_va >= (vaddr_t)Sysmap + MACHINE_MAX_PTSIZE) + printf("collect: kernel PT VA out of range\n"); + else + goto ok; + pmap_pvdump(pa); + continue; +ok: +#endif + pte = (pt_entry_t *)(pv->pv_va + PAGE_SIZE); + while (--pte >= (pt_entry_t *)pv->pv_va && *pte == PG_NV) + ; + if (pte >= (pt_entry_t *)pv->pv_va) + continue; + +#ifdef PMAP_DEBUG + if (pmapdebug & (PDB_PTPAGE|PDB_COLLECT)) { + printf("collect: freeing KPT page at %lx (ste %x@%p)\n", + pv->pv_va, *pv->pv_ptste, pv->pv_ptste); + opmapdebug = pmapdebug; + pmapdebug |= PDB_PTPAGE; + } + + ste = pv->pv_ptste; +#endif + /* + * If all entries were invalid we can remove the page. + * We call pmap_remove_entry to take care of invalidating + * ST and Sysptmap entries. + */ + pmap_extract(pmap_kernel(), pv->pv_va, &kpa); + pmap_remove_mapping(pmap_kernel(), pv->pv_va, PT_ENTRY_NULL, + PRM_TFLUSH|PRM_CFLUSH); + /* + * Use the physical address to locate the original + * (kmem_alloc assigned) address for the page and put + * that page back on the free list. + */ + for (pkpt = &kpt_used_list, kpt = *pkpt; + kpt != NULL; + pkpt = &kpt->kpt_next, kpt = *pkpt) + if (kpt->kpt_pa == kpa) + break; +#ifdef PMAP_DEBUG + if (kpt == NULL) + panic("pmap_collect: lost a KPT page"); + if (pmapdebug & (PDB_PTPAGE|PDB_COLLECT)) + printf("collect: %lx (%lx) to free list\n", + kpt->kpt_va, kpa); +#endif + *pkpt = kpt->kpt_next; + kpt->kpt_next = kpt_free_list; + kpt_free_list = kpt; +#ifdef PMAP_DEBUG + if (pmapdebug & (PDB_PTPAGE|PDB_COLLECT)) + pmapdebug = opmapdebug; + + if (*ste & SG_V) + printf("collect: kernel STE at %p still valid (%x)\n", + ste, *ste); + ste = &Sysptmap[ste - pmap_ste(pmap_kernel(), 0)]; + if (*ste & SG_V) + printf("collect: kernel PTmap at %p still valid (%x)\n", + ste, *ste); +#endif + } } /* |