FreeBSD/sys/i386/i386/pmap.c
/*
 * Remove all pages from specified address space
 * this aids process exit speeds.  Also, this code
 * is special cased for current process only, but
 * can have the more generic (and slightly slower)
 * mode enabled.  This is much faster than pmap_remove
 * in the case of running down an entire address space.
 */
Remove all pages from specified address space
this aids process exit speeds.  Also, this code
is special cased for current process only, but
can have the more generic (and slightly slower)
mode enabled.  This is much faster than pmap_remove
in the case of running down an entire address space.
Remove all pages from specified address space this aids process exit speeds . Also this code is special cased for current process only but can have the more generic ( and slightly slower ) mode enabled . This is much faster than pmap_remove in the case of running down an entire address space .
void
pmap_remove_pages(pmap_t pmap)
{
	pt_entry_t *pte, tpte;
	vm_page_t m, mpte, mt;
	pv_entry_t pv;
	struct md_page *pvh;
	struct pv_chunk *pc, *npc;
	struct spglist free;
	int field, idx;
	int32_t bit;
	uint32_t inuse, bitmask;
	int allfree;
	if (pmap != PCPU_GET(curpmap)) {
		printf("warning: pmap_remove_pages called with non-current pmap\n");
		return;
	}
	SLIST_INIT(&free);
	rw_wlock(&pvh_global_lock);
	PMAP_LOCK(pmap);
	sched_pin();
	TAILQ_FOREACH_SAFE(pc, &pmap->pm_pvchunk, pc_list, npc) {
		KASSERT(pc->pc_pmap == pmap, ("Wrong pmap %p %p", pmap,
		    pc->pc_pmap));
		allfree = 1;
		for (field = 0; field < _NPCM; field++) {
			inuse = ~pc->pc_map[field] & pc_freemask[field];
			while (inuse != 0) {
				bit = bsfl(inuse);
				bitmask = 1UL << bit;
				idx = field * 32 + bit;
				pv = &pc->pc_pventry[idx];
				inuse &= ~bitmask;
				pte = pmap_pde(pmap, pv->pv_va);
				tpte = *pte;
				if ((tpte & PG_PS) == 0) {
					pte = vtopte(pv->pv_va);
					tpte = *pte & ~PG_PTE_PAT;
				}
				if (tpte == 0) {
					printf(
					    "TPTE at %p  IS ZERO @ VA %08x\n",
					    pte, pv->pv_va);
					panic("bad pte");
				}
				if (tpte & PG_W) {
					allfree = 0;
					continue;
				}
				m = PHYS_TO_VM_PAGE(tpte & PG_FRAME);
				KASSERT(m->phys_addr == (tpte & PG_FRAME),
				    ("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 tpte %#jx",
				    (uintmax_t)tpte));
				pte_clear(pte);
				if ((tpte & (PG_M | PG_RW)) == (PG_M | PG_RW)) {
					if ((tpte & PG_PS) != 0) {
						for (mt = m; mt < &m[NBPDR / PAGE_SIZE]; mt++)
							vm_page_dirty(mt);
					} else
						vm_page_dirty(m);
				}
				PV_STAT(pv_entry_frees++);
				PV_STAT(pv_entry_spare++);
				pv_entry_count--;
				pc->pc_map[field] |= bitmask;
				if ((tpte & PG_PS) != 0) {
					pmap->pm_stats.resident_count -= NBPDR / PAGE_SIZE;
					pvh = pa_to_pvh(tpte & PG_PS_FRAME);
					TAILQ_REMOVE(&pvh->pv_list, pv, pv_next);
					if (TAILQ_EMPTY(&pvh->pv_list)) {
						for (mt = m; mt < &m[NBPDR / PAGE_SIZE]; mt++)
							if (TAILQ_EMPTY(&mt->md.pv_list))
								vm_page_aflag_clear(mt, PGA_WRITEABLE);
					}
					mpte = pmap_lookup_pt_page(pmap, pv->pv_va);
					if (mpte != NULL) {
						pmap_remove_pt_page(pmap, mpte);
						pmap->pm_stats.resident_count--;
						KASSERT(mpte->wire_count == NPTEPG,
						    ("pmap_remove_pages: pte page wire count error"));
						mpte->wire_count = 0;
						pmap_add_delayed_free_list(mpte, &free, FALSE);
						atomic_subtract_int(&vm_cnt.v_wire_count, 1);
					}
				} else {
					pmap->pm_stats.resident_count--;
					TAILQ_REMOVE(&m->md.pv_list, pv, pv_next);
					if (TAILQ_EMPTY(&m->md.pv_list) &&
					    (m->flags & PG_FICTITIOUS) == 0) {
						pvh = pa_to_pvh(VM_PAGE_TO_PHYS(m));
						if (TAILQ_EMPTY(&pvh->pv_list))
							vm_page_aflag_clear(m, PGA_WRITEABLE);
					}
					pmap_unuse_pt(pmap, pv->pv_va, &free);
				}
			}
		}
		if (allfree) {
			TAILQ_REMOVE(&pmap->pm_pvchunk, pc, pc_list);
			free_pv_chunk(pc);
		}
	}
	sched_unpin();
	pmap_invalidate_all(pmap);
	rw_wunlock(&pvh_global_lock);
	PMAP_UNLOCK(pmap);
	pmap_free_zero_pages(&free);
}
void pmap_remove_pages ( pmap_t pmap ) { pt_entry_t * pte , tpte ; vm_page_t m , mpte , mt ; pv_entry_t pv ; struct md_page * pvh ; struct pv_chunk * pc , * npc ; struct spglist free ; int field , idx ; int32_t bit ; uint32_t inuse , bitmask ; int allfree ; if ( pmap != PCPU_GET ( curpmap ) ) { printf ( " \n " ) ; return ; } SLIST_INIT ( & free ) ; rw_wlock ( & pvh_global_lock ) ; PMAP_LOCK ( pmap ) ; sched_pin ( ) ; TAILQ_FOREACH_SAFE ( pc , & pmap -> pm_pvchunk , pc_list , npc ) { KASSERT ( pc -> pc_pmap == pmap , ( " " , pmap , pc -> pc_pmap ) ) ; allfree = 1 ; for ( field = 0 ; field < _NPCM ; field ++ ) { inuse = ~ pc -> pc_map [ field ] & pc_freemask [ field ] ; while ( inuse != 0 ) { bit = bsfl ( inuse ) ; bitmask = 1UL << bit ; idx = field * 32 + bit ; pv = & pc -> pc_pventry [ idx ] ; inuse &= ~ bitmask ; pte = pmap_pde ( pmap , pv -> pv_va ) ; tpte = * pte ; if ( ( tpte & PG_PS ) == 0 ) { pte = vtopte ( pv -> pv_va ) ; tpte = * pte & ~ PG_PTE_PAT ; } if ( tpte == 0 ) { printf ( " \n " , pte , pv -> pv_va ) ; panic ( " " ) ; } if ( tpte & PG_W ) { allfree = 0 ; continue ; } m = PHYS_TO_VM_PAGE ( tpte & PG_FRAME ) ; KASSERT ( m -> phys_addr == ( tpte & PG_FRAME ) , ( " " , 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 ) ) ; pte_clear ( pte ) ; if ( ( tpte & ( PG_M | PG_RW ) ) == ( PG_M | PG_RW ) ) { if ( ( tpte & PG_PS ) != 0 ) { for ( mt = m ; mt < & m [ NBPDR / PAGE_SIZE ] ; mt ++ ) vm_page_dirty ( mt ) ; } else vm_page_dirty ( m ) ; } PV_STAT ( pv_entry_frees ++ ) ; PV_STAT ( pv_entry_spare ++ ) ; pv_entry_count -- ; pc -> pc_map [ field ] |= bitmask ; if ( ( tpte & PG_PS ) != 0 ) { pmap -> pm_stats . resident_count -= NBPDR / PAGE_SIZE ; pvh = pa_to_pvh ( tpte & PG_PS_FRAME ) ; TAILQ_REMOVE ( & pvh -> pv_list , pv , pv_next ) ; if ( TAILQ_EMPTY ( & pvh -> pv_list ) ) { for ( mt = m ; mt < & m [ NBPDR / PAGE_SIZE ] ; mt ++ ) if ( TAILQ_EMPTY ( & mt -> md . pv_list ) ) vm_page_aflag_clear ( mt , PGA_WRITEABLE ) ; } mpte = pmap_lookup_pt_page ( pmap , pv -> pv_va ) ; if ( mpte != NULL ) { pmap_remove_pt_page ( pmap , mpte ) ; pmap -> pm_stats . resident_count -- ; KASSERT ( mpte -> wire_count == NPTEPG , ( " " ) ) ; mpte -> wire_count = 0 ; pmap_add_delayed_free_list ( mpte , & free , FALSE ) ; atomic_subtract_int ( & vm_cnt . v_wire_count , 1 ) ; } } else { pmap -> pm_stats . resident_count -- ; TAILQ_REMOVE ( & m -> md . pv_list , pv , pv_next ) ; if ( TAILQ_EMPTY ( & m -> md . pv_list ) && ( m -> flags & PG_FICTITIOUS ) == 0 ) { pvh = pa_to_pvh ( VM_PAGE_TO_PHYS ( m ) ) ; if ( TAILQ_EMPTY ( & pvh -> pv_list ) ) vm_page_aflag_clear ( m , PGA_WRITEABLE ) ; } pmap_unuse_pt ( pmap , pv -> pv_va , & free ) ; } } } if ( allfree ) { TAILQ_REMOVE ( & pmap -> pm_pvchunk , pc , pc_list ) ; free_pv_chunk ( pc ) ; } } sched_unpin ( ) ; pmap_invalidate_all ( pmap ) ; rw_wunlock ( & pvh_global_lock ) ; PMAP_UNLOCK ( pmap ) ; pmap_free_zero_pages ( & free ) ; }
Remove all pages from specified address space
 this aids process exit speeds.
Remove all pages from specified address space this aids process exit speeds .
/*
 * We cannot remove wired pages from a process' mapping at this time
 */ /*
				 * Update the vm_page_t clean/reference bits.
				 */ /* Mark free */