Module Name: src Committed By: matt Date: Mon Jul 11 16:06:09 UTC 2016
Modified Files: src/sys/uvm/pmap: pmap.c pmap.h pmap_segtab.c pmap_synci.c pmap_tlb.c pmap_tlb.h tlb.h vmpagemd.h Added Files: src/sys/uvm/pmap: pmap_synci.h Log Message: Changes so that MIPS can use the common pmap. Change/augment the virtual cache alias callbacks. To generate a diff of this commit: cvs rdiff -u -r1.14 -r1.15 src/sys/uvm/pmap/pmap.c cvs rdiff -u -r1.6 -r1.7 src/sys/uvm/pmap/pmap.h cvs rdiff -u -r1.2 -r1.3 src/sys/uvm/pmap/pmap_segtab.c \ src/sys/uvm/pmap/pmap_synci.c src/sys/uvm/pmap/tlb.h \ src/sys/uvm/pmap/vmpagemd.h cvs rdiff -u -r0 -r1.1 src/sys/uvm/pmap/pmap_synci.h cvs rdiff -u -r1.12 -r1.13 src/sys/uvm/pmap/pmap_tlb.c cvs rdiff -u -r1.8 -r1.9 src/sys/uvm/pmap/pmap_tlb.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/uvm/pmap/pmap.c diff -u src/sys/uvm/pmap/pmap.c:1.14 src/sys/uvm/pmap/pmap.c:1.15 --- src/sys/uvm/pmap/pmap.c:1.14 Thu Jul 7 06:55:44 2016 +++ src/sys/uvm/pmap/pmap.c Mon Jul 11 16:06:09 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: pmap.c,v 1.14 2016/07/07 06:55:44 msaitoh Exp $ */ +/* $NetBSD: pmap.c,v 1.15 2016/07/11 16:06:09 matt Exp $ */ /*- * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc. @@ -67,7 +67,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.14 2016/07/07 06:55:44 msaitoh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.15 2016/07/11 16:06:09 matt Exp $"); /* * Manages physical address maps. @@ -102,22 +102,22 @@ __KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.1 #define __PMAP_PRIVATE #include <sys/param.h> -#include <sys/systm.h> -#include <sys/proc.h> +#include <sys/atomic.h> #include <sys/buf.h> +#include <sys/cpu.h> +#include <sys/mutex.h> #include <sys/pool.h> #include <sys/atomic.h> #include <sys/mutex.h> #include <sys/atomic.h> -#include <sys/socketvar.h> /* XXX: for sock_loan_thresh */ #include <uvm/uvm.h> -#define PMAP_COUNT(name) (pmap_evcnt_##name.ev_count++ + 0) -#define PMAP_COUNTER(name, desc) \ -static struct evcnt pmap_evcnt_##name = \ - EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "pmap", desc); \ -EVCNT_ATTACH_STATIC(pmap_evcnt_##name) +#if defined(MULTIPROCESSOR) && defined(PMAP_VIRTUAL_CACHE_ALIASES) \ + && !defined(PMAP_NO_PV_UNCACHED) +#error PMAP_VIRTUAL_CACHE_ALIASES with MULTIPROCESSOR requires \ + PMAP_NO_PV_UNCACHED to be defined +#endif PMAP_COUNTER(remove_kernel_calls, "remove kernel calls"); PMAP_COUNTER(remove_kernel_pages, "kernel pages unmapped"); @@ -132,8 +132,6 @@ PMAP_COUNTER(prefer_requests, "prefer re PMAP_COUNTER(prefer_adjustments, "prefer adjustments"); PMAP_COUNTER(idlezeroed_pages, "pages idle zeroed"); -PMAP_COUNTER(zeroed_pages, "pages zeroed"); -PMAP_COUNTER(copied_pages, "pages copied"); PMAP_COUNTER(kenter_pa, "kernel fast mapped pages"); PMAP_COUNTER(kenter_pa_bad, "kernel fast mapped pages (bad color)"); @@ -190,20 +188,22 @@ PMAP_COUNTER(page_protect, "page_protect #define PMAP_ASID_RESERVED 0 CTASSERT(PMAP_ASID_RESERVED == 0); -/* - * Initialize the kernel pmap. - */ -#ifdef MULTIPROCESSOR -#define PMAP_SIZE offsetof(struct pmap, pm_pai[PMAP_TLB_MAX]) -#else -#define PMAP_SIZE sizeof(struct pmap) -kmutex_t pmap_pvlist_mutex __aligned(COHERENCY_UNIT); +#ifndef PMAP_SEGTAB_ALIGN +#define PMAP_SEGTAB_ALIGN /* nothing */ +#endif +#ifdef _LP64 +pmap_segtab_t pmap_kstart_segtab PMAP_SEGTAB_ALIGN; /* first mid-level segtab for kernel */ +#endif +pmap_segtab_t pmap_kern_segtab PMAP_SEGTAB_ALIGN = { /* top level segtab for kernel */ +#ifdef _LP64 + .seg_seg[(VM_MIN_KERNEL_ADDRESS & XSEGOFSET) >> SEGSHIFT] = &pmap_kstart_segtab, #endif +}; struct pmap_kernel kernel_pmap_store = { .kernel_pmap = { .pm_count = 1, - .pm_segtab = PMAP_INVALID_SEGTAB_ADDRESS, + .pm_segtab = &pmap_kern_segtab, .pm_minaddr = VM_MIN_KERNEL_ADDRESS, .pm_maxaddr = VM_MAX_KERNEL_ADDRESS, }, @@ -211,7 +211,7 @@ struct pmap_kernel kernel_pmap_store = { struct pmap * const kernel_pmap_ptr = &kernel_pmap_store.kernel_pmap; -struct pmap_limits pmap_limits = { +struct pmap_limits pmap_limits = { /* VA and PA limits */ .virtual_start = VM_MIN_KERNEL_ADDRESS, }; @@ -231,23 +231,24 @@ struct pool pmap_pv_pool; #ifndef PMAP_PV_LOWAT #define PMAP_PV_LOWAT 16 #endif -int pmap_pv_lowat = PMAP_PV_LOWAT; +int pmap_pv_lowat = PMAP_PV_LOWAT; -bool pmap_initialized = false; +bool pmap_initialized = false; #define PMAP_PAGE_COLOROK_P(a, b) \ ((((int)(a) ^ (int)(b)) & pmap_page_colormask) == 0) -u_int pmap_page_colormask; +u_int pmap_page_colormask; -#define PAGE_IS_MANAGED(pa) \ - (pmap_initialized == true && vm_physseg_find(atop(pa), NULL) != -1) +#define PAGE_IS_MANAGED(pa) (pmap_initialized && uvm_pageismanaged(pa)) #define PMAP_IS_ACTIVE(pm) \ ((pm) == pmap_kernel() || \ (pm) == curlwp->l_proc->p_vmspace->vm_map.pmap) /* Forward function declarations */ +void pmap_page_remove(struct vm_page *); +static void pmap_pvlist_check(struct vm_page_md *); void pmap_remove_pv(pmap_t, vaddr_t, struct vm_page *, bool); -void pmap_enter_pv(pmap_t, vaddr_t, struct vm_page *, u_int *); +void pmap_enter_pv(pmap_t, vaddr_t, struct vm_page *, pt_entry_t *, u_int); /* * PV table management functions. @@ -265,7 +266,50 @@ struct pool_allocator pmap_pv_page_alloc #if !defined(MULTIPROCESSOR) || !defined(PMAP_MD_NEED_TLB_MISS_LOCK) #define pmap_md_tlb_miss_lock_enter() do { } while(/*CONSTCOND*/0) #define pmap_md_tlb_miss_lock_exit() do { } while(/*CONSTCOND*/0) -#endif /* !MULTIPROCESSOR || !PMAP_MD_NEED_TLB_MISS_LOCK */ +#endif /* !MULTIPROCESSOR || !PMAP_MD_NEED_TLB_MISS_LOCK */ + +#ifndef MULTIPROCESSOR +kmutex_t pmap_pvlist_mutex __cacheline_aligned; +#endif + +/* + * Debug functions. + */ + +static inline void +pmap_asid_check(pmap_t pm, const char *func) +{ +#ifdef DEBUG + if (!PMAP_IS_ACTIVE(pm)) + return; + + struct pmap_asid_info * const pai = PMAP_PAI(pm, cpu_tlb_info(curcpu())); + tlb_asid_t asid = tlb_get_asid(); + if (asid != pai->pai_asid) + panic("%s: inconsistency for active TLB update: %u <-> %u", + func, asid, pai->pai_asid); +#endif +} + +static void +pmap_addr_range_check(pmap_t pmap, vaddr_t sva, vaddr_t eva, const char *func) +{ +#ifdef DEBUG + if (pmap == pmap_kernel()) { + if (sva < VM_MIN_KERNEL_ADDRESS) + panic("%s: kva %#"PRIxVADDR" not in range", + func, sva); + if (eva >= pmap_limits.virtual_end) + panic("%s: kva %#"PRIxVADDR" not in range", + func, eva); + } else { + if (eva > VM_MAXUSER_ADDRESS) + panic("%s: uva %#"PRIxVADDR" not in range", + func, eva); + pmap_asid_check(pmap, func); + } +#endif +} /* * Misc. functions. @@ -274,18 +318,18 @@ struct pool_allocator pmap_pv_page_alloc bool pmap_page_clear_attributes(struct vm_page_md *mdpg, u_int clear_attributes) { - volatile u_int * const attrp = &mdpg->mdpg_attrs; + volatile unsigned long * const attrp = &mdpg->mdpg_attrs; #ifdef MULTIPROCESSOR for (;;) { u_int old_attr = *attrp; if ((old_attr & clear_attributes) == 0) return false; u_int new_attr = old_attr & ~clear_attributes; - if (old_attr == atomic_cas_uint(attrp, old_attr, new_attr)) + if (old_attr == atomic_cas_ulong(attrp, old_attr, new_attr)) return true; } #else - u_int old_attr = *attrp; + unsigned long old_attr = *attrp; if ((old_attr & clear_attributes) == 0) return false; *attrp &= ~clear_attributes; @@ -297,7 +341,7 @@ void pmap_page_set_attributes(struct vm_page_md *mdpg, u_int set_attributes) { #ifdef MULTIPROCESSOR - atomic_or_uint(&mdpg->mdpg_attrs, set_attributes); + atomic_or_ulong(&mdpg->mdpg_attrs, set_attributes); #else mdpg->mdpg_attrs |= set_attributes; #endif @@ -307,17 +351,19 @@ static void pmap_page_syncicache(struct vm_page *pg) { #ifndef MULTIPROCESSOR - struct pmap * const curpmap = curcpu()->ci_curpm; + struct pmap * const curpmap = curlwp->l_proc->p_vmspace->vm_map.pmap; #endif struct vm_page_md * const mdpg = VM_PAGE_TO_MD(pg); pv_entry_t pv = &mdpg->mdpg_first; kcpuset_t *onproc; #ifdef MULTIPROCESSOR kcpuset_create(&onproc, true); + KASSERT(onproc != NULL); #else onproc = NULL; #endif - (void)VM_PAGEMD_PVLIST_LOCK(mdpg, false); + VM_PAGEMD_PVLIST_READLOCK(mdpg); + pmap_pvlist_check(mdpg); if (pv->pv_pmap != NULL) { for (; pv != NULL; pv = pv->pv_next) { @@ -334,13 +380,14 @@ pmap_page_syncicache(struct vm_page *pg) #endif } } + pmap_pvlist_check(mdpg); VM_PAGEMD_PVLIST_UNLOCK(mdpg); kpreempt_disable(); pmap_md_page_syncicache(pg, onproc); + kpreempt_enable(); #ifdef MULTIPROCESSOR kcpuset_destroy(onproc); #endif - kpreempt_enable(); } /* @@ -402,24 +449,58 @@ pmap_growkernel(vaddr_t maxkvaddr) vaddr_t pmap_steal_memory(vsize_t size, vaddr_t *vstartp, vaddr_t *vendp) { - u_int npgs; + size_t npgs; paddr_t pa; vaddr_t va; + struct vm_physseg *maybe_seg = NULL; + u_int maybe_bank = vm_nphysseg; size = round_page(size); npgs = atop(size); + aprint_debug("%s: need %zu pages\n", __func__, npgs); + for (u_int bank = 0; bank < vm_nphysseg; bank++) { struct vm_physseg * const seg = VM_PHYSMEM_PTR(bank); if (uvm.page_init_done == true) panic("pmap_steal_memory: called _after_ bootstrap"); - if (seg->avail_start != seg->start || - seg->avail_start >= seg->avail_end) + aprint_debug("%s: seg %u: %#"PRIxPADDR" %#"PRIxPADDR" %#"PRIxPADDR" %#"PRIxPADDR"\n", + __func__, bank, + seg->avail_start, seg->start, + seg->avail_end, seg->end); + + if (seg->avail_start != seg->start + || seg->avail_start >= seg->avail_end) { + aprint_debug("%s: seg %u: bad start\n", __func__, bank); continue; + } - if ((seg->avail_end - seg->avail_start) < npgs) + if (seg->avail_end - seg->avail_start < npgs) { + aprint_debug("%s: seg %u: too small for %zu pages\n", + __func__, bank, npgs); continue; + } + + if (!pmap_md_ok_to_steal_p(seg, npgs)) { + continue; + } + + /* + * Always try to allocate from the segment with the least + * amount of space left. + */ +#define VM_PHYSMEM_SPACE(s) ((s)->avail_end - (s)->avail_start) + if (maybe_seg == NULL + || VM_PHYSMEM_SPACE(seg) < VM_PHYSMEM_SPACE(maybe_seg)) { + maybe_seg = seg; + maybe_bank = bank; + } + } + + if (maybe_seg) { + struct vm_physseg * const seg = maybe_seg; + u_int bank = maybe_bank; /* * There are enough pages here; steal them! @@ -435,11 +516,17 @@ pmap_steal_memory(vsize_t size, vaddr_t if (vm_nphysseg == 1) panic("pmap_steal_memory: out of memory!"); + aprint_debug("%s: seg %u: %zu pages stolen (removed)\n", + __func__, bank, npgs); /* Remove this segment from the list. */ vm_nphysseg--; - if (bank < vm_nphysseg) - memmove(seg, seg+1, - sizeof(*seg) * (vm_nphysseg - bank)); + for (u_int x = bank; x < vm_nphysseg; x++) { + /* structure copy */ + VM_PHYSMEM_PTR_SWAP(x, x + 1); + } + } else { + aprint_debug("%s: seg %u: %zu pages stolen (%#"PRIxPADDR" left)\n", + __func__, bank, npgs, VM_PHYSMEM_SPACE(seg)); } va = pmap_md_map_poolpage(pa, size); @@ -450,7 +537,7 @@ pmap_steal_memory(vsize_t size, vaddr_t /* * If we got here, there was no memory left. */ - panic("pmap_steal_memory: no memory to steal"); + panic("pmap_steal_memory: no memory to steal %zu pages", npgs); } /* @@ -478,6 +565,11 @@ pmap_init(void) */ pool_setlowat(&pmap_pv_pool, pmap_pv_lowat); + /* + * Set the page colormask but allow pmap_md_init to override it. + */ + pmap_page_colormask = ptoa(uvmexp.colormask); + pmap_md_init(); /* @@ -501,12 +593,10 @@ pmap_init(void) pmap_t pmap_create(void) { - pmap_t pmap; - UVMHIST_FUNC(__func__); UVMHIST_CALLED(pmaphist); PMAP_COUNT(create); - pmap = pool_get(&pmap_pmap_pool, PR_WAITOK); + pmap_t pmap = pool_get(&pmap_pmap_pool, PR_WAITOK); memset(pmap, 0, PMAP_SIZE); KASSERT(pmap->pm_pai[0].pai_link.le_prev == NULL); @@ -520,9 +610,12 @@ pmap_create(void) #ifdef MULTIPROCESSOR kcpuset_create(&pmap->pm_active, true); kcpuset_create(&pmap->pm_onproc, true); + KASSERT(pmap->pm_active != NULL); + KASSERT(pmap->pm_onproc != NULL); #endif - UVMHIST_LOG(pmaphist, "<- pmap %p", pmap,0,0,0); + UVMHIST_LOG(pmaphist, " <-- done (pmap=%p)", pmap, 0, 0, 0); + return pmap; } @@ -535,15 +628,16 @@ void pmap_destroy(pmap_t pmap) { UVMHIST_FUNC(__func__); UVMHIST_CALLED(pmaphist); - UVMHIST_LOG(pmaphist, "(pmap=%p)", pmap, 0,0,0); + UVMHIST_LOG(pmaphist, "(pmap=%p)", pmap, 0, 0, 0); if (atomic_dec_uint_nv(&pmap->pm_count) > 0) { PMAP_COUNT(dereference); + UVMHIST_LOG(pmaphist, " <-- done (deref)", 0, 0, 0, 0); return; } - KASSERT(pmap->pm_count == 0); PMAP_COUNT(destroy); + KASSERT(pmap->pm_count == 0); kpreempt_disable(); pmap_md_tlb_miss_lock_enter(); pmap_tlb_asid_release_all(pmap); @@ -553,12 +647,14 @@ pmap_destroy(pmap_t pmap) #ifdef MULTIPROCESSOR kcpuset_destroy(pmap->pm_active); kcpuset_destroy(pmap->pm_onproc); + pmap->pm_active = NULL; + pmap->pm_onproc = NULL; #endif pool_put(&pmap_pmap_pool, pmap); kpreempt_enable(); - UVMHIST_LOG(pmaphist, "<- done", 0,0,0,0); + UVMHIST_LOG(pmaphist, " <-- done (freed)", 0, 0, 0, 0); } /* @@ -567,16 +663,15 @@ pmap_destroy(pmap_t pmap) void pmap_reference(pmap_t pmap) { - UVMHIST_FUNC(__func__); UVMHIST_CALLED(pmaphist); - UVMHIST_LOG(pmaphist, "(pmap=%p)", pmap, 0,0,0); + UVMHIST_LOG(pmaphist, "(pmap=%p)", pmap, 0, 0, 0); PMAP_COUNT(reference); if (pmap != NULL) { atomic_inc_uint(&pmap->pm_count); } - UVMHIST_LOG(pmaphist, "<- done", 0,0,0,0); + UVMHIST_LOG(pmaphist, " <-- done", 0, 0, 0, 0); } /* @@ -588,7 +683,7 @@ pmap_activate(struct lwp *l) pmap_t pmap = l->l_proc->p_vmspace->vm_map.pmap; UVMHIST_FUNC(__func__); UVMHIST_CALLED(pmaphist); - UVMHIST_LOG(pmaphist, "(l=%p (pmap=%p))", l, pmap, 0,0); + UVMHIST_LOG(pmaphist, "(l=%p (pmap=%p))", l, pmap, 0, 0); PMAP_COUNT(activate); kpreempt_disable(); @@ -600,9 +695,122 @@ pmap_activate(struct lwp *l) pmap_md_tlb_miss_lock_exit(); kpreempt_enable(); - UVMHIST_LOG(pmaphist, "<- done", 0,0,0,0); + UVMHIST_LOG(pmaphist, " <-- done", 0, 0, 0, 0); +} + +/* + * Remove this page from all physical maps in which it resides. + * Reflects back modify bits to the pager. + */ +void +pmap_page_remove(struct vm_page *pg) +{ + struct vm_page_md * const mdpg = VM_PAGE_TO_MD(pg); + + kpreempt_disable(); + VM_PAGEMD_PVLIST_LOCK(mdpg); + pmap_pvlist_check(mdpg); + + UVMHIST_FUNC(__func__); UVMHIST_CALLED(pmaphist); + + pv_entry_t pv = &mdpg->mdpg_first; + if (pv->pv_pmap == NULL) { + VM_PAGEMD_PVLIST_UNLOCK(mdpg); + kpreempt_enable(); + UVMHIST_LOG(pmaphist, " <-- done (empty)", 0, 0, 0, 0); + return; + } + + pv_entry_t npv; + pv_entry_t pvp = NULL; + + for (; pv != NULL; pv = npv) { + npv = pv->pv_next; +#ifdef PMAP_VIRTUAL_CACHE_ALIASES + if (pv->pv_va & PV_KENTER) { + UVMHIST_LOG(pmaphist, " pv %p pmap %p va %" + PRIxVADDR" skip", pv, pv->pv_pmap, pv->pv_va, 0); + + KASSERT(pv->pv_pmap == pmap_kernel()); + + /* Assume no more - it'll get fixed if there are */ + pv->pv_next = NULL; + + /* + * pvp is non-null when we already have a PV_KENTER + * pv in pvh_first; otherwise we haven't seen a + * PV_KENTER pv and we need to copy this one to + * pvh_first + */ + if (pvp) { + /* + * The previous PV_KENTER pv needs to point to + * this PV_KENTER pv + */ + pvp->pv_next = pv; + } else { + pv_entry_t fpv = &mdpg->mdpg_first; + *fpv = *pv; + KASSERT(fpv->pv_pmap == pmap_kernel()); + } + pvp = pv; + continue; + } +#endif + const pmap_t pmap = pv->pv_pmap; + vaddr_t va = trunc_page(pv->pv_va); + pt_entry_t * const ptep = pmap_pte_lookup(pmap, va); + KASSERTMSG(ptep != NULL, "%#"PRIxVADDR " %#"PRIxVADDR, va, + pmap_limits.virtual_end); + pt_entry_t pte = *ptep; + UVMHIST_LOG(pmaphist, " pv %p pmap %p va %"PRIxVADDR + " pte %#"PRIxPTE, pv, pmap, va, pte_value(pte)); + if (!pte_valid_p(pte)) + continue; + const bool is_kernel_pmap_p = (pmap == pmap_kernel()); + if (is_kernel_pmap_p) { + PMAP_COUNT(remove_kernel_pages); + } else { + PMAP_COUNT(remove_user_pages); + } + if (pte_wired_p(pte)) + pmap->pm_stats.wired_count--; + pmap->pm_stats.resident_count--; + + pmap_md_tlb_miss_lock_enter(); + const pt_entry_t npte = pte_nv_entry(is_kernel_pmap_p); + *ptep = npte; + /* + * Flush the TLB for the given address. + */ + pmap_tlb_invalidate_addr(pmap, va); + pmap_md_tlb_miss_lock_exit(); + + /* + * non-null means this is a non-pvh_first pv, so we should + * free it. + */ + if (pvp) { + KASSERT(pvp->pv_pmap == pmap_kernel()); + KASSERT(pvp->pv_next == NULL); + pmap_pv_free(pv); + } else { + pv->pv_pmap = NULL; + pv->pv_next = NULL; + } + } + +#ifdef PMAP_VIRTUAL_CACHE_ALIASES + pmap_page_clear_attributes(mdpg, VM_PAGEMD_UNCACHED); +#endif + pmap_pvlist_check(mdpg); + VM_PAGEMD_PVLIST_UNLOCK(mdpg); + kpreempt_enable(); + + UVMHIST_LOG(pmaphist, " <-- done", 0, 0, 0, 0); } + /* * Make a previously active pmap (vmspace) inactive. */ @@ -612,25 +820,28 @@ pmap_deactivate(struct lwp *l) pmap_t pmap = l->l_proc->p_vmspace->vm_map.pmap; UVMHIST_FUNC(__func__); UVMHIST_CALLED(pmaphist); - UVMHIST_LOG(pmaphist, "(l=%p (pmap=%p))", l, pmap, 0,0); + UVMHIST_LOG(pmaphist, "(l=%p (pmap=%p))", l, pmap, 0, 0); PMAP_COUNT(deactivate); kpreempt_disable(); + KASSERT(l == curlwp || l->l_cpu == curlwp->l_cpu); pmap_md_tlb_miss_lock_enter(); curcpu()->ci_pmap_user_segtab = PMAP_INVALID_SEGTAB_ADDRESS; +#ifdef _LP64 + curcpu()->ci_pmap_user_seg0tab = NULL; +#endif pmap_tlb_asid_deactivate(pmap); pmap_md_tlb_miss_lock_exit(); kpreempt_enable(); - UVMHIST_LOG(pmaphist, "<- done", 0,0,0,0); + UVMHIST_LOG(pmaphist, " <-- done", 0, 0, 0, 0); } void pmap_update(struct pmap *pmap) { - UVMHIST_FUNC(__func__); UVMHIST_CALLED(pmaphist); - UVMHIST_LOG(pmaphist, "(pmap=%p)", pmap, 0,0,0); + UVMHIST_LOG(pmaphist, "(pmap=%p)", pmap, 0, 0, 0); PMAP_COUNT(update); kpreempt_disable(); @@ -656,7 +867,8 @@ pmap_update(struct pmap *pmap) pmap_md_tlb_miss_lock_exit(); kpreempt_enable(); - UVMHIST_LOG(pmaphist, "<- done", 0,0,0,0); + UVMHIST_LOG(pmaphist, " <-- done%s", + (pmap == pmap_kernel()) ? " (kernel)" : "", 0, 0, 0); } /* @@ -674,7 +886,7 @@ pmap_pte_remove(pmap_t pmap, vaddr_t sva const bool is_kernel_pmap_p = (pmap == pmap_kernel()); UVMHIST_FUNC(__func__); UVMHIST_CALLED(pmaphist); - UVMHIST_LOG(pmaphist, "(pmap=%p %sva=%"PRIxVADDR"..%"PRIxVADDR, + UVMHIST_LOG(pmaphist, "(pmap=%p %sva=%#"PRIxVADDR"..%#"PRIxVADDR, pmap, (is_kernel_pmap_p ? "(kernel) " : ""), sva, eva); UVMHIST_LOG(pmaphist, "ptep=%p, flags(npte)=%#"PRIxPTR")", ptep, flags, 0, 0); @@ -682,20 +894,20 @@ pmap_pte_remove(pmap_t pmap, vaddr_t sva KASSERT(kpreempt_disabled()); for (; sva < eva; sva += NBPG, ptep++) { - pt_entry_t pt_entry = *ptep; - if (!pte_valid_p(pt_entry)) + const pt_entry_t pte = *ptep; + if (!pte_valid_p(pte)) continue; - if (is_kernel_pmap_p) - PMAP_COUNT(remove_kernel_calls); - else + if (is_kernel_pmap_p) { + PMAP_COUNT(remove_kernel_pages); + } else { PMAP_COUNT(remove_user_pages); - if (pte_wired_p(pt_entry)) + } + if (pte_wired_p(pte)) pmap->pm_stats.wired_count--; pmap->pm_stats.resident_count--; - struct vm_page *pg = PHYS_TO_VM_PAGE(pte_to_paddr(pt_entry)); + struct vm_page * const pg = PHYS_TO_VM_PAGE(pte_to_paddr(pte)); if (__predict_true(pg != NULL)) { - pmap_remove_pv(pmap, sva, pg, - pte_modified_p(pt_entry)); + pmap_remove_pv(pmap, sva, pg, pte_modified_p(pte)); } pmap_md_tlb_miss_lock_enter(); *ptep = npte; @@ -705,6 +917,9 @@ pmap_pte_remove(pmap_t pmap, vaddr_t sva pmap_tlb_invalidate_addr(pmap, sva); pmap_md_tlb_miss_lock_exit(); } + + UVMHIST_LOG(pmaphist, " <-- done", 0, 0, 0, 0); + return false; } @@ -718,28 +933,22 @@ pmap_remove(pmap_t pmap, vaddr_t sva, va UVMHIST_LOG(pmaphist, "(pmap=%p, va=%#"PRIxVADDR"..%#"PRIxVADDR")", pmap, sva, eva, 0); - if (is_kernel_pmap_p) + if (is_kernel_pmap_p) { PMAP_COUNT(remove_kernel_calls); - else + } else { PMAP_COUNT(remove_user_calls); -#ifdef PARANOIADIAG - if (sva < pm->pm_minaddr || eva > pm->pm_maxaddr) - panic("%s: va range %#"PRIxVADDR"-%#"PRIxVADDR" not in range", - __func__, sva, eva - 1); - if (PMAP_IS_ACTIVE(pmap)) { - struct pmap_asid_info * const pai = PMAP_PAI(pmap, curcpu()); - uint32_t asid = tlb_get_asid(); - if (asid != pai->pai_asid) { - panic("%s: inconsistency for active TLB flush" - ": %d <-> %d", __func__, asid, pai->pai_asid); - } } +#ifdef PMAP_FAULTINFO + curpcb->pcb_faultinfo.pfi_faultaddr = 0; + curpcb->pcb_faultinfo.pfi_repeats = 0; + curpcb->pcb_faultinfo.pfi_faultpte = NULL; #endif kpreempt_disable(); + pmap_addr_range_check(pmap, sva, eva, __func__); pmap_pte_process(pmap, sva, eva, pmap_pte_remove, npte); kpreempt_enable(); - UVMHIST_LOG(pmaphist, "<- done", 0,0,0,0); + UVMHIST_LOG(pmaphist, " <-- done", 0, 0, 0, 0); } /* @@ -767,55 +976,47 @@ pmap_page_protect(struct vm_page *pg, vm /* copy_on_write */ case VM_PROT_READ: case VM_PROT_READ|VM_PROT_EXECUTE: - (void)VM_PAGEMD_PVLIST_LOCK(mdpg, false); pv = &mdpg->mdpg_first; + kpreempt_disable(); + VM_PAGEMD_PVLIST_READLOCK(mdpg); + pmap_pvlist_check(mdpg); /* - * Loop over all current mappings setting/clearing as appropriate. + * Loop over all current mappings setting/clearing as apropos. */ if (pv->pv_pmap != NULL) { while (pv != NULL) { +#ifdef PMAP_VIRTUAL_CACHE_ALIASES + if (pv->pv_va & PV_KENTER) { + pv = pv->pv_next; + continue; + } +#endif const pmap_t pmap = pv->pv_pmap; - const uint16_t gen = VM_PAGEMD_PVLIST_GEN(mdpg); - va = pv->pv_va; - VM_PAGEMD_PVLIST_UNLOCK(mdpg); + va = trunc_page(pv->pv_va); + const uintptr_t gen = + VM_PAGEMD_PVLIST_UNLOCK(mdpg); pmap_protect(pmap, va, va + PAGE_SIZE, prot); KASSERT(pv->pv_pmap == pmap); pmap_update(pmap); - if (gen != VM_PAGEMD_PVLIST_LOCK(mdpg, false)) { + if (gen != VM_PAGEMD_PVLIST_READLOCK(mdpg)) { pv = &mdpg->mdpg_first; } else { pv = pv->pv_next; } + pmap_pvlist_check(mdpg); } } + pmap_pvlist_check(mdpg); VM_PAGEMD_PVLIST_UNLOCK(mdpg); + kpreempt_enable(); break; /* remove_all */ default: - /* - * Do this first so that for each unmapping, pmap_remove_pv - * won't try to sync the icache. - */ - if (pmap_page_clear_attributes(mdpg, VM_PAGEMD_EXECPAGE)) { - UVMHIST_LOG(pmapexechist, "pg %p (pa %#"PRIxPADDR - "): execpage cleared", pg, VM_PAGE_TO_PHYS(pg),0,0); - PMAP_COUNT(exec_uncached_page_protect); - } - (void)VM_PAGEMD_PVLIST_LOCK(mdpg, false); - pv = &mdpg->mdpg_first; - while (pv->pv_pmap != NULL) { - const pmap_t pmap = pv->pv_pmap; - va = pv->pv_va; - VM_PAGEMD_PVLIST_UNLOCK(mdpg); - pmap_remove(pmap, va, va + PAGE_SIZE); - pmap_update(pmap); - (void)VM_PAGEMD_PVLIST_LOCK(mdpg, false); - } - VM_PAGEMD_PVLIST_UNLOCK(mdpg); + pmap_page_remove(pg); } - UVMHIST_LOG(pmaphist, "<- done", 0,0,0,0); + UVMHIST_LOG(pmaphist, " <-- done", 0, 0, 0, 0); } static bool @@ -825,7 +1026,7 @@ pmap_pte_protect(pmap_t pmap, vaddr_t sv const vm_prot_t prot = (flags & VM_PROT_ALL); UVMHIST_FUNC(__func__); UVMHIST_CALLED(pmaphist); - UVMHIST_LOG(pmaphist, "(pmap=%p %sva=%"PRIxVADDR"..%"PRIxVADDR, + UVMHIST_LOG(pmaphist, "(pmap=%p %sva=%#"PRIxVADDR"..%#"PRIxVADDR, pmap, (pmap == pmap_kernel() ? "(kernel) " : ""), sva, eva); UVMHIST_LOG(pmaphist, "ptep=%p, flags(npte)=%#"PRIxPTR")", ptep, flags, 0, 0); @@ -835,38 +1036,42 @@ pmap_pte_protect(pmap_t pmap, vaddr_t sv * Change protection on every valid mapping within this segment. */ for (; sva < eva; sva += NBPG, ptep++) { - pt_entry_t pt_entry = *ptep; - if (!pte_valid_p(pt_entry)) + pt_entry_t pte = *ptep; + if (!pte_valid_p(pte)) continue; - struct vm_page * const pg = - PHYS_TO_VM_PAGE(pte_to_paddr(pt_entry)); - if (pg != NULL && pte_modified_p(pt_entry)) { + struct vm_page * const pg = PHYS_TO_VM_PAGE(pte_to_paddr(pte)); + if (pg != NULL && pte_modified_p(pte)) { struct vm_page_md * const mdpg = VM_PAGE_TO_MD(pg); - pmap_md_vca_clean(pg, sva, PMAP_WBINV); if (VM_PAGEMD_EXECPAGE_P(mdpg)) { KASSERT(mdpg->mdpg_first.pv_pmap != NULL); - if (pte_cached_p(pt_entry)) { +#ifdef PMAP_VIRTUAL_CACHE_ALIASES + if (VM_PAGEMD_CACHED_P(mdpg)) { +#endif UVMHIST_LOG(pmapexechist, "pg %p (pa %#"PRIxPADDR"): %s", pg, VM_PAGE_TO_PHYS(pg), "syncicached performed", 0); pmap_page_syncicache(pg); PMAP_COUNT(exec_synced_protect); +#ifdef PMAP_VIRTUAL_CACHE_ALIASES } +#endif } } - pt_entry = pte_prot_downgrade(pt_entry, prot); - if (*ptep != pt_entry) { + pte = pte_prot_downgrade(pte, prot); + if (*ptep != pte) { pmap_md_tlb_miss_lock_enter(); - *ptep = pt_entry; + *ptep = pte; /* * Update the TLB if needed. */ - pmap_tlb_update_addr(pmap, sva, pt_entry, - PMAP_TLB_NEED_IPI); + pmap_tlb_update_addr(pmap, sva, pte, PMAP_TLB_NEED_IPI); pmap_md_tlb_miss_lock_exit(); } } + + UVMHIST_LOG(pmaphist, " <-- done", 0, 0, 0, 0); + return false; } @@ -877,57 +1082,46 @@ pmap_pte_protect(pmap_t pmap, vaddr_t sv void pmap_protect(pmap_t pmap, vaddr_t sva, vaddr_t eva, vm_prot_t prot) { - UVMHIST_FUNC(__func__); UVMHIST_CALLED(pmaphist); UVMHIST_LOG(pmaphist, - " pmap=%p, va=%#"PRIxVADDR"..%#"PRIxVADDR" port=%#x)", + "(pmap=%p, va=%#"PRIxVADDR"..%#"PRIxVADDR", prot=%u)", pmap, sva, eva, prot); PMAP_COUNT(protect); if ((prot & VM_PROT_READ) == VM_PROT_NONE) { pmap_remove(pmap, sva, eva); - UVMHIST_LOG(pmaphist, "<- done", 0,0,0,0); + UVMHIST_LOG(pmaphist, " <-- done", 0, 0, 0, 0); return; } -#ifdef PARANOIADIAG - if (sva < pm->pm_minaddr || eva > pm->pm_maxaddr) - panic("%s: va range %#"PRIxVADDR"-%#"PRIxVADDR" not in range", - __func__, sva, eva - 1); - if (PMAP_IS_ACTIVE(pmap)) { - struct pmap_asid_info * const pai = PMAP_PAI(pmap, curcpu()); - uint32_t asid = tlb_get_asid(); - if (asid != pai->pai_asid) { - panic("%s: inconsistency for active TLB update" - ": %d <-> %d", __func__, asid, pai->pai_asid); - } - } -#endif - /* * Change protection on every valid mapping within this segment. */ kpreempt_disable(); + pmap_addr_range_check(pmap, sva, eva, __func__); pmap_pte_process(pmap, sva, eva, pmap_pte_protect, prot); kpreempt_enable(); - UVMHIST_LOG(pmaphist, "<- done", 0,0,0,0); + UVMHIST_LOG(pmaphist, " <-- done", 0, 0, 0, 0); } -#if defined(__PMAP_VIRTUAL_CACHE_ALIASES) +#if defined(PMAP_VIRTUAL_CACHE_ALIASES) && !defined(PMAP_NO_PV_UNCACHED) /* * pmap_page_cache: * * Change all mappings of a managed page to cached/uncached. */ -static void +void pmap_page_cache(struct vm_page *pg, bool cached) { struct vm_page_md * const mdpg = VM_PAGE_TO_MD(pg); + UVMHIST_FUNC(__func__); UVMHIST_CALLED(pmaphist); UVMHIST_LOG(pmaphist, "(pg=%p (pa %#"PRIxPADDR") cached=%s)", pg, VM_PAGE_TO_PHYS(pg), cached ? "true" : "false", 0); + KASSERT(kpreempt_disabled()); + KASSERT(VM_PAGEMD_PVLIST_LOCKED_P(mdpg)); if (cached) { pmap_page_clear_attributes(mdpg, VM_PAGEMD_UNCACHED); @@ -937,32 +1131,28 @@ pmap_page_cache(struct vm_page *pg, bool PMAP_COUNT(page_cache_evictions); } - KASSERT(VM_PAGEMD_PVLIST_LOCKED_P(mdpg)); - KASSERT(kpreempt_disabled()); - for (pv_entry_t pv = &mdpg->mdpg_first; - pv != NULL; - pv = pv->pv_next) { + for (pv_entry_t pv = &mdpg->mdpg_first; pv != NULL; pv = pv->pv_next) { pmap_t pmap = pv->pv_pmap; - vaddr_t va = pv->pv_va; + vaddr_t va = trunc_page(pv->pv_va); KASSERT(pmap != NULL); KASSERT(pmap != pmap_kernel() || !pmap_md_direct_mapped_vaddr_p(va)); pt_entry_t * const ptep = pmap_pte_lookup(pmap, va); if (ptep == NULL) continue; - pt_entry_t pt_entry = *ptep; - if (pte_valid_p(pt_entry)) { - pt_entry = pte_cached_change(pt_entry, cached); + pt_entry_t pte = *ptep; + if (pte_valid_p(pte)) { + pte = pte_cached_change(pte, cached); pmap_md_tlb_miss_lock_enter(); - *ptep = pt_entry; - pmap_tlb_update_addr(pmap, va, pt_entry, - PMAP_TLB_NEED_IPI); + *ptep = pte; + pmap_tlb_update_addr(pmap, va, pte, PMAP_TLB_NEED_IPI); pmap_md_tlb_miss_lock_exit(); } } - UVMHIST_LOG(pmaphist, "<- done", 0,0,0,0); + + UVMHIST_LOG(pmaphist, " <-- done", 0, 0, 0, 0); } -#endif /* __PMAP_VIRTUAL_CACHE_ALIASES */ +#endif /* PMAP_VIRTUAL_CACHE_ALIASES && !PMAP_NO_PV_UNCACHED */ /* * Insert the given physical page (p) at @@ -979,18 +1169,25 @@ pmap_page_cache(struct vm_page *pg, bool int pmap_enter(pmap_t pmap, vaddr_t va, paddr_t pa, vm_prot_t prot, u_int flags) { - pt_entry_t npte; const bool wired = (flags & PMAP_WIRED) != 0; const bool is_kernel_pmap_p = (pmap == pmap_kernel()); + u_int update_flags = (flags & VM_PROT_ALL) != 0 ? PMAP_TLB_INSERT : 0; #ifdef UVMHIST - struct kern_history * const histp = + struct kern_history * const histp = ((prot & VM_PROT_EXECUTE) ? &pmapexechist : &pmaphist); #endif - UVMHIST_FUNC(__func__); + UVMHIST_FUNC(__func__); UVMHIST_CALLED(*histp); #define VM_PROT_STRING(prot) \ - &"\0 (R)\0 (W)\0 (RW)\0 (X)\0 (RX)\0 (WX)\0 (RWX)\0"[UVM_PROTECTION(prot)*6] - UVMHIST_CALLED(*histp); + &"\0 " \ + "(R)\0 " \ + "(W)\0 " \ + "(RW)\0 " \ + "(X)\0 " \ + "(RX)\0 " \ + "(WX)\0 " \ + "(RWX)\0"[UVM_PROTECTION(prot)*6] + UVMHIST_LOG(*histp, "(pmap=%p, va=%#"PRIxVADDR", pa=%#"PRIxPADDR, UVMHIST_LOG(*histp, "(pmap=%p, va=%#"PRIxVADDR", pa=%#"PRIxPADDR, pmap, va, pa, 0); UVMHIST_LOG(*histp, "prot=%#x%s flags=%#x%s)", @@ -1006,29 +1203,27 @@ pmap_enter(pmap_t pmap, vaddr_t va, padd if (!good_color) PMAP_COUNT(user_mappings_bad); } -#if defined(DEBUG) || defined(DIAGNOSTIC) || defined(PARANOIADIAG) - if (va < pmap->pm_minaddr || va >= pmap->pm_maxaddr) - panic("%s: %s %#"PRIxVADDR" too big", - __func__, is_kernel_pmap_p ? "kva" : "uva", va); -#endif + pmap_addr_range_check(pmap, va, va, __func__); - KASSERTMSG(prot & VM_PROT_READ, - "%s: no READ (%#x) in prot %#x", __func__, VM_PROT_READ, prot); + KASSERTMSG(prot & VM_PROT_READ, "no READ (%#x) in prot %#x", + VM_PROT_READ, prot); struct vm_page * const pg = PHYS_TO_VM_PAGE(pa); - struct vm_page_md *mdpg; + struct vm_page_md * const mdpg = (pg ? VM_PAGE_TO_MD(pg) : NULL); if (pg) { - mdpg = VM_PAGE_TO_MD(pg); /* Set page referenced/modified status based on flags */ - if (flags & VM_PROT_WRITE) + if (flags & VM_PROT_WRITE) { pmap_page_set_attributes(mdpg, VM_PAGEMD_MODIFIED|VM_PAGEMD_REFERENCED); - else if (flags & VM_PROT_ALL) + } else if (flags & VM_PROT_ALL) { pmap_page_set_attributes(mdpg, VM_PAGEMD_REFERENCED); + } -#ifdef __PMAP_VIRTUAL_CACHE_ALIASES - if (!VM_PAGEMD_CACHED(pg)) +#ifdef PMAP_VIRTUAL_CACHE_ALIASES + if (!VM_PAGEMD_CACHED_P(mdpg)) { flags |= PMAP_NOCACHE; + PMAP_COUNT(uncached_mappings); + } #endif PMAP_COUNT(managed_mappings); @@ -1037,25 +1232,27 @@ pmap_enter(pmap_t pmap, vaddr_t va, padd * Assumption: if it is not part of our managed memory * then it must be device memory which may be volatile. */ - mdpg = NULL; - flags |= PMAP_NOCACHE; + if ((flags & PMAP_CACHE_MASK) == 0) + flags |= PMAP_NOCACHE; PMAP_COUNT(unmanaged_mappings); } - npte = pte_make_enter(pa, mdpg, prot, flags, is_kernel_pmap_p); + pt_entry_t npte = pte_make_enter(pa, mdpg, prot, flags, + is_kernel_pmap_p); kpreempt_disable(); + pt_entry_t * const ptep = pmap_pte_reserve(pmap, va, flags); if (__predict_false(ptep == NULL)) { kpreempt_enable(); - UVMHIST_LOG(*histp, "<- ENOMEM", 0,0,0,0); + UVMHIST_LOG(*histp, " <-- ENOMEM", 0, 0, 0, 0); return ENOMEM; } - pt_entry_t opte = *ptep; + const pt_entry_t opte = *ptep; /* Done after case that may sleep/return. */ if (pg) - pmap_enter_pv(pmap, va, pg, &npte); + pmap_enter_pv(pmap, va, pg, &npte, 0); /* * Now validate mapping with desired protection/wiring. @@ -1067,7 +1264,8 @@ pmap_enter(pmap_t pmap, vaddr_t va, padd npte = pte_wire_entry(npte); } - UVMHIST_LOG(*histp, "new pte %#x (pa %#"PRIxPADDR")", npte, pa, 0,0); + UVMHIST_LOG(*histp, "new pte %#"PRIxPTE" (pa %#"PRIxPADDR")", + pte_value(npte), pa, 0, 0); if (pte_valid_p(opte) && pte_to_paddr(opte) != pa) { pmap_remove(pmap, va, va + NBPG); @@ -1075,15 +1273,16 @@ pmap_enter(pmap_t pmap, vaddr_t va, padd } KASSERT(pte_valid_p(npte)); - bool resident = pte_valid_p(opte); - if (!resident) + const bool resident = pte_valid_p(opte); + if (resident) { + update_flags |= PMAP_TLB_NEED_IPI; + } else { pmap->pm_stats.resident_count++; + } + pmap_md_tlb_miss_lock_enter(); *ptep = npte; - - pmap_tlb_update_addr(pmap, va, npte, - ((flags & VM_PROT_ALL) ? PMAP_TLB_INSERT : 0) - | (resident ? PMAP_TLB_NEED_IPI : 0)); + pmap_tlb_update_addr(pmap, va, npte, update_flags); pmap_md_tlb_miss_lock_exit(); kpreempt_enable(); @@ -1118,52 +1317,59 @@ pmap_enter(pmap_t pmap, vaddr_t va, padd PMAP_COUNT(exec_mappings); pmap_page_syncicache(pg); pmap_page_clear_attributes(mdpg, VM_PAGEMD_EXECPAGE); - UVMHIST_LOG(pmapexechist, + UVMHIST_LOG(*histp, "va=%#"PRIxVADDR" pg %p: %s syncicache%s", va, pg, "immediate", " (writeable)"); } - if (prot & VM_PROT_EXECUTE) { - UVMHIST_LOG(pmapexechist, "<- 0 (OK)", 0,0,0,0); - } else { - UVMHIST_LOG(pmaphist, "<- 0 (OK)", 0,0,0,0); - } + UVMHIST_LOG(*histp, " <-- 0 (OK)", 0, 0, 0, 0); return 0; } void pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot, u_int flags) { + pmap_t pmap = pmap_kernel(); struct vm_page * const pg = PHYS_TO_VM_PAGE(pa); - struct vm_page_md *mdpg; + struct vm_page_md * const mdpg = (pg ? VM_PAGE_TO_MD(pg) : NULL); UVMHIST_FUNC(__func__); UVMHIST_CALLED(pmaphist); - UVMHIST_LOG(pmaphist, "(va=%#"PRIxVADDR" pa=%#"PRIxPADDR - ", prot=%#x, flags=%#x)", va, pa, prot, flags); + UVMHIST_LOG(pmaphist, + "(va=%#"PRIxVADDR", pa=%#"PRIxPADDR", prot=%u, flags=%#x)", + va, pa, prot, flags); PMAP_COUNT(kenter_pa); - if (pg == NULL) { - mdpg = NULL; + if (mdpg == NULL) { PMAP_COUNT(kenter_pa_unmanaged); - flags |= PMAP_NOCACHE; + if ((flags & PMAP_CACHE_MASK) == 0) + flags |= PMAP_NOCACHE; } else { - mdpg = VM_PAGE_TO_MD(pg); + if ((flags & PMAP_NOCACHE) == 0 && !PMAP_PAGE_COLOROK_P(pa, va)) + PMAP_COUNT(kenter_pa_bad); } - if ((flags & PMAP_NOCACHE) == 0 && !PMAP_PAGE_COLOROK_P(pa, va)) - PMAP_COUNT(kenter_pa_bad); - - const pt_entry_t npte = pte_make_kenter_pa(pa, mdpg, prot, flags); + pt_entry_t npte = pte_make_kenter_pa(pa, mdpg, prot, flags); kpreempt_disable(); - pt_entry_t * const ptep = pmap_pte_reserve(pmap_kernel(), va, 0); - KASSERT(ptep != NULL); + pt_entry_t * const ptep = pmap_pte_lookup(pmap, va); + KASSERTMSG(ptep != NULL, "%#"PRIxVADDR " %#"PRIxVADDR, va, + pmap_limits.virtual_end); KASSERT(!pte_valid_p(*ptep)); - pmap_md_tlb_miss_lock_enter(); - *ptep = npte; + + /* + * No need to track non-managed pages or PMAP_KMPAGEs pages for aliases + */ +#ifdef PMAP_VIRTUAL_CACHE_ALIASES + if (pg != NULL && (flags & PMAP_KMPAGE) == 0) { + pmap_enter_pv(pmap, va, pg, &npte, PV_KENTER); + } +#endif + /* * We have the option to force this mapping into the TLB but we * don't. Instead let the next reference to the page do it. */ + pmap_md_tlb_miss_lock_enter(); + *ptep = npte; pmap_tlb_update_addr(pmap_kernel(), va, npte, 0); pmap_md_tlb_miss_lock_exit(); kpreempt_enable(); @@ -1175,38 +1381,49 @@ pmap_kenter_pa(vaddr_t va, paddr_t pa, v ((long *)va)[i], va, ((long *)pa)[i], pa); } #endif - UVMHIST_LOG(pmaphist, "<- done", 0,0,0,0); + + UVMHIST_LOG(pmaphist, " <-- done (ptep=%p)", ptep, 0, 0, 0); } +/* + * Remove the given range of addresses from the kernel map. + * + * It is assumed that the start and end are properly + * rounded to the page size. + */ + static bool pmap_pte_kremove(pmap_t pmap, vaddr_t sva, vaddr_t eva, pt_entry_t *ptep, uintptr_t flags) { - const pt_entry_t new_pt_entry = pte_nv_entry(true); + const pt_entry_t new_pte = pte_nv_entry(true); + + UVMHIST_FUNC(__func__); UVMHIST_CALLED(pmaphist); + UVMHIST_LOG(pmaphist, + "(pmap=%p, sva=%#"PRIxVADDR", eva=%#"PRIxVADDR", ptep=%p)", + pmap, sva, eva, ptep); KASSERT(kpreempt_disabled()); - /* - * Set every pt on every valid mapping within this segment. - */ for (; sva < eva; sva += NBPG, ptep++) { - pt_entry_t pt_entry = *ptep; - if (!pte_valid_p(pt_entry)) { + pt_entry_t pte = *ptep; + if (!pte_valid_p(pte)) continue; - } PMAP_COUNT(kremove_pages); - struct vm_page * const pg = - PHYS_TO_VM_PAGE(pte_to_paddr(pt_entry)); - if (pg != NULL) - pmap_md_vca_clean(pg, sva, PMAP_WBINV); + struct vm_page * const pg = PHYS_TO_VM_PAGE(pte_to_paddr(pte)); + if (pg != NULL) { + pmap_remove_pv(pmap, sva, pg, !pte_readonly_p(pte)); + } pmap_md_tlb_miss_lock_enter(); - *ptep = new_pt_entry; - pmap_tlb_invalidate_addr(pmap_kernel(), sva); + *ptep = new_pte; + pmap_tlb_invalidate_addr(pmap, sva); pmap_md_tlb_miss_lock_exit(); } + UVMHIST_LOG(pmaphist, " <-- done", 0, 0, 0, 0); + return false; } @@ -1217,19 +1434,22 @@ pmap_kremove(vaddr_t va, vsize_t len) const vaddr_t eva = round_page(va + len); UVMHIST_FUNC(__func__); UVMHIST_CALLED(pmaphist); - UVMHIST_LOG(pmaphist, "(va=%#"PRIxVADDR" len=%#"PRIxVSIZE")", - va, len, 0,0); + UVMHIST_LOG(pmaphist, "(va=%#"PRIxVADDR", len=%#"PRIxVSIZE")", + va, len, 0, 0); kpreempt_disable(); pmap_pte_process(pmap_kernel(), sva, eva, pmap_pte_kremove, 0); kpreempt_enable(); - UVMHIST_LOG(pmaphist, "<- done", 0,0,0,0); + UVMHIST_LOG(pmaphist, " <-- done", 0, 0, 0, 0); } void pmap_remove_all(struct pmap *pmap) { + UVMHIST_FUNC(__func__); UVMHIST_CALLED(pmaphist); + UVMHIST_LOG(pmaphist, "(pm=%p)", pmap, 0, 0, 0); + KASSERT(pmap != pmap_kernel()); kpreempt_disable(); @@ -1238,12 +1458,27 @@ pmap_remove_all(struct pmap *pmap) * tlb_invalidate_addrs(). */ pmap_md_tlb_miss_lock_enter(); - pmap_tlb_asid_deactivate(pmap); +#ifdef MULTIPROCESSOR + // This should be the last CPU with this pmap onproc + KASSERT(!kcpuset_isotherset(pmap->pm_onproc, cpu_index(curcpu()))); + if (kcpuset_isset(pmap->pm_onproc, cpu_index(curcpu()))) +#endif + pmap_tlb_asid_deactivate(pmap); +#ifdef MULTIPROCESSOR + KASSERT(kcpuset_iszero(pmap->pm_onproc)); +#endif pmap_tlb_asid_release_all(pmap); pmap_md_tlb_miss_lock_exit(); pmap->pm_flags |= PMAP_DEFERRED_ACTIVATE; +#ifdef PMAP_FAULTINFO + curpcb->pcb_faultinfo.pfi_faultaddr = 0; + curpcb->pcb_faultinfo.pfi_repeats = 0; + curpcb->pcb_faultinfo.pfi_faultpte = NULL; +#endif kpreempt_enable(); + + UVMHIST_LOG(pmaphist, " <-- done", 0, 0, 0, 0); } /* @@ -1256,36 +1491,26 @@ pmap_remove_all(struct pmap *pmap) void pmap_unwire(pmap_t pmap, vaddr_t va) { - UVMHIST_FUNC(__func__); UVMHIST_CALLED(pmaphist); - UVMHIST_LOG(pmaphist, "(pmap=%p va=%#"PRIxVADDR")", pmap, va, 0,0); + UVMHIST_LOG(pmaphist, "(pmap=%p, va=%#"PRIxVADDR")", pmap, va, 0, 0); PMAP_COUNT(unwire); /* * Don't need to flush the TLB since PG_WIRED is only in software. */ -#ifdef PARANOIADIAG - if (va < pmap->pm_minaddr || pmap->pm_maxaddr <= va) - panic("pmap_unwire"); -#endif kpreempt_disable(); + pmap_addr_range_check(pmap, va, va, __func__); pt_entry_t * const ptep = pmap_pte_lookup(pmap, va); - pt_entry_t pt_entry = *ptep; -#ifdef DIAGNOSTIC - if (ptep == NULL) - panic("%s: pmap %p va %#"PRIxVADDR" invalid STE", - __func__, pmap, va); -#endif + KASSERTMSG(ptep != NULL, "pmap %p va %#"PRIxVADDR" invalid STE", + pmap, va); + pt_entry_t pte = *ptep; + KASSERTMSG(pte_valid_p(pte), + "pmap %p va %#"PRIxVADDR" invalid PTE %#"PRIxPTE" @ %p", + pmap, va, pte_value(pte), ptep); -#ifdef DIAGNOSTIC - if (!pte_valid_p(pt_entry)) - panic("pmap_unwire: pmap %p va %#"PRIxVADDR" invalid PTE", - pmap, va); -#endif - - if (pte_wired_p(pt_entry)) { + if (pte_wired_p(pte)) { pmap_md_tlb_miss_lock_enter(); - *ptep = pte_unwire_entry(*ptep); + *ptep = pte_unwire_entry(pte); pmap_md_tlb_miss_lock_exit(); pmap->pm_stats.wired_count--; } @@ -1296,6 +1521,8 @@ pmap_unwire(pmap_t pmap, vaddr_t va) } #endif kpreempt_enable(); + + UVMHIST_LOG(pmaphist, " <-- done", 0, 0, 0, 0); } /* @@ -1309,8 +1536,6 @@ pmap_extract(pmap_t pmap, vaddr_t va, pa { paddr_t pa; - //UVMHIST_FUNC(__func__); UVMHIST_CALLED(pmaphist); - //UVMHIST_LOG(pmaphist, "(pmap=%p va=%#"PRIxVADDR")", pmap, va, 0,0); if (pmap == pmap_kernel()) { if (pmap_md_direct_mapped_vaddr_p(va)) { pa = pmap_md_direct_mapped_vaddr_to_paddr(va); @@ -1318,16 +1543,14 @@ pmap_extract(pmap_t pmap, vaddr_t va, pa } if (pmap_md_io_vaddr_p(va)) panic("pmap_extract: io address %#"PRIxVADDR"", va); + + if (va >= pmap_limits.virtual_end) + panic("%s: illegal kernel mapped address %#"PRIxVADDR, + __func__, va); } kpreempt_disable(); - pt_entry_t * const ptep = pmap_pte_lookup(pmap, va); - if (ptep == NULL) { - //UVMHIST_LOG(pmaphist, "<- false (not in segmap)", 0,0,0,0); - kpreempt_enable(); - return false; - } - if (!pte_valid_p(*ptep)) { - //UVMHIST_LOG(pmaphist, "<- false (PTE not valid)", 0,0,0,0); + const pt_entry_t * const ptep = pmap_pte_lookup(pmap, va); + if (ptep == NULL || !pte_valid_p(*ptep)) { kpreempt_enable(); return false; } @@ -1337,7 +1560,6 @@ done: if (pap != NULL) { *pap = pa; } - //UVMHIST_LOG(pmaphist, "<- true (pa %#"PRIxPADDR")", pa, 0,0,0); return true; } @@ -1352,7 +1574,6 @@ void pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vaddr_t dst_addr, vsize_t len, vaddr_t src_addr) { - UVMHIST_FUNC(__func__); UVMHIST_CALLED(pmaphist); PMAP_COUNT(copy); } @@ -1373,7 +1594,7 @@ pmap_clear_reference(struct vm_page *pg) bool rv = pmap_page_clear_attributes(mdpg, VM_PAGEMD_REFERENCED); - UVMHIST_LOG(pmaphist, "<- %s", rv ? "true" : "false", 0,0,0); + UVMHIST_LOG(pmaphist, " <-- %s", rv ? "true" : "false", 0, 0, 0); return rv; } @@ -1387,7 +1608,6 @@ pmap_clear_reference(struct vm_page *pg) bool pmap_is_referenced(struct vm_page *pg) { - return VM_PAGEMD_REFERENCED_P(VM_PAGE_TO_MD(pg)); } @@ -1400,7 +1620,6 @@ pmap_clear_modify(struct vm_page *pg) struct vm_page_md * const mdpg = VM_PAGE_TO_MD(pg); pv_entry_t pv = &mdpg->mdpg_first; pv_entry_t pv_next; - uint16_t gen; UVMHIST_FUNC(__func__); UVMHIST_CALLED(pmaphist); UVMHIST_LOG(pmaphist, "(pg=%p (%#"PRIxPADDR"))", @@ -1423,11 +1642,11 @@ pmap_clear_modify(struct vm_page *pg) } } if (!pmap_page_clear_attributes(mdpg, VM_PAGEMD_MODIFIED)) { - UVMHIST_LOG(pmaphist, "<- false", 0,0,0,0); + UVMHIST_LOG(pmaphist, " <-- false", 0, 0, 0, 0); return false; } if (pv->pv_pmap == NULL) { - UVMHIST_LOG(pmaphist, "<- true (no mappings)", 0,0,0,0); + UVMHIST_LOG(pmaphist, " <-- true (no mappings)", 0, 0, 0, 0); return true; } @@ -1437,35 +1656,44 @@ pmap_clear_modify(struct vm_page *pg) * flush the VAC first if there is one. */ kpreempt_disable(); - gen = VM_PAGEMD_PVLIST_LOCK(mdpg, false); + KASSERT(!VM_PAGEMD_PVLIST_LOCKED_P(mdpg)); + VM_PAGEMD_PVLIST_READLOCK(mdpg); + pmap_pvlist_check(mdpg); for (; pv != NULL; pv = pv_next) { pmap_t pmap = pv->pv_pmap; - vaddr_t va = pv->pv_va; + vaddr_t va = trunc_page(pv->pv_va); + + pv_next = pv->pv_next; +#ifdef PMAP_VIRTUAL_CACHE_ALIASES + if (pv->pv_va & PV_KENTER) + continue; +#endif pt_entry_t * const ptep = pmap_pte_lookup(pmap, va); KASSERT(ptep); - pv_next = pv->pv_next; - pt_entry_t pt_entry = pte_prot_nowrite(*ptep); - if (*ptep == pt_entry) { + pt_entry_t pte = pte_prot_nowrite(*ptep); + if (*ptep == pte) { continue; } - pmap_md_vca_clean(pg, va, PMAP_WBINV); + KASSERT(pte_valid_p(pte)); + const uintptr_t gen = VM_PAGEMD_PVLIST_UNLOCK(mdpg); pmap_md_tlb_miss_lock_enter(); - *ptep = pt_entry; - VM_PAGEMD_PVLIST_UNLOCK(mdpg); + *ptep = pte; pmap_tlb_invalidate_addr(pmap, va); pmap_md_tlb_miss_lock_exit(); pmap_update(pmap); - if (__predict_false(gen != VM_PAGEMD_PVLIST_LOCK(mdpg, false))) { + if (__predict_false(gen != VM_PAGEMD_PVLIST_READLOCK(mdpg))) { /* * The list changed! So restart from the beginning. */ pv_next = &mdpg->mdpg_first; + pmap_pvlist_check(mdpg); } } + pmap_pvlist_check(mdpg); VM_PAGEMD_PVLIST_UNLOCK(mdpg); kpreempt_enable(); - UVMHIST_LOG(pmaphist, "<- true (mappings changed)", 0,0,0,0); + UVMHIST_LOG(pmaphist, " <-- true (mappings changed)", 0, 0, 0, 0); return true; } @@ -1478,7 +1706,6 @@ pmap_clear_modify(struct vm_page *pg) bool pmap_is_modified(struct vm_page *pg) { - return VM_PAGEMD_MODIFIED_P(VM_PAGE_TO_MD(pg)); } @@ -1498,17 +1725,31 @@ pmap_set_modified(paddr_t pa) /******************** pv_entry management ********************/ static void -pmap_check_pvlist(struct vm_page *pg) +pmap_pvlist_check(struct vm_page_md *mdpg) { -#ifdef PARANOIADIAG - struct vm_page_md * const mdpg = VM_PAGE_TO_MD(pg); - pt_entry_t pv = &mdpg->mdpg_first; +#ifdef DEBUG + pv_entry_t pv = &mdpg->mdpg_first; if (pv->pv_pmap != NULL) { +#ifdef PMAP_VIRTUAL_CACHE_ALIASES + const u_int colormask = uvmexp.colormask; + u_int colors = 0; +#endif for (; pv != NULL; pv = pv->pv_next) { - KASSERT(!pmap_md_direct_mapped_vaddr_p(pv->pv_va)); + KASSERT(pv->pv_pmap != pmap_kernel() || !pmap_md_direct_mapped_vaddr_p(pv->pv_va)); +#ifdef PMAP_VIRTUAL_CACHE_ALIASES + colors |= __BIT(atop(pv->pv_va) & colormask); +#endif } +#ifdef PMAP_VIRTUAL_CACHE_ALIASES + // Assert there if there more than 1 color mapped, that they + // are uncached. + KASSERTMSG(!pmap_md_virtual_cache_aliasing_p() + || colors == 0 || (colors & (colors-1)) == 0 + || VM_PAGEMD_UNCACHED_P(mdpg), "colors=%#x uncached=%u", + colors, VM_PAGEMD_UNCACHED_P(mdpg)); +#endif } -#endif /* PARANOIADIAG */ +#endif /* DEBUG */ } /* @@ -1516,27 +1757,32 @@ pmap_check_pvlist(struct vm_page *pg) * physical to virtual map table. */ void -pmap_enter_pv(pmap_t pmap, vaddr_t va, struct vm_page *pg, u_int *npte) +pmap_enter_pv(pmap_t pmap, vaddr_t va, struct vm_page *pg, pt_entry_t *nptep, + u_int flags) { struct vm_page_md * const mdpg = VM_PAGE_TO_MD(pg); pv_entry_t pv, npv, apv; - int16_t gen; - bool first __unused = false; +#ifdef UVMHIST + bool first = false; +#endif UVMHIST_FUNC(__func__); UVMHIST_CALLED(pmaphist); UVMHIST_LOG(pmaphist, "(pmap=%p va=%#"PRIxVADDR" pg=%p (%#"PRIxPADDR")", pmap, va, pg, VM_PAGE_TO_PHYS(pg)); - UVMHIST_LOG(pmaphist, "nptep=%p (%#x))", npte, *npte, 0, 0); + UVMHIST_LOG(pmaphist, "nptep=%p (%#"PRIxPTE"))", + nptep, pte_value(*nptep), 0, 0); KASSERT(kpreempt_disabled()); KASSERT(pmap != pmap_kernel() || !pmap_md_direct_mapped_vaddr_p(va)); + KASSERTMSG(pmap != pmap_kernel() || !pmap_md_io_vaddr_p(va), + "va %#"PRIxVADDR, va); apv = NULL; - pv = &mdpg->mdpg_first; - gen = VM_PAGEMD_PVLIST_LOCK(mdpg, true); - pmap_check_pvlist(pg); + VM_PAGEMD_PVLIST_LOCK(mdpg); again: + pv = &mdpg->mdpg_first; + pmap_pvlist_check(mdpg); if (pv->pv_pmap == NULL) { KASSERT(pv->pv_next == NULL); /* @@ -1544,15 +1790,25 @@ again: */ PMAP_COUNT(primary_mappings); PMAP_COUNT(mappings); +#ifdef UVMHIST first = true; -#ifdef __PMAP_VIRTUAL_CACHE_ALIASES - pmap_page_clear_attributes(pg, VM_PAGEMD_UNCACHED); +#endif +#ifdef PMAP_VIRTUAL_CACHE_ALIASES + KASSERT(VM_PAGEMD_CACHED_P(mdpg)); + // If the new mapping has an incompatible color the last + // mapping of this page, clean the page before using it. + if (!PMAP_PAGE_COLOROK_P(va, pv->pv_va)) { + pmap_md_vca_clean(pg, PMAP_WBINV); + } #endif pv->pv_pmap = pmap; - pv->pv_va = va; + pv->pv_va = va | flags; } else { - if (pmap_md_vca_add(pg, va, npte)) +#ifdef PMAP_VIRTUAL_CACHE_ALIASES + if (pmap_md_vca_add(pg, va, nptep)) { goto again; + } +#endif /* * There is at least one other VA mapping this page. @@ -1566,20 +1822,24 @@ again: const paddr_t pa = VM_PAGE_TO_PHYS(pg); #endif for (npv = pv; npv; npv = npv->pv_next) { - if (pmap == npv->pv_pmap && va == npv->pv_va) { + if (pmap == npv->pv_pmap + && va == trunc_page(npv->pv_va)) { #ifdef PARANOIADIAG pt_entry_t *ptep = pmap_pte_lookup(pmap, va); - pt_entry_t pt_entry = (ptep ? *ptep : 0); - if (!pte_valid_p(pt_entry) - || pte_to_paddr(pt_entry) != pa) - printf( - "pmap_enter_pv: found va %#"PRIxVADDR" pa %#"PRIxPADDR" in pv_table but != %x\n", - va, pa, pt_entry); + pt_entry_t pte = (ptep != NULL) ? *ptep : 0; + if (!pte_valid_p(pte) || pte_to_paddr(pte) != pa) + printf("%s: found va %#"PRIxVADDR + " pa %#"PRIxPADDR + " in pv_table but != %#"PRIxPTE"\n", + __func__, va, pa, pte_value(pte)); #endif PMAP_COUNT(remappings); VM_PAGEMD_PVLIST_UNLOCK(mdpg); if (__predict_false(apv != NULL)) pmap_pv_free(apv); + + UVMHIST_LOG(pmaphist, " <-- done pv=%p%s", + pv, " (reused)", 0, 0); return; } } @@ -1587,9 +1847,10 @@ again: /* * To allocate a PV, we have to release the PVLIST lock * so get the page generation. We allocate the PV, and - * then reacquire the lock. + * then reacquire the lock. */ - VM_PAGEMD_PVLIST_UNLOCK(mdpg); + pmap_pvlist_check(mdpg); + const uintptr_t gen = VM_PAGEMD_PVLIST_UNLOCK(mdpg); apv = (pv_entry_t)pmap_pv_alloc(); if (apv == NULL) @@ -1597,28 +1858,39 @@ again: /* * If the generation has changed, then someone else - * tinkered with this page so we should - * start over. + * tinkered with this page so we should start over. */ - uint16_t oldgen = gen; - gen = VM_PAGEMD_PVLIST_LOCK(mdpg, true); - if (gen != oldgen) + if (gen != VM_PAGEMD_PVLIST_LOCK(mdpg)) goto again; } npv = apv; apv = NULL; - npv->pv_va = va; +#ifdef PMAP_VIRTUAL_CACHE_ALIASES + /* + * If need to deal with virtual cache aliases, keep mappings + * in the kernel pmap at the head of the list. This allows + * the VCA code to easily use them for cache operations if + * present. + */ + pmap_t kpmap = pmap_kernel(); + if (pmap != kpmap) { + while (pv->pv_pmap == kpmap && pv->pv_next != NULL) { + pv = pv->pv_next; + } + } +#endif + npv->pv_va = va | flags; npv->pv_pmap = pmap; npv->pv_next = pv->pv_next; pv->pv_next = npv; PMAP_COUNT(mappings); } - pmap_check_pvlist(pg); + pmap_pvlist_check(mdpg); VM_PAGEMD_PVLIST_UNLOCK(mdpg); if (__predict_false(apv != NULL)) pmap_pv_free(apv); - UVMHIST_LOG(pmaphist, "<- done pv=%p%s", + UVMHIST_LOG(pmaphist, " <-- done pv=%p%s", pv, first ? " (first pv)" : "",0,0); } @@ -1638,15 +1910,16 @@ pmap_remove_pv(pmap_t pmap, vaddr_t va, UVMHIST_FUNC(__func__); UVMHIST_CALLED(pmaphist); UVMHIST_LOG(pmaphist, - "(pmap=%p va=%#"PRIxVADDR" pg=%p (pa %#"PRIxPADDR")\n", + "(pmap=%p, va=%#"PRIxVADDR", pg=%p (pa %#"PRIxPADDR")", pmap, va, pg, VM_PAGE_TO_PHYS(pg)); - UVMHIST_LOG(pmaphist, "dirty=%s)", dirty ? "true" : "false", 0,0,0); + UVMHIST_LOG(pmaphist, "dirty=%s)", dirty ? "true" : "false", 0, 0, 0); KASSERT(kpreempt_disabled()); + KASSERT((va & PAGE_MASK) == 0); pv = &mdpg->mdpg_first; - (void)VM_PAGEMD_PVLIST_LOCK(mdpg, true); - pmap_check_pvlist(pg); + VM_PAGEMD_PVLIST_LOCK(mdpg); + pmap_pvlist_check(mdpg); /* * If it is the first entry on the list, it is actually @@ -1656,14 +1929,14 @@ pmap_remove_pv(pmap_t pmap, vaddr_t va, */ last = false; - if (pmap == pv->pv_pmap && va == pv->pv_va) { + if (pmap == pv->pv_pmap && va == trunc_page(pv->pv_va)) { npv = pv->pv_next; if (npv) { *pv = *npv; KASSERT(pv->pv_pmap != NULL); } else { -#ifdef __PMAP_VIRTUAL_CACHE_ALIASES - pmap_page_clear_attributes(pg, VM_PAGEMD_UNCACHED); +#ifdef PMAP_VIRTUAL_CACHE_ALIASES + pmap_page_clear_attributes(mdpg, VM_PAGEMD_UNCACHED); #endif pv->pv_pmap = NULL; last = true; /* Last mapping removed */ @@ -1672,18 +1945,21 @@ pmap_remove_pv(pmap_t pmap, vaddr_t va, } else { for (npv = pv->pv_next; npv; pv = npv, npv = npv->pv_next) { PMAP_COUNT(remove_pvsearch); - if (pmap == npv->pv_pmap && va == npv->pv_va) + if (pmap == npv->pv_pmap && va == trunc_page(npv->pv_va)) break; } if (npv) { pv->pv_next = npv->pv_next; } } - pmap_md_vca_remove(pg, va); - pmap_check_pvlist(pg); + pmap_pvlist_check(mdpg); VM_PAGEMD_PVLIST_UNLOCK(mdpg); +#ifdef PMAP_VIRTUAL_CACHE_ALIASES + pmap_md_vca_remove(pg, va, dirty, last); +#endif + /* * Free the pv_entry if needed. */ @@ -1716,7 +1992,8 @@ pmap_remove_pv(pmap_t pmap, vaddr_t va, PMAP_COUNT(exec_synced_remove); } } - UVMHIST_LOG(pmaphist, "<- done", 0,0,0,0); + + UVMHIST_LOG(pmaphist, " <-- done", 0, 0, 0, 0); } #if defined(MULTIPROCESSOR) @@ -1743,18 +2020,17 @@ pmap_pvlist_lock_init(size_t cache_line_ */ for (size_t i = 0; i < nlocks; lock_va += cache_line_size, i++) { kmutex_t * const lock = (kmutex_t *)lock_va; - mutex_init(lock, MUTEX_DEFAULT, IPL_VM); + mutex_init(lock, MUTEX_DEFAULT, IPL_HIGH); pli->pli_locks[i] = lock; } pli->pli_lock_mask = nlocks - 1; } -uint16_t -pmap_pvlist_lock(struct vm_page_md *mdpg, bool list_change) +kmutex_t * +pmap_pvlist_lock_addr(struct vm_page_md *mdpg) { struct pmap_pvlist_info * const pli = &pmap_pvlist_info; kmutex_t *lock = mdpg->mdpg_lock; - int16_t gen; /* * Allocate a lock on an as-needed basis. This will hopefully give us @@ -1776,33 +2052,20 @@ pmap_pvlist_lock(struct vm_page_md *mdpg } /* - * Now finally lock the pvlists. + * Now finally provide the lock. */ - mutex_spin_enter(lock); - - /* - * If the locker will be changing the list, increment the high 16 bits - * of attrs so we use that as a generation number. - */ - gen = VM_PAGEMD_PVLIST_GEN(mdpg); /* get old value */ - if (list_change) - atomic_add_int(&mdpg->mdpg_attrs, 0x10000); - - /* - * Return the generation number. - */ - return gen; + return lock; } #else /* !MULTIPROCESSOR */ void pmap_pvlist_lock_init(size_t cache_line_size) { - mutex_init(&pmap_pvlist_mutex, MUTEX_DEFAULT, IPL_VM); + mutex_init(&pmap_pvlist_mutex, MUTEX_DEFAULT, IPL_HIGH); } #ifdef MODULAR -uint16_t -pmap_pvlist_lock(struct vm_page_md *mdpg, bool list_change) +kmutex_t * +pmap_pvlist_lock_addr(struct vm_page_md *mdpg) { /* * We just use a global lock. @@ -1812,11 +2075,9 @@ pmap_pvlist_lock(struct vm_page_md *mdpg } /* - * Now finally lock the pvlists. + * Now finally provide the lock. */ - mutex_spin_enter(mdpg->mdpg_lock); - - return 0; + return mdpg->mdpg_lock; } #endif /* MODULAR */ #endif /* !MULTIPROCESSOR */ @@ -1829,7 +2090,7 @@ pmap_pvlist_lock(struct vm_page_md *mdpg void * pmap_pv_page_alloc(struct pool *pp, int flags) { - struct vm_page *pg = PMAP_ALLOC_POOLPAGE(UVM_PGA_USERESERVE); + struct vm_page * const pg = PMAP_ALLOC_POOLPAGE(UVM_PGA_USERESERVE); if (pg == NULL) return NULL; @@ -1849,9 +2110,13 @@ pmap_pv_page_free(struct pool *pp, void KASSERT(pmap_md_direct_mapped_vaddr_p(va)); const paddr_t pa = pmap_md_direct_mapped_vaddr_to_paddr(va); struct vm_page * const pg = PHYS_TO_VM_PAGE(pa); - struct vm_page_md * const mdpg = VM_PAGE_TO_MD(pg); - pmap_md_vca_remove(pg, va); - pmap_page_clear_attributes(mdpg, VM_PAGEMD_POOLPAGE); + KASSERT(pg != NULL); +#ifdef PMAP_VIRTUAL_CACHE_ALIASES + kpreempt_disable(); + pmap_md_vca_remove(pg, va, true, true); + kpreempt_enable(); +#endif + pmap_page_clear_attributes(VM_PAGE_TO_MD(pg), VM_PAGEMD_POOLPAGE); uvm_pagefree(pg); } @@ -1863,8 +2128,6 @@ pmap_pv_page_free(struct pool *pp, void void pmap_prefer(vaddr_t foff, vaddr_t *vap, vsize_t sz, int td) { - vaddr_t va; - vsize_t d; vsize_t prefer_mask = ptoa(uvmexp.colormask); PMAP_COUNT(prefer_requests); @@ -1872,13 +2135,11 @@ pmap_prefer(vaddr_t foff, vaddr_t *vap, prefer_mask |= pmap_md_cache_prefer_mask(); if (prefer_mask) { - va = *vap; - - d = foff - va; - d &= prefer_mask; + vaddr_t va = *vap; + vsize_t d = (foff - va) & prefer_mask; if (d) { if (td) - *vap = trunc_page(va -((-d) & prefer_mask)); + *vap = trunc_page(va - ((-d) & prefer_mask)); else *vap = round_page(va + d); PMAP_COUNT(prefer_adjustments); @@ -1891,30 +2152,24 @@ pmap_prefer(vaddr_t foff, vaddr_t *vap, vaddr_t pmap_map_poolpage(paddr_t pa) { - struct vm_page * const pg = PHYS_TO_VM_PAGE(pa); KASSERT(pg); struct vm_page_md * const mdpg = VM_PAGE_TO_MD(pg); pmap_page_set_attributes(mdpg, VM_PAGEMD_POOLPAGE); - const vaddr_t va = pmap_md_map_poolpage(pa, NBPG); - pmap_md_vca_add(pg, va, NULL); - return va; + return pmap_md_map_poolpage(pa, NBPG); } paddr_t pmap_unmap_poolpage(vaddr_t va) { - KASSERT(pmap_md_direct_mapped_vaddr_p(va)); paddr_t pa = pmap_md_direct_mapped_vaddr_to_paddr(va); struct vm_page * const pg = PHYS_TO_VM_PAGE(pa); - KASSERT(pg); - struct vm_page_md * const mdpg = VM_PAGE_TO_MD(pg); - pmap_page_clear_attributes(mdpg, VM_PAGEMD_POOLPAGE); + KASSERT(pg != NULL); + pmap_page_clear_attributes(VM_PAGE_TO_MD(pg), VM_PAGEMD_POOLPAGE); pmap_md_unmap_poolpage(va, NBPG); - pmap_md_vca_remove(pg, va); return pa; } Index: src/sys/uvm/pmap/pmap.h diff -u src/sys/uvm/pmap/pmap.h:1.6 src/sys/uvm/pmap/pmap.h:1.7 --- src/sys/uvm/pmap/pmap.h:1.6 Thu Jul 7 06:55:44 2016 +++ src/sys/uvm/pmap/pmap.h Mon Jul 11 16:06:09 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: pmap.h,v 1.6 2016/07/07 06:55:44 msaitoh Exp $ */ +/* $NetBSD: pmap.h,v 1.7 2016/07/11 16:06:09 matt Exp $ */ /* * Copyright (c) 1992, 1993 @@ -152,6 +152,15 @@ struct pmap_limits { vaddr_t virtual_end; }; +/* + * Initialize the kernel pmap. + */ +#ifdef MULTIPROCESSOR +#define PMAP_SIZE offsetof(struct pmap, pm_pai[PMAP_TLB_MAX]) +#else +#define PMAP_SIZE sizeof(struct pmap) +#endif + /* * The pools from which pmap structures and sub-structures are allocated. */ @@ -162,6 +171,10 @@ extern struct pool_allocator pmap_pv_pag extern struct pmap_kernel kernel_pmap_store; extern struct pmap_limits pmap_limits; +extern u_int pmap_page_colormask; + +extern pmap_segtab_t pmap_kern_segtab; + #define pmap_wired_count(pmap) ((pmap)->pm_stats.wired_count) #define pmap_resident_count(pmap) ((pmap)->pm_stats.resident_count) @@ -173,12 +186,17 @@ void pmap_set_modified(paddr_t); bool pmap_page_clear_attributes(struct vm_page_md *, u_int); void pmap_page_set_attributes(struct vm_page_md *, u_int); void pmap_pvlist_lock_init(size_t); +#ifdef PMAP_VIRTUAL_CACHE_ALIASES +void pmap_page_cache(struct vm_page *, bool cached); +#endif + #define PMAP_WB 0 #define PMAP_WBINV 1 #define PMAP_INV 2 -uint16_t pmap_pvlist_lock(struct vm_page_md *, bool); +//uint16_t pmap_pvlist_lock(struct vm_page_md *, bool); +kmutex_t *pmap_pvlist_lock_addr(struct vm_page_md *); #define PMAP_STEAL_MEMORY /* enable pmap_steal_memory() */ #define PMAP_GROWKERNEL /* enable pmap_growkernel() */ @@ -193,5 +211,11 @@ struct vm_page *pmap_md_alloc_poolpage(i #define PMAP_MAP_POOLPAGE(pa) pmap_map_poolpage(pa) #define PMAP_UNMAP_POOLPAGE(va) pmap_unmap_poolpage(va) +#define PMAP_COUNT(name) (pmap_evcnt_##name.ev_count++ + 0) +#define PMAP_COUNTER(name, desc) \ +struct evcnt pmap_evcnt_##name = \ + EVCNT_INITIALIZER(EVCNT_TYPE_MISC, NULL, "pmap", desc); \ +EVCNT_ATTACH_STATIC(pmap_evcnt_##name) + #endif /* _KERNEL */ #endif /* _COMMON_PMAP_H_ */ Index: src/sys/uvm/pmap/pmap_segtab.c diff -u src/sys/uvm/pmap/pmap_segtab.c:1.2 src/sys/uvm/pmap/pmap_segtab.c:1.3 --- src/sys/uvm/pmap/pmap_segtab.c:1.2 Thu Jun 11 08:04:44 2015 +++ src/sys/uvm/pmap/pmap_segtab.c Mon Jul 11 16:06:09 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: pmap_segtab.c,v 1.2 2015/06/11 08:04:44 matt Exp $ */ +/* $NetBSD: pmap_segtab.c,v 1.3 2016/07/11 16:06:09 matt Exp $ */ /*- * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc. @@ -67,7 +67,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: pmap_segtab.c,v 1.2 2015/06/11 08:04:44 matt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pmap_segtab.c,v 1.3 2016/07/11 16:06:09 matt Exp $"); /* * Manages physical address maps. @@ -346,16 +346,17 @@ void pmap_segtab_activate(struct pmap *pm, struct lwp *l) { if (l == curlwp) { + struct cpu_info * const ci = l->l_cpu; KASSERT(pm == l->l_proc->p_vmspace->vm_map.pmap); if (pm == pmap_kernel()) { - l->l_cpu->ci_pmap_user_segtab = (void*)0xdeadbabe; + ci->ci_pmap_user_segtab = PMAP_INVALID_SEGTAB_ADDRESS; #ifdef _LP64 - l->l_cpu->ci_pmap_user_seg0tab = (void*)0xdeadbabe; + ci->ci_pmap_user_seg0tab = PMAP_INVALID_SEGTAB_ADDRESS; #endif } else { - l->l_cpu->ci_pmap_user_segtab = pm->pm_segtab; + ci->ci_pmap_user_segtab = pm->pm_segtab; #ifdef _LP64 - l->l_cpu->ci_pmap_user_seg0tab = pm->pm_segtab->seg_seg[0]; + ci->ci_pmap_user_seg0tab = pm->pm_segtab->seg_seg[0]; #endif } } Index: src/sys/uvm/pmap/pmap_synci.c diff -u src/sys/uvm/pmap/pmap_synci.c:1.2 src/sys/uvm/pmap/pmap_synci.c:1.3 --- src/sys/uvm/pmap/pmap_synci.c:1.2 Tue Jul 2 09:35:48 2013 +++ src/sys/uvm/pmap/pmap_synci.c Mon Jul 11 16:06:09 2016 @@ -29,7 +29,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: pmap_synci.c,v 1.2 2013/07/02 09:35:48 matt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pmap_synci.c,v 1.3 2016/07/11 16:06:09 matt Exp $"); #define __PMAP_PRIVATE @@ -44,8 +44,11 @@ __KERNEL_RCSID(0, "$NetBSD: pmap_synci.c #include <uvm/uvm.h> #if defined(MULTIPROCESSOR) +u_int pmap_tlb_synci_page_mask; +u_int pmap_tlb_synci_map_mask; + void -pmap_syncicache_ast(struct cpu_info *ci) +pmap_tlb_syncicache_ast(struct cpu_info *ci) { struct pmap_tlb_info * const ti = cpu_tlb_info(ci); @@ -63,7 +66,6 @@ pmap_syncicache_ast(struct cpu_info *ci) pmap_md_icache_sync_all(); ti->ti_evcnt_synci_all.ev_count++; ti->ti_evcnt_synci_pages.ev_count += pmap_tlb_synci_page_mask+1; - kpreempt_enable(); return; } @@ -81,12 +83,10 @@ pmap_syncicache_ast(struct cpu_info *ci) ti->ti_evcnt_synci_pages.ev_count++; } } - - kpreempt_enable(); } void -pmap_tlb_syncicache(vaddr_t va, uint32_t page_onproc) +pmap_tlb_syncicache(vaddr_t va, const kcpuset_t *page_onproc) { KASSERT(kpreempt_disabled()); /* @@ -108,10 +108,11 @@ pmap_tlb_syncicache(vaddr_t va, uint32_t * then become equal but that's a one in 4 billion cache and will * just cause an extra sync of the icache. */ - const uint32_t cpu_mask = 1L << cpu_index(curcpu()); + struct cpu_info * const ci = curcpu(); + kcpuset_t *onproc; + kcpuset_create(&onproc, true); const uint32_t page_mask = 1L << ((va >> PGSHIFT) & pmap_tlb_synci_page_mask); - uint32_t onproc = 0; for (size_t i = 0; i < pmap_ntlbs; i++) { struct pmap_tlb_info * const ti = pmap_tlbs[i]; TLBINFO_LOCK(ti); @@ -128,7 +129,7 @@ pmap_tlb_syncicache(vaddr_t va, uint32_t if (orig_page_bitmap == old_page_bitmap) { if (old_page_bitmap == 0) { - onproc |= ti->ti_cpu_mask; + kcpuset_merge(onproc, ti->ti_kcpuset); } else { ti->ti_evcnt_synci_deferred.ev_count++; } @@ -143,20 +144,20 @@ pmap_tlb_syncicache(vaddr_t va, uint32_t #endif TLBINFO_UNLOCK(ti); } - onproc &= page_onproc; - if (__predict_false(onproc != 0)) { + kcpuset_intersect(onproc, page_onproc); + if (__predict_false(!kcpuset_iszero(onproc))) { /* * If the cpu need to sync this page, tell the current lwp * to sync the icache before it returns to userspace. */ - if (onproc & cpu_mask) { - if (curcpu()->ci_flags & CPUF_USERPMAP) { + if (kcpuset_isset(onproc, cpu_index(ci))) { + if (ci->ci_flags & CPUF_USERPMAP) { curlwp->l_md.md_astpending = 1; /* force call to ast() */ - curcpu()->ci_evcnt_synci_onproc_rqst.ev_count++; + ci->ci_evcnt_synci_onproc_rqst.ev_count++; } else { - curcpu()->ci_evcnt_synci_deferred_rqst.ev_count++; + ci->ci_evcnt_synci_deferred_rqst.ev_count++; } - onproc ^= cpu_mask; + kcpuset_clear(onproc, cpu_index(ci)); } /* @@ -165,12 +166,14 @@ pmap_tlb_syncicache(vaddr_t va, uint32_t * We might cause some spurious icache syncs but that's not * going to break anything. */ - for (u_int n = ffs(onproc); - onproc != 0; - onproc >>= n, onproc <<= n, n = ffs(onproc)) { - cpu_send_ipi(cpu_lookup(n-1), IPI_SYNCICACHE); + for (cpuid_t n = kcpuset_ffs(onproc); + n-- > 0; + n = kcpuset_ffs(onproc)) { + kcpuset_clear(onproc, n); + cpu_send_ipi(cpu_lookup(n), IPI_SYNCICACHE); } } + kcpuset_destroy(onproc); } void Index: src/sys/uvm/pmap/tlb.h diff -u src/sys/uvm/pmap/tlb.h:1.2 src/sys/uvm/pmap/tlb.h:1.3 --- src/sys/uvm/pmap/tlb.h:1.2 Mon Sep 21 15:50:19 2015 +++ src/sys/uvm/pmap/tlb.h Mon Jul 11 16:06:09 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: tlb.h,v 1.2 2015/09/21 15:50:19 matt Exp $ */ +/* $NetBSD: tlb.h,v 1.3 2016/07/11 16:06:09 matt Exp $ */ /*- * Copyright (c) 2011 The NetBSD Foundation, Inc. * All rights reserved. @@ -34,6 +34,8 @@ struct tlbmask; +typedef bool (*tlb_walkfunc_t)(void *, vaddr_t, tlb_asid_t, pt_entry_t); + struct tlb_md_ops { void (*md_tlb_set_asid)(tlb_asid_t); tlb_asid_t @@ -45,10 +47,9 @@ struct tlb_md_ops { bool (*md_tlb_update_addr)(vaddr_t, tlb_asid_t, pt_entry_t, bool); void (*md_tlb_read_entry)(size_t, struct tlbmask *); void (*md_tlb_write_entry)(size_t, const struct tlbmask *); - u_int (*md_tlb_record_asids)(u_long *); + u_int (*md_tlb_record_asids)(u_long *, tlb_asid_t); void (*md_tlb_dump)(void (*)(const char *, ...)); - void (*md_tlb_walk)(void *, bool (*)(void *, vaddr_t, tlb_asid_t, - pt_entry_t)); + void (*md_tlb_walk)(void *, tlb_walkfunc_t); }; tlb_asid_t @@ -59,11 +60,11 @@ void tlb_invalidate_globals(void); void tlb_invalidate_asids(tlb_asid_t, tlb_asid_t); void tlb_invalidate_addr(vaddr_t, tlb_asid_t); bool tlb_update_addr(vaddr_t, tlb_asid_t, pt_entry_t, bool); -u_int tlb_record_asids(u_long *); +u_int tlb_record_asids(u_long *, tlb_asid_t); void tlb_enter_addr(size_t, const struct tlbmask *); void tlb_read_entry(size_t, struct tlbmask *); void tlb_write_entry(size_t, const struct tlbmask *); -void tlb_walk(void *, bool (*)(void *, vaddr_t, tlb_asid_t, pt_entry_t)); +void tlb_walk(void *, tlb_walkfunc_t); void tlb_dump(void (*)(const char *, ...)); #endif /* _KERNEL || _KMEMUSER */ Index: src/sys/uvm/pmap/vmpagemd.h diff -u src/sys/uvm/pmap/vmpagemd.h:1.2 src/sys/uvm/pmap/vmpagemd.h:1.3 --- src/sys/uvm/pmap/vmpagemd.h:1.2 Tue Mar 4 06:14:53 2014 +++ src/sys/uvm/pmap/vmpagemd.h Mon Jul 11 16:06:09 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: vmpagemd.h,v 1.2 2014/03/04 06:14:53 matt Exp $ */ +/* $NetBSD: vmpagemd.h,v 1.3 2016/07/11 16:06:09 matt Exp $ */ /*- * Copyright (c) 2011 The NetBSD Foundation, Inc. @@ -42,15 +42,16 @@ #error use assym.h instead #endif -#ifdef _MODULE -#error this file should not be included by loadable kernel modules -#endif +//#ifdef _MODULE +//#error this file should not be included by loadable kernel modules +//#endif #ifdef _KERNEL_OPT #include "opt_modular.h" #include "opt_multiprocessor.h" #endif +#include <sys/atomic.h> #include <sys/mutex.h> #define __HAVE_VM_PAGE_MD @@ -59,17 +60,20 @@ typedef struct pv_entry { struct pv_entry *pv_next; struct pmap *pv_pmap; vaddr_t pv_va; +#define PV_KENTER 0x0001 } *pv_entry_t; +#ifndef _MODULE + #define VM_PAGEMD_REFERENCED 0x0001 /* page has been recently referenced */ #define VM_PAGEMD_MODIFIED 0x0002 /* page has been modified */ #define VM_PAGEMD_POOLPAGE 0x0004 /* page is used as a poolpage */ #define VM_PAGEMD_EXECPAGE 0x0008 /* page is exec mapped */ -#ifdef __PMAP_VIRTUAL_CACHE_ALIASES +#ifdef PMAP_VIRTUAL_CACHE_ALIASES #define VM_PAGEMD_UNCACHED 0x0010 /* page is mapped uncached */ #endif -#ifdef __PMAP_VIRTUAL_CACHE_ALIASES +#ifdef PMAP_VIRTUAL_CACHE_ALIASES #define VM_PAGEMD_CACHED_P(mdpg) (((mdpg)->mdpg_attrs & VM_PAGEMD_UNCACHED) == 0) #define VM_PAGEMD_UNCACHED_P(mdpg) (((mdpg)->mdpg_attrs & VM_PAGEMD_UNCACHED) != 0) #endif @@ -78,29 +82,70 @@ typedef struct pv_entry { #define VM_PAGEMD_POOLPAGE_P(mdpg) (((mdpg)->mdpg_attrs & VM_PAGEMD_POOLPAGE) != 0) #define VM_PAGEMD_EXECPAGE_P(mdpg) (((mdpg)->mdpg_attrs & VM_PAGEMD_EXECPAGE) != 0) +#endif /* !_MODULE */ + struct vm_page_md { - volatile u_int mdpg_attrs; /* page attributes */ + volatile unsigned long mdpg_attrs; /* page attributes */ struct pv_entry mdpg_first; /* pv_entry first */ -#if defined(MULTIPROCESSOR) || defined(MODULAR) +#if defined(MULTIPROCESSOR) || defined(MODULAR) || defined(_MODULE) kmutex_t *mdpg_lock; /* pv list lock */ +#endif +}; + +#ifndef _MODULE +#if defined(MULTIPROCESSOR) || defined(MODULAR) #define VM_PAGEMD_PVLIST_LOCK_INIT(mdpg) \ (mdpg)->mdpg_lock = NULL -#define VM_PAGEMD_PVLIST_LOCK(pg, list_change) \ - pmap_pvlist_lock(mdpg, list_change) +#else +#define VM_PAGEMD_PVLIST_LOCK_INIT(mdpg) do { } while (/*CONSTCOND*/ 0) +#endif /* MULTIPROCESSOR || MODULAR */ + +#define VM_PAGEMD_PVLIST_LOCK(mdpg) \ + pmap_pvlist_lock(mdpg, 1) +#define VM_PAGEMD_PVLIST_READLOCK(mdpg) \ + pmap_pvlist_lock(mdpg, 0) #define VM_PAGEMD_PVLIST_UNLOCK(mdpg) \ - mutex_spin_exit((mdpg)->mdpg_lock) + pmap_pvlist_unlock(mdpg) #define VM_PAGEMD_PVLIST_LOCKED_P(mdpg) \ - mutex_owner((mdpg)->mdpg_lock) + pmap_pvlist_locked_p(mdpg) #define VM_PAGEMD_PVLIST_GEN(mdpg) \ - ((uint16_t)((mdpg)->mdpg_attrs >> 16)) + ((mdpg)->mdpg_attrs >> 16) + +#ifdef _KERNEL +#if defined(MULTIPROCESSOR) || defined(MODULAR) +kmutex_t *pmap_pvlist_lock_addr(struct vm_page_md *); #else -#define VM_PAGEMD_PVLIST_LOCK_INIT(mdpg) do { } while (/*CONSTCOND*/ 0) -#define VM_PAGEMD_PVLIST_LOCK(mdpg, lc) (mutex_spin_enter(&pmap_pvlist_mutex), 0) -#define VM_PAGEMD_PVLIST_UNLOCK(mdpg) mutex_spin_exit(&pmap_pvlist_mutex) -#define VM_PAGEMD_PVLIST_LOCKED_P(mdpg) true -#define VM_PAGEMD_PVLIST_GEN(mdpg) (0) -#endif /* MULTIPROCESSOR || MODULAR */ -}; +extern kmutex_t pmap_pvlist_mutex; +static inline kmutex_t * +pmap_pvlist_lock_addr(struct vm_page_md *mdpg) +{ + return &pmap_pvlist_mutex; +} +#endif + +static inline uintptr_t +pmap_pvlist_lock(struct vm_page_md *mdpg, uintptr_t increment) +{ + mutex_spin_enter(pmap_pvlist_lock_addr(mdpg)); + const uintptr_t gen = VM_PAGEMD_PVLIST_GEN(mdpg); + mdpg->mdpg_attrs += increment << 16; + return gen; +} + +static inline uintptr_t +pmap_pvlist_unlock(struct vm_page_md *mdpg) +{ + const uintptr_t gen = VM_PAGEMD_PVLIST_GEN(mdpg); + mutex_spin_exit(pmap_pvlist_lock_addr(mdpg)); + return gen; +} + +static inline bool +pmap_pvlist_locked_p(struct vm_page_md *mdpg) +{ + return mutex_owned(pmap_pvlist_lock_addr(mdpg)); +} +#endif /* _KERNEL */ #define VM_MDPAGE_INIT(pg) \ do { \ @@ -111,4 +156,6 @@ do { \ VM_PAGEMD_PVLIST_LOCK_INIT(&(pg)->mdpage); \ } while (/* CONSTCOND */ 0) +#endif /* _MODULE */ + #endif /* __COMMON_PMAP_TLB_VMPAGEMD_H_ */ Index: src/sys/uvm/pmap/pmap_tlb.c diff -u src/sys/uvm/pmap/pmap_tlb.c:1.12 src/sys/uvm/pmap/pmap_tlb.c:1.13 --- src/sys/uvm/pmap/pmap_tlb.c:1.12 Thu Jun 11 05:28:42 2015 +++ src/sys/uvm/pmap/pmap_tlb.c Mon Jul 11 16:06:09 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: pmap_tlb.c,v 1.12 2015/06/11 05:28:42 matt Exp $ */ +/* $NetBSD: pmap_tlb.c,v 1.13 2016/07/11 16:06:09 matt Exp $ */ /*- * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -31,7 +31,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: pmap_tlb.c,v 1.12 2015/06/11 05:28:42 matt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pmap_tlb.c,v 1.13 2016/07/11 16:06:09 matt Exp $"); /* * Manages address spaces in a TLB. @@ -181,20 +181,6 @@ u_int pmap_ntlbs = 1; #define TLBINFO_ASID_INUSE_P(ti, asid) \ __BITMAP_ISSET_P((ti)->ti_asid_bitmap, (asid)) -static void -pmap_pai_check(struct pmap_tlb_info *ti) -{ -#ifdef DIAGNOSTIC - struct pmap_asid_info *pai; - LIST_FOREACH(pai, &ti->ti_pais, pai_link) { - KASSERT(pai != NULL); - KASSERT(PAI_PMAP(pai, ti) != pmap_kernel()); - KASSERT(pai->pai_asid > KERNEL_PID); - KASSERT(TLBINFO_ASID_INUSE_P(ti, pai->pai_asid)); - } -#endif -} - #ifdef MULTIPROCESSOR __unused static inline bool pmap_tlb_intersecting_active_p(pmap_t pm, struct pmap_tlb_info *ti) @@ -217,15 +203,41 @@ pmap_tlb_intersecting_onproc_p(pmap_t pm } #endif -static inline void -pmap_pai_reset(struct pmap_tlb_info *ti, struct pmap_asid_info *pai, +static void +pmap_tlb_pai_check(struct pmap_tlb_info *ti) +{ +#ifdef DIAGNOSTIC + struct pmap_asid_info *pai; + LIST_FOREACH(pai, &ti->ti_pais, pai_link) { + KASSERT(pai != NULL); + KASSERT(PAI_PMAP(pai, ti) != pmap_kernel()); + KASSERT(pai->pai_asid > KERNEL_PID); + KASSERTMSG(pai->pai_asid <= ti->ti_asid_max, + "pm %p asid %#x", PAI_PMAP(pai, ti), pai->pai_asid); + KASSERTMSG(TLBINFO_ASID_INUSE_P(ti, pai->pai_asid), + "pm %p asid %u", PAI_PMAP(pai, ti), pai->pai_asid); +#ifdef MULTIPROCESSOR + KASSERT(pmap_tlb_intersecting_active_p(PAI_PMAP(pai, ti), ti)); +#endif + } +#endif +} + +static void +pmap_tlb_pai_reset(struct pmap_tlb_info *ti, struct pmap_asid_info *pai, struct pmap *pm) { + UVMHIST_FUNC(__func__); UVMHIST_CALLED(maphist); + UVMHIST_LOG(maphist, "(ti=%p, pai=%p, pm=%p): asid %u", + ti, pai, pm, pai->pai_asid); + /* * We must have an ASID but it must not be onproc (on a processor). */ KASSERT(pai->pai_asid > KERNEL_PID); + KASSERT(pai->pai_asid <= ti->ti_asid_max); #if defined(MULTIPROCESSOR) + KASSERT(pmap_tlb_intersecting_active_p(pm, ti)); KASSERT(!pmap_tlb_intersecting_onproc_p(pm, ti)); #endif LIST_REMOVE(pai, pai_link); @@ -269,9 +281,12 @@ pmap_pai_reset(struct pmap_tlb_info *ti, #if PMAP_TLB_MAX == 1 kcpuset_zero(pm->pm_active); #else - kcpuset_atomicly_remove(pm->pm_active, ti->ti_kcpuset); + kcpuset_remove(pm->pm_active, ti->ti_kcpuset); #endif + KASSERT(!pmap_tlb_intersecting_active_p(pm, ti)); #endif /* MULTIPROCESSOR */ + + UVMHIST_LOG(maphist, " <-- done", 0, 0, 0, 0); } void @@ -394,7 +409,10 @@ pmap_tlb_asid_reinitialize(struct pmap_t const size_t asid_bitmap_words = ti->ti_asid_max / (8 * sizeof(ti->ti_asid_bitmap[0])); - pmap_pai_check(ti); + UVMHIST_FUNC(__func__); UVMHIST_CALLED(maphist); + UVMHIST_LOG(maphist, "(ti=%p, op=%u)", ti, op, 0, 0); + + pmap_tlb_pai_check(ti); ti->ti_evcnt_asid_reinits.ev_count++; @@ -410,14 +428,14 @@ pmap_tlb_asid_reinitialize(struct pmap_t } switch (op) { -#if defined(MULTIPROCESSOR) && defined(PMAP_NEED_TLB_SHOOTDOWN) +#if defined(MULTIPROCESSOR) && defined(PMAP_TLB_NEED_SHOOTDOWN) case TLBINV_ALL: tlb_invalidate_all(); break; case TLBINV_ALLUSER: tlb_invalidate_asids(KERNEL_PID + 1, ti->ti_asid_max); break; -#endif /* MULTIPROCESSOR && PMAP_NEED_TLB_SHOOTDOWN */ +#endif /* MULTIPROCESSOR && PMAP_TLB_NEED_SHOOTDOWN */ case TLBINV_NOBODY: { /* * If we are just reclaiming ASIDs in the TLB, let's go find @@ -428,14 +446,15 @@ pmap_tlb_asid_reinitialize(struct pmap_t * and clear the ASID bitmap. That will force everyone to * allocate a new ASID. */ -#if !defined(MULTIPROCESSOR) || defined(PMAP_NEED_TLB_SHOOTDOWN) +#if !defined(MULTIPROCESSOR) || defined(PMAP_TLB_NEED_SHOOTDOWN) pmap_tlb_asid_check(); - const u_int asids_found = tlb_record_asids(ti->ti_asid_bitmap); + const u_int asids_found = tlb_record_asids(ti->ti_asid_bitmap, + ti->ti_asid_max); pmap_tlb_asid_check(); KASSERT(asids_found == pmap_tlb_asid_count(ti)); if (__predict_false(asids_found >= ti->ti_asid_max / 2)) { tlb_invalidate_asids(KERNEL_PID + 1, ti->ti_asid_max); -#else /* MULTIPROCESSOR && !PMAP_NEED_TLB_SHOOTDOWN */ +#else /* MULTIPROCESSOR && !PMAP_TLB_NEED_SHOOTDOWN */ /* * For those systems (PowerPC) that don't require * cross cpu TLB shootdowns, we have to invalidate the @@ -446,7 +465,7 @@ pmap_tlb_asid_reinitialize(struct pmap_t * nightmare). */ tlb_invalidate_all(); -#endif /* MULTIPROCESSOR && !PMAP_NEED_TLB_SHOOTDOWN */ +#endif /* MULTIPROCESSOR && !PMAP_TLB_NEED_SHOOTDOWN */ ti->ti_asid_bitmap[0] = (2 << KERNEL_PID) - 1; for (size_t word = 1; word <= asid_bitmap_words; @@ -454,11 +473,11 @@ pmap_tlb_asid_reinitialize(struct pmap_t ti->ti_asid_bitmap[word] = 0; } ti->ti_asids_free = ti->ti_asid_max - KERNEL_PID; -#if !defined(MULTIPROCESSOR) || defined(PMAP_NEED_TLB_SHOOTDOWN) +#if !defined(MULTIPROCESSOR) || defined(PMAP_TLB_NEED_SHOOTDOWN) } else { ti->ti_asids_free -= asids_found; } -#endif /* !MULTIPROCESSOR || PMAP_NEED_TLB_SHOOTDOWN */ +#endif /* !MULTIPROCESSOR || PMAP_TLB_NEED_SHOOTDOWN */ KASSERTMSG(ti->ti_asids_free <= ti->ti_asid_max, "%u", ti->ti_asids_free); break; @@ -490,7 +509,7 @@ pmap_tlb_asid_reinitialize(struct pmap_t if (TLBINFO_ASID_INUSE_P(ti, pai->pai_asid)) { KASSERT(op == TLBINV_NOBODY); } else { - pmap_pai_reset(ti, pai, pm); + pmap_tlb_pai_reset(ti, pai, pm); } } #ifdef DIAGNOSTIC @@ -498,9 +517,10 @@ pmap_tlb_asid_reinitialize(struct pmap_t KASSERTMSG(free_count == ti->ti_asids_free, "bitmap error: %zu != %u", free_count, ti->ti_asids_free); #endif + UVMHIST_LOG(maphist, " <-- done", 0, 0, 0, 0); } -#if defined(MULTIPROCESSOR) && defined(PMAP_NEED_TLB_SHOOTDOWN) +#if defined(MULTIPROCESSOR) && defined(PMAP_TLB_NEED_SHOOTDOWN) #if PMAP_MAX_TLB == 1 #error shootdown not required for single TLB systems #endif @@ -527,7 +547,7 @@ pmap_tlb_shootdown_process(void) */ struct pmap_asid_info * const pai = PMAP_PAI(ti->ti_victim, ti); KASSERT(ti->ti_victim != pmap_kernel()); - if (!pmap_tlb_intersecting_onproc_p(ti_victim->pm_onproc, ti)) { + if (!pmap_tlb_intersecting_onproc_p(ti->ti_victim, ti)) { /* * The victim is an active pmap so we will just * invalidate its TLB entries. @@ -544,7 +564,7 @@ pmap_tlb_shootdown_process(void) * ASID. */ KASSERT(!pmap_tlb_intersecting_onproc_p(pm, ti)); - pmap_pai_reset(ti, pai, PAI_PMAP(pai, ti)); + pmap_tlb_pai_reset(ti, pai, PAI_PMAP(pai, ti)); } break; } @@ -610,11 +630,12 @@ pmap_tlb_shootdown_bystanders(pmap_t pm) /* * We don't need to deal our own TLB. */ - kcpuset_t *pm_active; + UVMHIST_FUNC(__func__); UVMHIST_CALLED(maphist); + + kcpuset_t *pm_active; kcpuset_clone(&pm_active, pm->pm_active); - kcpuset_atomicly_remove(pm->pm_active, - cpu_tlb_info(curcpu())->ti_kcpuset); + kcpuset_remove(pm_active, cpu_tlb_info(curcpu())->ti_kcpuset); const bool kernel_p = (pm == pmap_kernel()); bool ipi_sent = false; @@ -682,7 +703,7 @@ pmap_tlb_shootdown_bystanders(pmap_t pm) * And best of all, we avoid an IPI. */ KASSERT(!kernel_p); - pmap_pai_reset(ti, pai, pm); + pmap_tlb_pai_reset(ti, pai, pm); //ti->ti_evcnt_lazy_shots.ev_count++; } TLBINFO_UNLOCK(ti); @@ -690,32 +711,51 @@ pmap_tlb_shootdown_bystanders(pmap_t pm) kcpuset_destroy(pm_active); + UVMHIST_LOG(maphist, " <-- done (ipi_sent=%d)", ipi_sent, 0, 0, 0); + return ipi_sent; } -#endif /* MULTIPROCESSOR && PMAP_NEED_TLB_SHOOTDOWN */ +#endif /* MULTIPROCESSOR && PMAP_TLB_NEED_SHOOTDOWN */ #ifndef PMAP_TLB_HWPAGEWALKER int -pmap_tlb_update_addr(pmap_t pm, vaddr_t va, pt_entry_t pt_entry, u_int flags) +pmap_tlb_update_addr(pmap_t pm, vaddr_t va, pt_entry_t pte, u_int flags) { struct pmap_tlb_info * const ti = cpu_tlb_info(curcpu()); struct pmap_asid_info * const pai = PMAP_PAI(pm, ti); int rv = -1; + UVMHIST_FUNC(__func__); UVMHIST_CALLED(maphist); + UVMHIST_LOG(maphist, + " (pm=%p va=%#"PRIxVADDR", pte=%#"PRIxPTE" flags=%#x)", + pm, va, pte_value(pte), flags); + KASSERT(kpreempt_disabled()); + KASSERTMSG(pte_valid_p(pte), "va %#"PRIxVADDR" %#"PRIxPTE, + va, pte_value(pte)); + TLBINFO_LOCK(ti); if (pm == pmap_kernel() || PMAP_PAI_ASIDVALID_P(pai, ti)) { pmap_tlb_asid_check(); - rv = tlb_update_addr(va, pai->pai_asid, pt_entry, + rv = tlb_update_addr(va, pai->pai_asid, pte, (flags & PMAP_TLB_INSERT) != 0); pmap_tlb_asid_check(); - } -#if defined(MULTIPROCESSOR) && defined(PMAP_NEED_TLB_SHOOTDOWN) - pm->pm_shootdown_pending = (flags & PMAP_TLB_NEED_IPI) != 0; + UVMHIST_LOG(maphist, + " %d <-- tlb_update_addr(%#"PRIxVADDR", %#x, %#"PRIxPTE", ...)", + rv, va, pai->pai_asid, pte_value(pte)); + KASSERTMSG((flags & PMAP_TLB_INSERT) == 0 || rv == 1, + "pmap %p (asid %u) va %#"PRIxVADDR" pte %#"PRIxPTE" rv %d", + pm, pai->pai_asid, va, pte_value(pte), rv); + } +#if defined(MULTIPROCESSOR) && defined(PMAP_TLB_NEED_SHOOTDOWN) + if (flags & PMAP_TLB_NEED_IPI) + pm->pm_shootdown_pending = 1; #endif TLBINFO_UNLOCK(ti); + UVMHIST_LOG(maphist, " <-- done (rv=%d)", rv, 0, 0, 0); + return rv; } #endif /* !PMAP_TLB_HWPAGEWALKER */ @@ -727,21 +767,20 @@ pmap_tlb_invalidate_addr(pmap_t pm, vadd struct pmap_asid_info * const pai = PMAP_PAI(pm, ti); UVMHIST_FUNC(__func__); UVMHIST_CALLED(maphist); + UVMHIST_LOG(maphist, " (pm=%p va=%#"PRIxVADDR") ti=%p asid=%#x", + pm, va, ti, pai->pai_asid); KASSERT(kpreempt_disabled()); - UVMHIST_LOG(maphist, " (pm=%#x va=%#x) ti=%#x asid=%#x", - pm, va, ti, pai->pai_asid); - TLBINFO_LOCK(ti); if (pm == pmap_kernel() || PMAP_PAI_ASIDVALID_P(pai, ti)) { pmap_tlb_asid_check(); - UVMHIST_LOG(maphist, " invalidating %#x asid %#x", + UVMHIST_LOG(maphist, " invalidating %#"PRIxVADDR" asid %#x", va, pai->pai_asid, 0, 0); tlb_invalidate_addr(va, pai->pai_asid); pmap_tlb_asid_check(); } -#if defined(MULTIPROCESSOR) && defined(PMAP_NEED_TLB_SHOOTDOWN) +#if defined(MULTIPROCESSOR) && defined(PMAP_TLB_NEED_SHOOTDOWN) pm->pm_shootdown_pending = 1; #endif TLBINFO_UNLOCK(ti); @@ -836,7 +875,7 @@ pmap_tlb_asid_alloc(struct pmap_tlb_info #if PMAP_TLB_MAX == 1 kcpuset_copy(pm->pm_active, kcpuset_running); #else - kcpuset_atomicly_merge(pm->pm_active, ti->ti_kcpuset); + kcpuset_merge(pm->pm_active, ti->ti_kcpuset); #endif #endif } @@ -852,9 +891,10 @@ pmap_tlb_asid_acquire(pmap_t pm, struct struct pmap_tlb_info * const ti = cpu_tlb_info(ci); struct pmap_asid_info * const pai = PMAP_PAI(pm, ti); - KASSERT(kpreempt_disabled()); - UVMHIST_FUNC(__func__); UVMHIST_CALLED(maphist); + UVMHIST_LOG(maphist, "(pm=%p, l=%p, ti=%p)", pm, l, ti, 0); + + KASSERT(kpreempt_disabled()); /* * Kernels use a fixed ASID and thus doesn't need to acquire one. @@ -864,11 +904,10 @@ pmap_tlb_asid_acquire(pmap_t pm, struct return; } - UVMHIST_LOG(maphist, " (pm=%#x, l=%#x, ti=%#x)", pm, l, ti, 0); TLBINFO_LOCK(ti); KASSERT(pai->pai_asid <= KERNEL_PID || pai->pai_link.le_prev != NULL); KASSERT(pai->pai_asid > KERNEL_PID || pai->pai_link.le_prev == NULL); - pmap_pai_check(ti); + pmap_tlb_pai_check(ti); if (__predict_false(!PMAP_PAI_ASIDVALID_P(pai, ti))) { /* * If we've run out ASIDs, reinitialize the ASID space. @@ -886,6 +925,10 @@ pmap_tlb_asid_acquire(pmap_t pm, struct pmap_tlb_asid_alloc(ti, pm, pai); UVMHIST_LOG(maphist, "allocated asid %#x", pai->pai_asid, 0, 0, 0); } + pmap_tlb_pai_check(ti); +#if defined(MULTIPROCESSOR) + KASSERT(kcpuset_isset(pm->pm_active, cpu_index(ci))); +#endif if (l == curlwp) { #if defined(MULTIPROCESSOR) @@ -912,6 +955,7 @@ void pmap_tlb_asid_deactivate(pmap_t pm) { UVMHIST_FUNC(__func__); UVMHIST_CALLED(maphist); + KASSERT(kpreempt_disabled()); #if defined(MULTIPROCESSOR) /* @@ -935,8 +979,9 @@ pmap_tlb_asid_deactivate(pmap_t pm) } #endif curcpu()->ci_pmap_asid_cur = 0; - UVMHIST_LOG(maphist, " <-- done (pm=%#x)", pm, 0, 0, 0); + UVMHIST_LOG(maphist, " <-- done (pm=%p)", pm, 0, 0, 0); tlb_set_asid(KERNEL_PID); + pmap_tlb_pai_check(cpu_tlb_info(curcpu())); #if defined(DEBUG) pmap_tlb_asid_check(); #endif @@ -945,11 +990,15 @@ pmap_tlb_asid_deactivate(pmap_t pm) void pmap_tlb_asid_release_all(struct pmap *pm) { + UVMHIST_FUNC(__func__); UVMHIST_CALLED(maphist); + UVMHIST_LOG(maphist, "(pm=%p)", pm, 0, 0, 0); + KASSERT(pm != pmap_kernel()); #if defined(MULTIPROCESSOR) //KASSERT(!kcpuset_iszero(pm->pm_onproc)); // XXX -#if PMAP_TLB_MAX > 1 struct cpu_info * const ci __diagused = curcpu(); + KASSERT(!kcpuset_isotherset(pm->pm_onproc, cpu_index(ci))); +#if PMAP_TLB_MAX > 1 for (u_int i = 0; !kcpuset_iszero(pm->pm_active); i++) { KASSERT(i < pmap_ntlbs); struct pmap_tlb_info * const ti = pmap_tlbs[i]; @@ -960,31 +1009,25 @@ pmap_tlb_asid_release_all(struct pmap *p TLBINFO_LOCK(ti); if (PMAP_PAI_ASIDVALID_P(pai, ti)) { /* - * If this pmap isn't onproc on any of the cpus - * belonging to this tlb domain, we can just reset - * the ASID and be done. + * This pmap should not be in use by any other cpu so + * we can just reset and be happy. */ - if (!pmap_tlb_intersecting_onproc_p(pm, ti)) { - KASSERT(ti->ti_victim != pm); - pmap_pai_reset(ti, pai, pm); -#if PMAP_TLB_MAX == 1 - } else { - KASSERT(cpu_tlb_info(ci) == ti); - tlb_invalidate_asids(pai->pai_asid, - pai->pai_asid); -#else - } else if (cpu_tlb_info(ci) == ti) { - tlb_invalidate_asids(pai->pai_asid, - pai->pai_asid); - } else { - pm->pm_shootdown_needed = 1; -#endif - } + if (ti->ti_victim == pm) + ti->ti_victim = NULL; + pmap_tlb_pai_reset(ti, pai, pm); } + KASSERT(pai->pai_link.le_prev == NULL); TLBINFO_UNLOCK(ti); #if PMAP_TLB_MAX > 1 } #endif +#ifdef DIAGNOSTIC + for (size_t i = 0; i < (PMAP_TLB_MAX > 1 ? pmap_ntlbs : 1); i++) { + KASSERTMSG(pm->pm_pai[i].pai_asid == 0, + "pm %p i %zu asid %u", + pm, i, pm->pm_pai[i].pai_asid); + } +#endif #else /* * Handle the case of an UP kernel which only has, at most, one ASID. @@ -997,11 +1040,12 @@ pmap_tlb_asid_release_all(struct pmap *p if (curcpu()->ci_pmap_asid_cur == pai->pai_asid) { tlb_invalidate_asids(pai->pai_asid, pai->pai_asid); } else { - pmap_pai_reset(ti, pai, pm); + pmap_tlb_pai_reset(ti, pai, pm); } } TLBINFO_UNLOCK(ti); #endif /* MULTIPROCESSOR */ + UVMHIST_LOG(maphist, " <-- done", 0, 0, 0, 0); } void Index: src/sys/uvm/pmap/pmap_tlb.h diff -u src/sys/uvm/pmap/pmap_tlb.h:1.8 src/sys/uvm/pmap/pmap_tlb.h:1.9 --- src/sys/uvm/pmap/pmap_tlb.h:1.8 Thu Apr 2 06:17:52 2015 +++ src/sys/uvm/pmap/pmap_tlb.h Mon Jul 11 16:06:09 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: pmap_tlb.h,v 1.8 2015/04/02 06:17:52 matt Exp $ */ +/* $NetBSD: pmap_tlb.h,v 1.9 2016/07/11 16:06:09 matt Exp $ */ /* * Copyright (c) 1992, 1993 @@ -171,7 +171,7 @@ void pmap_tlb_info_evcnt_attach(struct p void pmap_tlb_asid_acquire(pmap_t, struct lwp *l); void pmap_tlb_asid_deactivate(pmap_t); void pmap_tlb_asid_release_all(pmap_t); -int pmap_tlb_update_addr(pmap_t, vaddr_t, uint32_t, u_int); +int pmap_tlb_update_addr(pmap_t, vaddr_t, pt_entry_t, u_int); #define PMAP_TLB_NEED_IPI 0x01 #define PMAP_TLB_INSERT 0x02 void pmap_tlb_invalidate_addr(pmap_t, vaddr_t); Added files: Index: src/sys/uvm/pmap/pmap_synci.h diff -u /dev/null src/sys/uvm/pmap/pmap_synci.h:1.1 --- /dev/null Mon Jul 11 16:06:09 2016 +++ src/sys/uvm/pmap/pmap_synci.h Mon Jul 11 16:06:09 2016 @@ -0,0 +1,41 @@ +/* $NetBSD: pmap_synci.h,v 1.1 2016/07/11 16:06:09 matt Exp $ */ +/*- + * Copyright (c) 2015 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Matt Thomas of 3am Software Foundry. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _UVM_PMAP_PMAP_SYNCI_H_ +#define _UVM_PMAP_PMAP_SYNCI_H_ + +extern u_int pmap_tlb_synci_map_mask; +extern u_int pmap_tlb_synci_page_mask; + +void pmap_tlb_syncicache(vaddr_t, const kcpuset_t *); +void pmap_tlb_syncicache_ast(struct cpu_info *); +void pmap_tlb_syncicache_wanted(struct cpu_info *); + +#endif /* _UVM_PMAP_PMAP_SYNCI_H_ */