FreeBSD/sys/i386/i386/pmap.c
/*
 * pmap_remove_pde: do the things to unmap a superpage in a process
 */
do the things to unmap a superpage in a process
do the things to unmap a superpage in a process
static void
pmap_remove_pde(pmap_t pmap, pd_entry_t *pdq, vm_offset_t sva,
    struct spglist *free)
{
	struct md_page *pvh;
	pd_entry_t oldpde;
	vm_offset_t eva, va;
	vm_page_t m, mpte;
	PMAP_LOCK_ASSERT(pmap, MA_OWNED);
	KASSERT((sva & PDRMASK) == 0,
	    ("pmap_remove_pde: sva is not 4mpage aligned"));
	oldpde = pte_load_clear(pdq);
	if (oldpde & PG_W)
		pmap->pm_stats.wired_count -= NBPDR / PAGE_SIZE;
	if (oldpde & PG_G)
		pmap_invalidate_page(kernel_pmap, sva);
	pmap->pm_stats.resident_count -= NBPDR / PAGE_SIZE;
	if (oldpde & PG_MANAGED) {
		pvh = pa_to_pvh(oldpde & PG_PS_FRAME);
		pmap_pvh_free(pvh, pmap, sva);
		eva = sva + NBPDR;
		for (va = sva, m = PHYS_TO_VM_PAGE(oldpde & PG_PS_FRAME);
		    va < eva; va += PAGE_SIZE, m++) {
			if ((oldpde & (PG_M | PG_RW)) == (PG_M | PG_RW))
				vm_page_dirty(m);
			if (oldpde & PG_A)
				vm_page_aflag_set(m, PGA_REFERENCED);
			if (TAILQ_EMPTY(&m->md.pv_list) &&
			    TAILQ_EMPTY(&pvh->pv_list))
				vm_page_aflag_clear(m, PGA_WRITEABLE);
		}
	}
	if (pmap == kernel_pmap) {
		pmap_remove_kernel_pde(pmap, pdq, sva);
	} else {
		mpte = pmap_lookup_pt_page(pmap, sva);
		if (mpte != NULL) {
			pmap_remove_pt_page(pmap, mpte);
			pmap->pm_stats.resident_count--;
			KASSERT(mpte->wire_count == NPTEPG,
			    ("pmap_remove_pde: 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);
		}
	}
}
static void pmap_remove_pde ( pmap_t pmap , pd_entry_t * pdq , vm_offset_t sva , struct spglist * free ) { struct md_page * pvh ; pd_entry_t oldpde ; vm_offset_t eva , va ; vm_page_t m , mpte ; PMAP_LOCK_ASSERT ( pmap , MA_OWNED ) ; KASSERT ( ( sva & PDRMASK ) == 0 , ( " " ) ) ; oldpde = pte_load_clear ( pdq ) ; if ( oldpde & PG_W ) pmap -> pm_stats . wired_count -= NBPDR / PAGE_SIZE ; if ( oldpde & PG_G ) pmap_invalidate_page ( kernel_pmap , sva ) ; pmap -> pm_stats . resident_count -= NBPDR / PAGE_SIZE ; if ( oldpde & PG_MANAGED ) { pvh = pa_to_pvh ( oldpde & PG_PS_FRAME ) ; pmap_pvh_free ( pvh , pmap , sva ) ; eva = sva + NBPDR ; for ( va = sva , m = PHYS_TO_VM_PAGE ( oldpde & PG_PS_FRAME ) ; va < eva ; va += PAGE_SIZE , m ++ ) { if ( ( oldpde & ( PG_M | PG_RW ) ) == ( PG_M | PG_RW ) ) vm_page_dirty ( m ) ; if ( oldpde & PG_A ) vm_page_aflag_set ( m , PGA_REFERENCED ) ; if ( TAILQ_EMPTY ( & m -> md . pv_list ) && TAILQ_EMPTY ( & pvh -> pv_list ) ) vm_page_aflag_clear ( m , PGA_WRITEABLE ) ; } } if ( pmap == kernel_pmap ) { pmap_remove_kernel_pde ( pmap , pdq , sva ) ; } else { mpte = pmap_lookup_pt_page ( pmap , sva ) ; 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 ) ; } } }
pmap_remove_pde: do the things to unmap a superpage in a process
pmap_remove_pde : do the things to unmap a superpage in a process
/*
	 * Machines that don't support invlpg, also don't support
	 * PG_G.
	 */