FreeBSD/sys/arm/arm/pmap-v6.c
/*
 *	Copy the range specified by src_addr/len
 *	from the source map to the range dst_addr/len
 *	in the destination map.
 *
 *	This routine is only advisory and need not do anything.
 */
Copy the range specified by src_addr/len
from the source map to the range dst_addr/len
in the destination map.

This routine is only advisory and need not do anything.
Copy the range specified by src_addr / len from the source map to the range dst_addr / len in the destination map . This routine is only advisory and need not do anything .
void
pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr, vm_size_t len,
    vm_offset_t src_addr)
{
	struct spglist free;
	vm_offset_t addr;
	vm_offset_t end_addr = src_addr + len;
	vm_offset_t nextva;
	if (dst_addr != src_addr)
		return;
	if (!pmap_is_current(src_pmap))
		return;
	rw_wlock(&pvh_global_lock);
	if (dst_pmap < src_pmap) {
		PMAP_LOCK(dst_pmap);
		PMAP_LOCK(src_pmap);
	} else {
		PMAP_LOCK(src_pmap);
		PMAP_LOCK(dst_pmap);
	}
	sched_pin();
	for (addr = src_addr; addr < end_addr; addr = nextva) {
		pt2_entry_t *src_pte2p, *dst_pte2p;
		vm_page_t dst_mpt2pg, src_mpt2pg;
		pt1_entry_t src_pte1;
		u_int pte1_idx;
		KASSERT(addr < VM_MAXUSER_ADDRESS,
		    ("%s: invalid to pmap_copy page tables", __func__));
		nextva = pte1_trunc(addr + PTE1_SIZE);
		if (nextva < addr)
			nextva = end_addr;
		pte1_idx = pte1_index(addr);
		src_pte1 = src_pmap->pm_pt1[pte1_idx];
		if (pte1_is_section(src_pte1)) {
			if ((addr & PTE1_OFFSET) != 0 ||
			    (addr + PTE1_SIZE) > end_addr)
				continue;
			if (dst_pmap->pm_pt1[pte1_idx] == 0 &&
			    (!pte1_is_managed(src_pte1) ||
			    pmap_pv_insert_pte1(dst_pmap, addr,
			    pte1_pa(src_pte1)))) {
				dst_pmap->pm_pt1[pte1_idx] = src_pte1 &
				    ~PTE1_W;
				dst_pmap->pm_stats.resident_count +=
				    PTE1_SIZE / PAGE_SIZE;
				pmap_pte1_mappings++;
			}
			continue;
		} else if (!pte1_is_link(src_pte1))
			continue;
		src_mpt2pg = PHYS_TO_VM_PAGE(pte1_link_pa(src_pte1));
#if 0 
		KASSERT(pt2_wirecount_get(src_mpt2pg, pte1_idx) > 0,
		    ("%s: source page table page is unused", __func__));
#else
		if (pt2_wirecount_get(src_mpt2pg, pte1_idx) == 0)
			continue;
#endif
		if (nextva > end_addr)
			nextva = end_addr;
		src_pte2p = pt2map_entry(addr);
		while (addr < nextva) {
			pt2_entry_t temp_pte2;
			temp_pte2 = pte2_load(src_pte2p);
			if (pte2_is_managed(temp_pte2)) {
				dst_mpt2pg = pmap_allocpte2(dst_pmap, addr,
				    PMAP_ENTER_NOSLEEP);
				if (dst_mpt2pg == NULL)
					goto out;
				dst_pte2p = pmap_pte2_quick(dst_pmap, addr);
				if (!pte2_is_valid(pte2_load(dst_pte2p)) &&
				    pmap_try_insert_pv_entry(dst_pmap, addr,
				    PHYS_TO_VM_PAGE(pte2_pa(temp_pte2)))) {
					temp_pte2 &=  ~(PTE2_W | PTE2_A);
					temp_pte2 |= PTE2_NM;
					pte2_store(dst_pte2p, temp_pte2);
					dst_pmap->pm_stats.resident_count++;
				} else {
					SLIST_INIT(&free);
					if (pmap_unwire_pt2(dst_pmap, addr,
					    dst_mpt2pg, &free)) {
						pmap_tlb_flush(dst_pmap, addr);
						pmap_free_zero_pages(&free);
					}
					goto out;
				}
				if (pt2_wirecount_get(dst_mpt2pg, pte1_idx) >=
				    pt2_wirecount_get(src_mpt2pg, pte1_idx))
					break;
			}
			addr += PAGE_SIZE;
			src_pte2p++;
		}
	}
out:
	sched_unpin();
	rw_wunlock(&pvh_global_lock);
	PMAP_UNLOCK(src_pmap);
	PMAP_UNLOCK(dst_pmap);
}
void pmap_copy ( pmap_t dst_pmap , pmap_t src_pmap , vm_offset_t dst_addr , vm_size_t len , vm_offset_t src_addr ) { struct spglist free ; vm_offset_t addr ; vm_offset_t end_addr = src_addr + len ; vm_offset_t nextva ; if ( dst_addr != src_addr ) return ; if ( ! pmap_is_current ( src_pmap ) ) return ; rw_wlock ( & pvh_global_lock ) ; if ( dst_pmap < src_pmap ) { PMAP_LOCK ( dst_pmap ) ; PMAP_LOCK ( src_pmap ) ; } else { PMAP_LOCK ( src_pmap ) ; PMAP_LOCK ( dst_pmap ) ; } sched_pin ( ) ; for ( addr = src_addr ; addr < end_addr ; addr = nextva ) { pt2_entry_t * src_pte2p , * dst_pte2p ; vm_page_t dst_mpt2pg , src_mpt2pg ; pt1_entry_t src_pte1 ; u_int pte1_idx ; KASSERT ( addr < VM_MAXUSER_ADDRESS , ( " " , __func__ ) ) ; nextva = pte1_trunc ( addr + PTE1_SIZE ) ; if ( nextva < addr ) nextva = end_addr ; pte1_idx = pte1_index ( addr ) ; src_pte1 = src_pmap -> pm_pt1 [ pte1_idx ] ; if ( pte1_is_section ( src_pte1 ) ) { if ( ( addr & PTE1_OFFSET ) != 0 || ( addr + PTE1_SIZE ) > end_addr ) continue ; if ( dst_pmap -> pm_pt1 [ pte1_idx ] == 0 && ( ! pte1_is_managed ( src_pte1 ) || pmap_pv_insert_pte1 ( dst_pmap , addr , pte1_pa ( src_pte1 ) ) ) ) { dst_pmap -> pm_pt1 [ pte1_idx ] = src_pte1 & ~ PTE1_W ; dst_pmap -> pm_stats . resident_count += PTE1_SIZE / PAGE_SIZE ; pmap_pte1_mappings ++ ; } continue ; } else if ( ! pte1_is_link ( src_pte1 ) ) continue ; src_mpt2pg = PHYS_TO_VM_PAGE ( pte1_link_pa ( src_pte1 ) ) ; #if 0 KASSERT ( pt2_wirecount_get ( src_mpt2pg , pte1_idx ) > 0 , ( " " , __func__ ) ) ; #else if ( pt2_wirecount_get ( src_mpt2pg , pte1_idx ) == 0 ) continue ; #endif if ( nextva > end_addr ) nextva = end_addr ; src_pte2p = pt2map_entry ( addr ) ; while ( addr < nextva ) { pt2_entry_t temp_pte2 ; temp_pte2 = pte2_load ( src_pte2p ) ; if ( pte2_is_managed ( temp_pte2 ) ) { dst_mpt2pg = pmap_allocpte2 ( dst_pmap , addr , PMAP_ENTER_NOSLEEP ) ; if ( dst_mpt2pg == NULL ) goto out ; dst_pte2p = pmap_pte2_quick ( dst_pmap , addr ) ; if ( ! pte2_is_valid ( pte2_load ( dst_pte2p ) ) && pmap_try_insert_pv_entry ( dst_pmap , addr , PHYS_TO_VM_PAGE ( pte2_pa ( temp_pte2 ) ) ) ) { temp_pte2 &= ~ ( PTE2_W | PTE2_A ) ; temp_pte2 |= PTE2_NM ; pte2_store ( dst_pte2p , temp_pte2 ) ; dst_pmap -> pm_stats . resident_count ++ ; } else { SLIST_INIT ( & free ) ; if ( pmap_unwire_pt2 ( dst_pmap , addr , dst_mpt2pg , & free ) ) { pmap_tlb_flush ( dst_pmap , addr ) ; pmap_free_zero_pages ( & free ) ; } goto out ; } if ( pt2_wirecount_get ( dst_mpt2pg , pte1_idx ) >= pt2_wirecount_get ( src_mpt2pg , pte1_idx ) ) break ; } addr += PAGE_SIZE ; src_pte2p ++ ; } } out : sched_unpin ( ) ; rw_wunlock ( & pvh_global_lock ) ; PMAP_UNLOCK ( src_pmap ) ; PMAP_UNLOCK ( dst_pmap ) ; }
Copy the range specified by src_addr/len
      from the source map to the range dst_addr/len
      in the destination map.
Copy the range specified by src_addr / len from the source map to the range dst_addr / len in the destination map .
/*
		 * We leave PT2s to be linked from PT1 even if they are not
		 * referenced until all PT2s in a page are without reference.
		 *
		 * QQQ: It could be changed ...
		 */ /* single_pt2_link_is_cleared */ /*
			 * we only virtual copy managed pages
			 */ /*
					 * Clear the wired, modified, and
					 * accessed (referenced) bits
					 * during the copy.
					 */