summaryrefslogtreecommitdiffstats
path: root/sys/sparc64
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/sparc64
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/sparc64')
-rw-r--r--sys/sparc64/sparc64/pmap.c43
1 files changed, 29 insertions, 14 deletions
diff --git a/sys/sparc64/sparc64/pmap.c b/sys/sparc64/sparc64/pmap.c
index 54e0b22..9073760 100644
--- a/sys/sparc64/sparc64/pmap.c
+++ b/sys/sparc64/sparc64/pmap.c
@@ -141,6 +141,8 @@ static void pmap_bootstrap_set_tte(struct tte *tp, u_long vpn, u_long data);
static void pmap_cache_remove(vm_page_t m, vm_offset_t va);
static int pmap_protect_tte(struct pmap *pm1, struct pmap *pm2,
struct tte *tp, vm_offset_t va);
+static int pmap_unwire_tte(pmap_t pm, pmap_t pm2, struct tte *tp,
+ vm_offset_t va);
/*
* Map the given physical page at the specified virtual address in the
@@ -1668,27 +1670,40 @@ pmap_object_init_pt(pmap_t pm, vm_offset_t addr, vm_object_t object,
("pmap_object_init_pt: non-device object"));
}
+static int
+pmap_unwire_tte(pmap_t pm, pmap_t pm2, struct tte *tp, vm_offset_t va)
+{
+
+ PMAP_LOCK_ASSERT(pm, MA_OWNED);
+ if ((tp->tte_data & TD_WIRED) == 0)
+ panic("pmap_unwire_tte: tp %p is missing TD_WIRED", tp);
+ atomic_clear_long(&tp->tte_data, TD_WIRED);
+ pm->pm_stats.wired_count--;
+ return (1);
+}
+
/*
- * Change the wiring attribute for a map/virtual-address pair.
- * 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 translation table entry is not a hardware
+ * feature, so there is no need to invalidate any TLB entries.
*/
void
-pmap_change_wiring(pmap_t pm, vm_offset_t va, boolean_t wired)
+pmap_unwire(pmap_t pm, vm_offset_t sva, vm_offset_t eva)
{
+ vm_offset_t va;
struct tte *tp;
- u_long data;
PMAP_LOCK(pm);
- if ((tp = tsb_tte_lookup(pm, va)) != NULL) {
- if (wired) {
- data = atomic_set_long(&tp->tte_data, TD_WIRED);
- if ((data & TD_WIRED) == 0)
- pm->pm_stats.wired_count++;
- } else {
- data = atomic_clear_long(&tp->tte_data, TD_WIRED);
- if ((data & TD_WIRED) != 0)
- pm->pm_stats.wired_count--;
- }
+ if (eva - sva > PMAP_TSB_THRESH)
+ tsb_foreach(pm, NULL, sva, eva, pmap_unwire_tte);
+ else {
+ for (va = sva; va < eva; va += PAGE_SIZE)
+ if ((tp = tsb_tte_lookup(pm, va)) != NULL)
+ pmap_unwire_tte(pm, NULL, tp, va);
}
PMAP_UNLOCK(pm);
}
OpenPOWER on IntegriCloud