FreeBSD/sys/i386/i386/pmap.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;
	pd_entry_t oldpde, *pde;
	pt_entry_t oldpte, *pte;
	vm_offset_t va;
	KASSERT((m->oflags & VPO_UNMANAGED) == 0,
	    ("pmap_clear_modify: page %p is not managed", m));
	VM_OBJECT_ASSERT_WLOCKED(m->object);
	KASSERT(!vm_page_xbusied(m),
	    ("pmap_clear_modify: page %p is exclusive busied", m));
	if ((m->aflags & 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);
		pde = pmap_pde(pmap, va);
		oldpde = *pde;
		if ((oldpde & PG_RW) != 0) {
			if (pmap_demote_pde(pmap, pde, va)) {
				if ((oldpde & PG_W) == 0) {
					va += VM_PAGE_TO_PHYS(m) - (oldpde &
					    PG_PS_FRAME);
					pte = pmap_pte_quick(pmap, va);
					oldpte = *pte;
					if ((oldpte & PG_V) != 0) {
						while (!atomic_cmpset_int((u_int *)pte,
						    oldpte,
						    oldpte & ~(PG_M | PG_RW)))
							oldpte = *pte;
						vm_page_dirty(m);
						pmap_invalidate_page(pmap, va);
					}
				}
			}
		}
		PMAP_UNLOCK(pmap);
	}
small_mappings:
	TAILQ_FOREACH(pv, &m->md.pv_list, pv_next) {
		pmap = PV_PMAP(pv);
		PMAP_LOCK(pmap);
		pde = pmap_pde(pmap, pv->pv_va);
		KASSERT((*pde & PG_PS) == 0, ("pmap_clear_modify: found"
		    " a 4mpage in page %p's pv list", m));
		pte = pmap_pte_quick(pmap, pv->pv_va);
		if ((*pte & (PG_M | PG_RW)) == (PG_M | PG_RW)) {
			atomic_clear_int((u_int *)pte, PG_M);
			pmap_invalidate_page(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 ; pd_entry_t oldpde , * pde ; pt_entry_t oldpte , * pte ; vm_offset_t va ; KASSERT ( ( m -> oflags & VPO_UNMANAGED ) == 0 , ( " " , m ) ) ; VM_OBJECT_ASSERT_WLOCKED ( m -> object ) ; KASSERT ( ! vm_page_xbusied ( m ) , ( " " , m ) ) ; if ( ( m -> aflags & 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 ) ; pde = pmap_pde ( pmap , va ) ; oldpde = * pde ; if ( ( oldpde & PG_RW ) != 0 ) { if ( pmap_demote_pde ( pmap , pde , va ) ) { if ( ( oldpde & PG_W ) == 0 ) { va += VM_PAGE_TO_PHYS ( m ) - ( oldpde & PG_PS_FRAME ) ; pte = pmap_pte_quick ( pmap , va ) ; oldpte = * pte ; if ( ( oldpte & PG_V ) != 0 ) { while ( ! atomic_cmpset_int ( ( u_int * ) pte , oldpte , oldpte & ~ ( PG_M | PG_RW ) ) ) oldpte = * pte ; vm_page_dirty ( m ) ; pmap_invalidate_page ( pmap , va ) ; } } } } PMAP_UNLOCK ( pmap ) ; } small_mappings : TAILQ_FOREACH ( pv , & m -> md . pv_list , pv_next ) { pmap = PV_PMAP ( pv ) ; PMAP_LOCK ( pmap ) ; pde = pmap_pde ( pmap , pv -> pv_va ) ; KASSERT ( ( * pde & PG_PS ) == 0 , ( " " " " , m ) ) ; pte = pmap_pte_quick ( pmap , pv -> pv_va ) ; if ( ( * pte & ( PG_M | PG_RW ) ) == ( PG_M | PG_RW ) ) { atomic_clear_int ( ( u_int * ) pte , PG_M ) ; pmap_invalidate_page ( 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 PTEs can have PG_M set.
	 * 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.
					 */ /*
						 * Regardless of whether a pte is 32 or 64 bits
						 * in size, PG_RW and PG_M are among the least
						 * significant 32 bits.
						 */ /*
			 * Regardless of whether a pte is 32 or 64 bits
			 * in size, PG_M is among the least significant
			 * 32 bits. 
			 */