FreeBSD/sys/arm/arm/pmap-v6.c
/*
 *	Clear the modify bits on the specified physical page.
 */
Clear the modify bits on the specified physical page.
Clear the modify bits on the specified physical page .
void
pmap_clear_modify(vm_page_t m)
{
	struct md_page *pvh;
	pv_entry_t next_pv, pv;
	pmap_t pmap;
	pt1_entry_t *pte1p, opte1;
	pt2_entry_t *pte2p, opte2;
	vm_offset_t va;
	KASSERT((m->oflags & VPO_UNMANAGED) == 0,
	    ("%s: page %p is not managed", __func__, m));
	VM_OBJECT_ASSERT_WLOCKED(m->object);
	KASSERT(!vm_page_xbusied(m),
	    ("%s: page %p is exclusive busy", __func__, m));
	if ((m->flags & PGA_WRITEABLE) == 0)
		return;
	rw_wlock(&pvh_global_lock);
	sched_pin();
	if ((m->flags & PG_FICTITIOUS) != 0)
		goto small_mappings;
	pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m));
	TAILQ_FOREACH_SAFE(pv, &pvh->pv_list, pv_next, next_pv) {
		va = pv->pv_va;
		pmap = PV_PMAP(pv);
		PMAP_LOCK(pmap);
		pte1p = pmap_pte1(pmap, va);
		opte1 = pte1_load(pte1p);
		if (!(opte1 & PTE1_RO)) {
			if (pmap_demote_pte1(pmap, pte1p, va) &&
			    !pte1_is_wired(opte1)) {
				va += VM_PAGE_TO_PHYS(m) - pte1_pa(opte1);
				pte2p = pmap_pte2_quick(pmap, va);
				opte2 = pte2_load(pte2p);
				if ((opte2 & PTE2_V)) {
					pte2_set_bit(pte2p, PTE2_NM | PTE2_RO);
					vm_page_dirty(m);
					pmap_tlb_flush(pmap, va);
				}
			}
		}
		PMAP_UNLOCK(pmap);
	}
small_mappings:
	TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) {
		pmap = PV_PMAP(pv);
		PMAP_LOCK(pmap);
		pte1p = pmap_pte1(pmap, pv->pv_va);
		KASSERT(!pte1_is_section(pte1_load(pte1p)), ("%s: found"
		    " a section in page %p's pv list", __func__, m));
		pte2p = pmap_pte2_quick(pmap, pv->pv_va);
		if (pte2_is_dirty(pte2_load(pte2p))) {
			pte2_set_bit(pte2p, PTE2_NM);
			pmap_tlb_flush(pmap, pv->pv_va);
		}
		PMAP_UNLOCK(pmap);
	}
	sched_unpin();
	rw_wunlock(&pvh_global_lock);
}
void pmap_clear_modify ( vm_page_t m ) { struct md_page * pvh ; pv_entry_t next_pv , pv ; pmap_t pmap ; pt1_entry_t * pte1p , opte1 ; pt2_entry_t * pte2p , opte2 ; vm_offset_t va ; KASSERT ( ( m -> oflags & VPO_UNMANAGED ) == 0 , ( " " , __func__ , m ) ) ; VM_OBJECT_ASSERT_WLOCKED ( m -> object ) ; KASSERT ( ! vm_page_xbusied ( m ) , ( " " , __func__ , m ) ) ; if ( ( m -> flags & PGA_WRITEABLE ) == 0 ) return ; rw_wlock ( & pvh_global_lock ) ; sched_pin ( ) ; if ( ( m -> flags & PG_FICTITIOUS ) != 0 ) goto small_mappings ; pvh = pa_to_pvh ( VM_PAGE_TO_PHYS ( m ) ) ; TAILQ_FOREACH_SAFE ( pv , & pvh -> pv_list , pv_next , next_pv ) { va = pv -> pv_va ; pmap = PV_PMAP ( pv ) ; PMAP_LOCK ( pmap ) ; pte1p = pmap_pte1 ( pmap , va ) ; opte1 = pte1_load ( pte1p ) ; if ( ! ( opte1 & PTE1_RO ) ) { if ( pmap_demote_pte1 ( pmap , pte1p , va ) && ! pte1_is_wired ( opte1 ) ) { va += VM_PAGE_TO_PHYS ( m ) - pte1_pa ( opte1 ) ; pte2p = pmap_pte2_quick ( pmap , va ) ; opte2 = pte2_load ( pte2p ) ; if ( ( opte2 & PTE2_V ) ) { pte2_set_bit ( pte2p , PTE2_NM | PTE2_RO ) ; vm_page_dirty ( m ) ; pmap_tlb_flush ( pmap , va ) ; } } } PMAP_UNLOCK ( pmap ) ; } small_mappings : TAILQ_FOREACH ( pv , & m -> md . pv_list , pv_next ) { pmap = PV_PMAP ( pv ) ; PMAP_LOCK ( pmap ) ; pte1p = pmap_pte1 ( pmap , pv -> pv_va ) ; KASSERT ( ! pte1_is_section ( pte1_load ( pte1p ) ) , ( " " " " , __func__ , m ) ) ; pte2p = pmap_pte2_quick ( pmap , pv -> pv_va ) ; if ( pte2_is_dirty ( pte2_load ( pte2p ) ) ) { pte2_set_bit ( pte2p , PTE2_NM ) ; pmap_tlb_flush ( pmap , pv -> pv_va ) ; } PMAP_UNLOCK ( pmap ) ; } sched_unpin ( ) ; rw_wunlock ( & pvh_global_lock ) ; }
Clear the modify bits on the specified physical page.
Clear the modify bits on the specified physical page .
/*
	 * If the page is not PGA_WRITEABLE, then no PTE2s can have PTE2_NM
	 * cleared. If the object containing the page is locked and the page
	 * is not exclusive busied, then PGA_WRITEABLE cannot be concurrently
	 * set.
	 */ /*
				 * Write protect the mapping to a
				 * single page so that a subsequent
				 * write access may repromote.
				 */