FreeBSD/sys/arm/arm/pmap-v4.c
/*
 * Modify pte bits for all ptes corresponding to the given physical address.
 * We use `maskbits' rather than `clearbits' because we're always passing
 * constants and the latter would require an extra inversion at run-time.
 */
Modify pte bits for all ptes corresponding to the given physical address.
We use `maskbits' rather than `clearbits' because we're always passing
constants and the latter would require an extra inversion at run-time.
Modify pte bits for all ptes corresponding to the given physical address . We use ` maskbits ' rather than ` clearbits ' because we ' re always passing constants and the latter would require an extra inversion at run - time .
static int
pmap_clearbit(struct vm_page *pg, u_int maskbits)
{
	struct l2_bucket *l2b;
	struct pv_entry *pv;
	pt_entry_t *ptep, npte, opte;
	pmap_t pm;
	vm_offset_t va;
	u_int oflags;
	int count = 0;
	rw_wlock(&pvh_global_lock);
	if (maskbits & PVF_WRITE)
		maskbits |= PVF_MOD;
	pg->md.pvh_attrs &= ~(maskbits & (PVF_MOD | PVF_REF));
	if (TAILQ_EMPTY(&pg->md.pv_list)) {
		rw_wunlock(&pvh_global_lock);
		return (0);
	}
	TAILQ_FOREACH(pv, &pg->md.pv_list, pv_list) {
		va = pv->pv_va;
		pm = pv->pv_pmap;
		oflags = pv->pv_flags;
		if (!(oflags & maskbits)) {
			if ((maskbits & PVF_WRITE) && (pv->pv_flags & PVF_NC)) {
				if (pg->md.pv_memattr !=
				    VM_MEMATTR_UNCACHEABLE) {
					PMAP_LOCK(pm);
					l2b = pmap_get_l2_bucket(pm, va);
					ptep = &l2b->l2b_kva[l2pte_index(va)];
					*ptep |= pte_l2_s_cache_mode;
					PTE_SYNC(ptep);
					PMAP_UNLOCK(pm);
				}
				pv->pv_flags &= ~(PVF_NC | PVF_MWC);
			}
			continue;
		}
		pv->pv_flags &= ~maskbits;
		PMAP_LOCK(pm);
		l2b = pmap_get_l2_bucket(pm, va);
		ptep = &l2b->l2b_kva[l2pte_index(va)];
		npte = opte = *ptep;
		if (maskbits & (PVF_WRITE|PVF_MOD)) {
			if ((pv->pv_flags & PVF_NC)) {
				if (maskbits & PVF_WRITE) {
					if (pg->md.pv_memattr !=
					    VM_MEMATTR_UNCACHEABLE)
						npte |= pte_l2_s_cache_mode;
					pv->pv_flags &= ~(PVF_NC | PVF_MWC);
				}
			} else
			if (opte & L2_S_PROT_W) {
				vm_page_dirty(pg);
				if (PV_BEEN_EXECD(oflags))
					pmap_idcache_wbinv_range(pm, pv->pv_va,
					    PAGE_SIZE);
				else
				if (PV_BEEN_REFD(oflags))
					pmap_dcache_wb_range(pm, pv->pv_va,
					    PAGE_SIZE,
					    (maskbits & PVF_REF) ? TRUE : FALSE,
					    FALSE);
			}
			npte &= ~L2_S_PROT_W;
		}
		if (maskbits & PVF_REF) {
			if ((pv->pv_flags & PVF_NC) == 0 &&
			    (maskbits & (PVF_WRITE|PVF_MOD)) == 0) {
				if (npte & L2_S_PROT_W) {
					if (PV_BEEN_EXECD(oflags))
						pmap_idcache_wbinv_range(pm,
						    pv->pv_va, PAGE_SIZE);
					else
					if (PV_BEEN_REFD(oflags))
						pmap_dcache_wb_range(pm,
						    pv->pv_va, PAGE_SIZE,
						    TRUE, FALSE);
				} else
				if ((npte & L2_TYPE_MASK) != L2_TYPE_INV) {
					if (PV_BEEN_EXECD(oflags))
						pmap_idcache_wbinv_range(pm,
						    pv->pv_va, PAGE_SIZE);
					else
					if (PV_BEEN_REFD(oflags))
						pmap_dcache_wb_range(pm,
						    pv->pv_va, PAGE_SIZE,
						    TRUE, TRUE);
				}
			}
			npte &= ~L2_TYPE_MASK;
			npte |= L2_TYPE_INV;
		}
		if (npte != opte) {
			count++;
			*ptep = npte;
			PTE_SYNC(ptep);
			if (PV_BEEN_EXECD(oflags))
				pmap_tlb_flushID_SE(pm, pv->pv_va);
			else
			if (PV_BEEN_REFD(oflags))
				pmap_tlb_flushD_SE(pm, pv->pv_va);
		}
		PMAP_UNLOCK(pm);
	}
	if (maskbits & PVF_WRITE)
		vm_page_aflag_clear(pg, PGA_WRITEABLE);
	rw_wunlock(&pvh_global_lock);
	return (count);
}
static int pmap_clearbit ( struct vm_page * pg , u_int maskbits ) { struct l2_bucket * l2b ; struct pv_entry * pv ; pt_entry_t * ptep , npte , opte ; pmap_t pm ; vm_offset_t va ; u_int oflags ; int count = 0 ; rw_wlock ( & pvh_global_lock ) ; if ( maskbits & PVF_WRITE ) maskbits |= PVF_MOD ; pg -> md . pvh_attrs &= ~ ( maskbits & ( PVF_MOD | PVF_REF ) ) ; if ( TAILQ_EMPTY ( & pg -> md . pv_list ) ) { rw_wunlock ( & pvh_global_lock ) ; return ( 0 ) ; } TAILQ_FOREACH ( pv , & pg -> md . pv_list , pv_list ) { va = pv -> pv_va ; pm = pv -> pv_pmap ; oflags = pv -> pv_flags ; if ( ! ( oflags & maskbits ) ) { if ( ( maskbits & PVF_WRITE ) && ( pv -> pv_flags & PVF_NC ) ) { if ( pg -> md . pv_memattr != VM_MEMATTR_UNCACHEABLE ) { PMAP_LOCK ( pm ) ; l2b = pmap_get_l2_bucket ( pm , va ) ; ptep = & l2b -> l2b_kva [ l2pte_index ( va ) ] ; * ptep |= pte_l2_s_cache_mode ; PTE_SYNC ( ptep ) ; PMAP_UNLOCK ( pm ) ; } pv -> pv_flags &= ~ ( PVF_NC | PVF_MWC ) ; } continue ; } pv -> pv_flags &= ~ maskbits ; PMAP_LOCK ( pm ) ; l2b = pmap_get_l2_bucket ( pm , va ) ; ptep = & l2b -> l2b_kva [ l2pte_index ( va ) ] ; npte = opte = * ptep ; if ( maskbits & ( PVF_WRITE | PVF_MOD ) ) { if ( ( pv -> pv_flags & PVF_NC ) ) { if ( maskbits & PVF_WRITE ) { if ( pg -> md . pv_memattr != VM_MEMATTR_UNCACHEABLE ) npte |= pte_l2_s_cache_mode ; pv -> pv_flags &= ~ ( PVF_NC | PVF_MWC ) ; } } else if ( opte & L2_S_PROT_W ) { vm_page_dirty ( pg ) ; if ( PV_BEEN_EXECD ( oflags ) ) pmap_idcache_wbinv_range ( pm , pv -> pv_va , PAGE_SIZE ) ; else if ( PV_BEEN_REFD ( oflags ) ) pmap_dcache_wb_range ( pm , pv -> pv_va , PAGE_SIZE , ( maskbits & PVF_REF ) ? TRUE : FALSE , FALSE ) ; } npte &= ~ L2_S_PROT_W ; } if ( maskbits & PVF_REF ) { if ( ( pv -> pv_flags & PVF_NC ) == 0 && ( maskbits & ( PVF_WRITE | PVF_MOD ) ) == 0 ) { if ( npte & L2_S_PROT_W ) { if ( PV_BEEN_EXECD ( oflags ) ) pmap_idcache_wbinv_range ( pm , pv -> pv_va , PAGE_SIZE ) ; else if ( PV_BEEN_REFD ( oflags ) ) pmap_dcache_wb_range ( pm , pv -> pv_va , PAGE_SIZE , TRUE , FALSE ) ; } else if ( ( npte & L2_TYPE_MASK ) != L2_TYPE_INV ) { if ( PV_BEEN_EXECD ( oflags ) ) pmap_idcache_wbinv_range ( pm , pv -> pv_va , PAGE_SIZE ) ; else if ( PV_BEEN_REFD ( oflags ) ) pmap_dcache_wb_range ( pm , pv -> pv_va , PAGE_SIZE , TRUE , TRUE ) ; } } npte &= ~ L2_TYPE_MASK ; npte |= L2_TYPE_INV ; } if ( npte != opte ) { count ++ ; * ptep = npte ; PTE_SYNC ( ptep ) ; if ( PV_BEEN_EXECD ( oflags ) ) pmap_tlb_flushID_SE ( pm , pv -> pv_va ) ; else if ( PV_BEEN_REFD ( oflags ) ) pmap_tlb_flushD_SE ( pm , pv -> pv_va ) ; } PMAP_UNLOCK ( pm ) ; } if ( maskbits & PVF_WRITE ) vm_page_aflag_clear ( pg , PGA_WRITEABLE ) ; rw_wunlock ( & pvh_global_lock ) ; return ( count ) ; }
Modify pte bits for all ptes corresponding to the given physical address.
Modify pte bits for all ptes corresponding to the given physical address .
/*
	 * Clear saved attributes (modify, reference)
	 */ /*
	 * Loop over all current mappings setting/clearing as appropos
	 */ /*
				 * Entry is not cacheable:
				 *
				 * Don't turn caching on again if this is a
				 * modified emulation. This would be
				 * inconsistent with the settings created by
				 * pmap_fix_cache(). Otherwise, it's safe
				 * to re-enable caching.
				 *
				 * There's no need to call pmap_fix_cache()
				 * here: all pages are losing their write
				 * permission.
				 */ /*
				 * Entry is writable/cacheable: check if pmap
				 * is current if it is flush it, otherwise it
				 * won't be in the cache
				 */ /* make the pte read only */ /*
				 * Check npte here; we may have already
				 * done the wbinv above, and the validity
				 * of the PTE is the same for opte and
				 * npte.
				 */ /* XXXJRT need idcache_inv_range */ /*
			 * Make the PTE invalid so that we will take a
			 * page fault the next time the mapping is
			 * referenced.
			 */ /* Flush the TLB entry if a current pmap. */