summaryrefslogtreecommitdiffstats
path: root/sys/mips
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2014-09-01 07:58:15 +0000
committerkib <kib@FreeBSD.org>2014-09-01 07:58:15 +0000
commit798eea16149d6a39c6fb5f721410f61b5bb1134a (patch)
tree8a38ed27916582f1759cfcc70e76cd5fabbebce1 /sys/mips
parent14d8fe45061d6304d3e6438cfe4267aa7e17c705 (diff)
downloadFreeBSD-src-798eea16149d6a39c6fb5f721410f61b5bb1134a.zip
FreeBSD-src-798eea16149d6a39c6fb5f721410f61b5bb1134a.tar.gz
Fix a leak of the wired pages when unwiring of the PROT_NONE-mapped
wired region. Rework the handling of unwire to do the it in batch, both at pmap and object level. All commits below are by alc. MFC r268327: Introduce pmap_unwire(). MFC r268591: Implement pmap_unwire() for powerpc. MFC r268776: Implement pmap_unwire() for arm. MFC r268806: pmap_unwire(9) man page. MFC r269134: When unwiring a region of an address space, do not assume that the underlying physical pages are mapped by the pmap. This fixes a leak of the wired pages on the unwiring of the region mapped with no access allowed. MFC r269339: In the implementation of the new function pmap_unwire(), the call to MOEA64_PVO_TO_PTE() must be performed before any changes are made to the PVO. Otherwise, MOEA64_PVO_TO_PTE() will panic. MFC r269365: Correct a long-standing problem in moea{,64}_pvo_enter() that was revealed by the combination of r268591 and r269134: When we attempt to add the wired attribute to an existing mapping, moea{,64}_pvo_enter() do nothing. (They only set the wired attribute on newly created mappings.) MFC r269433: Handle wiring failures in vm_map_wire() with the new functions pmap_unwire() and vm_object_unwire(). Retire vm_fault_{un,}wire(), since they are no longer used. MFC r269438: Rewrite a loop in vm_map_wire() so that gcc doesn't think that the variable "rv" is uninitialized. MFC r269485: Retire pmap_change_wiring(). Reviewed by: alc
Diffstat (limited to 'sys/mips')
-rw-r--r--sys/mips/mips/pmap.c60
1 files changed, 39 insertions, 21 deletions
diff --git a/sys/mips/mips/pmap.c b/sys/mips/mips/pmap.c
index 973791b..caee47c 100644
--- a/sys/mips/mips/pmap.c
+++ b/sys/mips/mips/pmap.c
@@ -2426,33 +2426,51 @@ pmap_object_init_pt(pmap_t pmap, vm_offset_t addr,
}
/*
- * Routine: pmap_change_wiring
- * Function: Change the wiring attribute for a map/virtual-address
- * pair.
- * In/out conditions:
- * The mapping must already exist in the pmap.
+ * Clear the wired attribute from the mappings for the specified range of
+ * addresses in the given pmap. Every valid mapping within that range
+ * must have the wired attribute set. In contrast, invalid mappings
+ * cannot have the wired attribute set, so they are ignored.
+ *
+ * The wired attribute of the page table entry is not a hardware feature,
+ * so there is no need to invalidate any TLB entries.
*/
void
-pmap_change_wiring(pmap_t pmap, vm_offset_t va, boolean_t wired)
+pmap_unwire(pmap_t pmap, vm_offset_t sva, vm_offset_t eva)
{
+ pd_entry_t *pde, *pdpe;
pt_entry_t *pte;
+ vm_offset_t va_next;
PMAP_LOCK(pmap);
- pte = pmap_pte(pmap, va);
-
- if (wired && !pte_test(pte, PTE_W))
- pmap->pm_stats.wired_count++;
- else if (!wired && pte_test(pte, PTE_W))
- pmap->pm_stats.wired_count--;
-
- /*
- * Wiring is not a hardware characteristic so there is no need to
- * invalidate TLB.
- */
- if (wired)
- pte_set(pte, PTE_W);
- else
- pte_clear(pte, PTE_W);
+ for (; sva < eva; sva = va_next) {
+ pdpe = pmap_segmap(pmap, sva);
+#ifdef __mips_n64
+ if (*pdpe == NULL) {
+ 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;
+ if (va_next > eva)
+ va_next = eva;
+ for (pte = pmap_pde_to_pte(pde, sva); sva != va_next; pte++,
+ sva += PAGE_SIZE) {
+ if (!pte_test(pte, PTE_V))
+ continue;
+ if (!pte_test(pte, PTE_W))
+ panic("pmap_unwire: pte %#jx is missing PG_W",
+ (uintmax_t)*pte);
+ pte_clear(pte, PTE_W);
+ pmap->pm_stats.wired_count--;
+ }
+ }
PMAP_UNLOCK(pmap);
}
OpenPOWER on IntegriCloud