FreeBSD/sys/arm64/arm64/pmap.c
/*
 * Destroy all managed, non-wired mappings in the given user-space
 * pmap.  This pmap cannot be active on any processor besides the
 * caller.
 *                                                                                
 * This function cannot be applied to the kernel pmap.  Moreover, it
 * is not intended for general use.  It is only to be used during
 * process termination.  Consequently, it can be implemented in ways
 * that make it faster than pmap_remove().  First, it can more quickly
 * destroy mappings by iterating over the pmap's collection of PV
 * entries, rather than searching the page table.  Second, it doesn't
 * have to test and clear the page table entries atomically, because
 * no processor is currently accessing the user address space.  In
 * particular, a page table entry's dirty bit won't change state once
 * this function starts.
 */
Destroy all managed, non-wired mappings in the given user-space
pmap.  This pmap cannot be active on any processor besides the
caller.

This function cannot be applied to the kernel pmap.  Moreover, it
is not intended for general use.  It is only to be used during
process termination.  Consequently, it can be implemented in ways
that make it faster than pmap_remove().  First, it can more quickly
destroy mappings by iterating over the pmap's collection of PV
entries, rather than searching the page table.  Second, it doesn't
have to test and clear the page table entries atomically, because
no processor is currently accessing the user address space.  In
particular, a page table entry's dirty bit won't change state once
this function starts.
Destroy all managed non - wired mappings in the given user - space pmap . This pmap cannot be active on any processor besides the caller . This function cannot be applied to the kernel pmap . Moreover it is not intended for general use . It is only to be used during process termination . Consequently it can be implemented in ways that make it faster than pmap_remove () . First it can more quickly destroy mappings by iterating over the pmap ' s collection of PV entries rather than searching the page table . Second it doesn ' t have to test and clear the page table entries atomically because no processor is currently accessing the user address space . In particular a page table entry ' s dirty bit won ' t change state once this function starts .
void
pmap_remove_pages(pmap_t pmap)
{
	pd_entry_t *pde;
	pt_entry_t *pte, tpte;
	struct spglist free;
	vm_page_t m;
	pv_entry_t pv;
	struct pv_chunk *pc, *npc;
	struct rwlock *lock;
	int64_t bit;
	uint64_t inuse, bitmask;
	int allfree, field, freed, idx, lvl;
	vm_paddr_t pa;
	lock = NULL;
	SLIST_INIT(&free);
	rw_rlock(&pvh_global_lock);
	PMAP_LOCK(pmap);
	TAILQ_FOREACH_SAFE(pc, &pmap->pm_pvchunk, pc_list, npc) {
		allfree = 1;
		freed = 0;
		for (field = 0; field < _NPCM; field++) {
			inuse = ~pc->pc_map[field] & pc_freemask[field];
			while (inuse != 0) {
				bit = ffsl(inuse) - 1;
				bitmask = 1UL << bit;
				idx = field * 64 + bit;
				pv = &pc->pc_pventry[idx];
				inuse &= ~bitmask;
				pde = pmap_pde(pmap, pv->pv_va, &lvl);
				KASSERT(pde != NULL,
				    ("Attempting to remove an unmapped page"));
				KASSERT(lvl == 2,
				    ("Invalid page directory level: %d", lvl));
				pte = pmap_l2_to_l3(pde, pv->pv_va);
				KASSERT(pte != NULL,
				    ("Attempting to remove an unmapped page"));
				tpte = pmap_load(pte);
				if (tpte & ATTR_SW_WIRED) {
					allfree = 0;
					continue;
				}
				pa = tpte & ~ATTR_MASK;
				m = PHYS_TO_VM_PAGE(pa);
				KASSERT(m->phys_addr == pa,
				    ("vm_page_t %p phys_addr mismatch %016jx %016jx",
				    m, (uintmax_t)m->phys_addr,
				    (uintmax_t)tpte));
				KASSERT((m->flags & PG_FICTITIOUS) != 0 ||
				    m < &vm_page_array[vm_page_array_size],
				    ("pmap_remove_pages: bad pte %#jx",
				    (uintmax_t)tpte));
				if (pmap_is_current(pmap) &&
				    pmap_l3_valid_cacheable(tpte))
					cpu_dcache_wb_range(pv->pv_va, L3_SIZE);
				pmap_load_clear(pte);
				PTE_SYNC(pte);
				pmap_invalidate_page(pmap, pv->pv_va);
				if ((tpte & ATTR_AP_RW_BIT) == ATTR_AP(ATTR_AP_RW))
					vm_page_dirty(m);
				CHANGE_PV_LIST_LOCK_TO_VM_PAGE(&lock, m);
				pc->pc_map[field] |= bitmask;
				pmap_resident_count_dec(pmap, 1);
				TAILQ_REMOVE(&m->md.pv_list, pv, pv_next);
				m->md.pv_gen++;
				pmap_unuse_l3(pmap, pv->pv_va, pmap_load(pde),
				    &free);
				freed++;
			}
		}
		PV_STAT(atomic_add_long(&pv_entry_frees, freed));
		PV_STAT(atomic_add_int(&pv_entry_spare, freed));
		PV_STAT(atomic_subtract_long(&pv_entry_count, freed));
		if (allfree) {
			TAILQ_REMOVE(&pmap->pm_pvchunk, pc, pc_list);
			free_pv_chunk(pc);
		}
	}
	pmap_invalidate_all(pmap);
	if (lock != NULL)
		rw_wunlock(lock);
	rw_runlock(&pvh_global_lock);
	PMAP_UNLOCK(pmap);
	pmap_free_zero_pages(&free);
}
void pmap_remove_pages ( pmap_t pmap ) { pd_entry_t * pde ; pt_entry_t * pte , tpte ; struct spglist free ; vm_page_t m ; pv_entry_t pv ; struct pv_chunk * pc , * npc ; struct rwlock * lock ; int64_t bit ; uint64_t inuse , bitmask ; int allfree , field , freed , idx , lvl ; vm_paddr_t pa ; lock = NULL ; SLIST_INIT ( & free ) ; rw_rlock ( & pvh_global_lock ) ; PMAP_LOCK ( pmap ) ; TAILQ_FOREACH_SAFE ( pc , & pmap -> pm_pvchunk , pc_list , npc ) { allfree = 1 ; freed = 0 ; for ( field = 0 ; field < _NPCM ; field ++ ) { inuse = ~ pc -> pc_map [ field ] & pc_freemask [ field ] ; while ( inuse != 0 ) { bit = ffsl ( inuse ) - 1 ; bitmask = 1UL << bit ; idx = field * 64 + bit ; pv = & pc -> pc_pventry [ idx ] ; inuse &= ~ bitmask ; pde = pmap_pde ( pmap , pv -> pv_va , & lvl ) ; KASSERT ( pde != NULL , ( " " ) ) ; KASSERT ( lvl == 2 , ( " " , lvl ) ) ; pte = pmap_l2_to_l3 ( pde , pv -> pv_va ) ; KASSERT ( pte != NULL , ( " " ) ) ; tpte = pmap_load ( pte ) ; if ( tpte & ATTR_SW_WIRED ) { allfree = 0 ; continue ; } pa = tpte & ~ ATTR_MASK ; m = PHYS_TO_VM_PAGE ( pa ) ; KASSERT ( m -> phys_addr == pa , ( " " , m , ( uintmax_t ) m -> phys_addr , ( uintmax_t ) tpte ) ) ; KASSERT ( ( m -> flags & PG_FICTITIOUS ) != 0 || m < & vm_page_array [ vm_page_array_size ] , ( " " , ( uintmax_t ) tpte ) ) ; if ( pmap_is_current ( pmap ) && pmap_l3_valid_cacheable ( tpte ) ) cpu_dcache_wb_range ( pv -> pv_va , L3_SIZE ) ; pmap_load_clear ( pte ) ; PTE_SYNC ( pte ) ; pmap_invalidate_page ( pmap , pv -> pv_va ) ; if ( ( tpte & ATTR_AP_RW_BIT ) == ATTR_AP ( ATTR_AP_RW ) ) vm_page_dirty ( m ) ; CHANGE_PV_LIST_LOCK_TO_VM_PAGE ( & lock , m ) ; pc -> pc_map [ field ] |= bitmask ; pmap_resident_count_dec ( pmap , 1 ) ; TAILQ_REMOVE ( & m -> md . pv_list , pv , pv_next ) ; m -> md . pv_gen ++ ; pmap_unuse_l3 ( pmap , pv -> pv_va , pmap_load ( pde ) , & free ) ; freed ++ ; } } PV_STAT ( atomic_add_long ( & pv_entry_frees , freed ) ) ; PV_STAT ( atomic_add_int ( & pv_entry_spare , freed ) ) ; PV_STAT ( atomic_subtract_long ( & pv_entry_count , freed ) ) ; if ( allfree ) { TAILQ_REMOVE ( & pmap -> pm_pvchunk , pc , pc_list ) ; free_pv_chunk ( pc ) ; } } pmap_invalidate_all ( pmap ) ; if ( lock != NULL ) rw_wunlock ( lock ) ; rw_runlock ( & pvh_global_lock ) ; PMAP_UNLOCK ( pmap ) ; pmap_free_zero_pages ( & free ) ; }
Destroy all managed, non-wired mappings in the given user-space
 pmap.
Destroy all managed non - wired mappings in the given user - space pmap .
/*
 * We cannot remove wired pages from a process' mapping at this time
 */ /* XXX: assumes tpte is level 3 */ /*
				 * Update the vm_page_t clean/reference bits.
				 */ /* Mark free */