diff options
author | alc <alc@FreeBSD.org> | 2013-08-31 16:21:13 +0000 |
---|---|---|
committer | alc <alc@FreeBSD.org> | 2013-08-31 16:21:13 +0000 |
commit | fab8eade8310946fb1b2f0159bffd123b3af6c02 (patch) | |
tree | e9f09ad41876f7b3f49e2b465183896a9658c319 | |
parent | 57ee6d3c5d7810dc69862869c1b7055eac730532 (diff) | |
download | FreeBSD-src-fab8eade8310946fb1b2f0159bffd123b3af6c02.zip FreeBSD-src-fab8eade8310946fb1b2f0159bffd123b3af6c02.tar.gz |
Implement pmap_advise().
-rw-r--r-- | sys/mips/mips/pmap.c | 83 |
1 files changed, 82 insertions, 1 deletions
diff --git a/sys/mips/mips/pmap.c b/sys/mips/mips/pmap.c index 90994cc..ebb6935 100644 --- a/sys/mips/mips/pmap.c +++ b/sys/mips/mips/pmap.c @@ -2914,11 +2914,92 @@ pmap_is_prefaultable(pmap_t pmap, vm_offset_t addr) } /* - * This function is advisory. + * Apply the given advice to the specified range of addresses within the + * given pmap. Depending on the advice, clear the referenced and/or + * modified flags in each mapping and set the mapped page's dirty field. */ void pmap_advise(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, int advice) { + pd_entry_t *pde, *pdpe; + pt_entry_t *pte; + vm_offset_t va, va_next; + vm_paddr_t pa; + vm_page_t m; + + if (advice != MADV_DONTNEED && advice != MADV_FREE) + return; + rw_wlock(&pvh_global_lock); + PMAP_LOCK(pmap); + for (; sva < eva; sva = va_next) { + pdpe = pmap_segmap(pmap, sva); +#ifdef __mips_n64 + if (*pdpe == 0) { + va_next = (sva + NBSEG) & ~SEGMASK; + if (va_next < sva) + va_next = eva; + continue; + } +#endif + va_next = (sva + NBPDR) & ~PDRMASK; + if (va_next < sva) + va_next = eva; + + pde = pmap_pdpe_to_pde(pdpe, sva); + if (*pde == NULL) + continue; + + /* + * Limit our scan to either the end of the va represented + * by the current page table page, or to the end of the + * range being write protected. + */ + if (va_next > eva) + va_next = eva; + + va = va_next; + for (pte = pmap_pde_to_pte(pde, sva); sva != va_next; pte++, + sva += PAGE_SIZE) { + if (!pte_test(pte, PTE_MANAGED | PTE_V)) { + if (va != va_next) { + pmap_invalidate_range(pmap, va, sva); + va = va_next; + } + continue; + } + pa = TLBLO_PTE_TO_PA(*pte); + m = PHYS_TO_VM_PAGE(pa); + m->md.pv_flags &= ~PV_TABLE_REF; + if (pte_test(pte, PTE_D)) { + if (advice == MADV_DONTNEED) { + /* + * Future calls to pmap_is_modified() + * can be avoided by making the page + * dirty now. + */ + vm_page_dirty(m); + } else { + pte_clear(pte, PTE_D); + if (va == va_next) + va = sva; + } + } else { + /* + * Unless PTE_D is set, any TLB entries + * mapping "sva" don't allow write access, so + * they needn't be invalidated. + */ + if (va != va_next) { + pmap_invalidate_range(pmap, va, sva); + va = va_next; + } + } + } + if (va != va_next) + pmap_invalidate_range(pmap, va, sva); + } + rw_wunlock(&pvh_global_lock); + PMAP_UNLOCK(pmap); } /* |