summaryrefslogtreecommitdiffstats
path: root/sys/arm
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2012-05-21 06:56:26 +0000
committerimp <imp@FreeBSD.org>2012-05-21 06:56:26 +0000
commit1031a61c54e663992b9485afb269c7466dde83bf (patch)
tree022de017936a2fab9fee52e188b795e9931ed347 /sys/arm
parent6297502d893ddd909c18d663a2c78849ef0c3ac9 (diff)
downloadFreeBSD-src-1031a61c54e663992b9485afb269c7466dde83bf.zip
FreeBSD-src-1031a61c54e663992b9485afb269c7466dde83bf.tar.gz
Implement pmap_mincore for arm. Now programs using it don't cause a
flood of console messages. Reviewed by: alc@
Diffstat (limited to 'sys/arm')
-rw-r--r--sys/arm/arm/pmap.c56
1 files changed, 53 insertions, 3 deletions
diff --git a/sys/arm/arm/pmap.c b/sys/arm/arm/pmap.c
index b6d8c76..5e49a44 100644
--- a/sys/arm/arm/pmap.c
+++ b/sys/arm/arm/pmap.c
@@ -4557,9 +4557,59 @@ pmap_remove_write(vm_page_t m)
int
pmap_mincore(pmap_t pmap, vm_offset_t addr, vm_paddr_t *locked_pa)
{
- printf("pmap_mincore()\n");
-
- return (0);
+ struct l2_bucket *l2b;
+ pt_entry_t *ptep, pte;
+ vm_paddr_t pa;
+ vm_page_t m;
+ int val;
+ boolean_t managed;
+
+ PMAP_LOCK(pmap);
+retry:
+ l2b = pmap_get_l2_bucket(pmap, addr);
+ if (l2b == NULL) {
+ val = 0;
+ goto out;
+ }
+ ptep = &l2b->l2b_kva[l2pte_index(addr)];
+ pte = *ptep;
+ if (!l2pte_valid(pte)) {
+ val = 0;
+ goto out;
+ }
+ val = MINCORE_INCORE;
+ if (pte & L2_S_PROT_W)
+ val |= MINCORE_MODIFIED | MINCORE_MODIFIED_OTHER;
+ managed = false;
+ pa = l2pte_pa(pte);
+ m = PHYS_TO_VM_PAGE(pa);
+ if (m != NULL && !(m->oflags & VPO_UNMANAGED))
+ managed = true;
+ if (managed) {
+ /*
+ * the ARM pmap tries to maintain a per-mapping
+ * reference bit. The trouble is that it's kept in
+ * the PV entry, not the PTE, so it's costly to access
+ * here. You would need to acquire the page queues
+ * lock, call pmap_find_pv(), and introduce a custom
+ * version of vm_page_pa_tryrelock() that releases and
+ * reacquires the page queues lock. In the end, I
+ * doubt it's worthwhile. This may falsely report
+ * the given address as referenced.
+ */
+ if ((m->md.pvh_attrs & PVF_REF) != 0)
+ val |= MINCORE_REFERENCED | MINCORE_REFERENCED_OTHER;
+ }
+ if ((val & (MINCORE_MODIFIED_OTHER | MINCORE_REFERENCED_OTHER)) !=
+ (MINCORE_MODIFIED_OTHER | MINCORE_REFERENCED_OTHER) && managed) {
+ /* Ensure that "PHYS_TO_VM_PAGE(pa)->object" doesn't change. */
+ if (vm_page_pa_tryrelock(pmap, pa, locked_pa))
+ goto retry;
+ } else
+out:
+ PA_UNLOCK_COND(*locked_pa);
+ PMAP_UNLOCK(pmap);
+ return (val);
}
OpenPOWER on IntegriCloud