bcopy(&PTD[KPTDI], &pmap->pm_pdir[KPTDI], NKPDE * sizeof(pd_entry_t));
bcopy(&PTD[KPTDI], &pmap->pm_pdir[KPTDI], MAXKPDE * sizeof(pd_entry_t));
pt_entry_t *pmap_pte __P((pmap_t, vm_offset_t));struct pv_entry * pmap_alloc_pv __P((void));void pmap_free_pv __P((struct pv_entry *));void i386_protection_init __P((void));void pmap_collect_pv __P((void));__inline void pmap_remove_pv __P((pmap_t, vm_offset_t, u_int));__inline void pmap_enter_pv __P((pmap_t, vm_offset_t, u_int));void pmap_deactivate __P((pmap_t, struct pcb *));void pmap_remove_all __P((vm_offset_t));void pads __P((pmap_t pm));void pmap_dump_pvlist __P((vm_offset_t phys, char *m));void pmap_pvdump __P((vm_offset_t pa));#if BSDVM_COMPAT#include <sys/msgbuf.h>/* * All those kernel PT submaps that BSD is so fond of */pt_entry_t	*CMAP1, *CMAP2, *XXX_mmap;caddr_t		CADDR1, CADDR2, vmmap;pt_entry_t	*msgbufmap;#endif	/* BSDVM_COMPAT *//* *	Bootstrap the system enough to run with virtual memory. *	Map the kernel's code and data, and allocate the system page table. * *	On the I386 this is called after mapping has already been enabled *	and just syncs the pmap module with what has already been done. *	[We can't call it easily with mapping off since the kernel is not *	mapped with PA == VA, hence we would have to relocate every address *	from the linked base (virtual) address to the actual (physical) *	address starting relative to 0] */voidpmap_bootstrap(virtual_start)	vm_offset_t virtual_start;{#if BSDVM_COMPAT	vm_offset_t va;	pt_entry_t *pte;#endif	/* XXX: allow for msgbuf */	avail_end -= i386_round_page(sizeof(struct msgbuf));	virtual_avail = virtual_start;	virtual_end = VM_MAX_KERNEL_ADDRESS;	/*	 * Initialize protection array.	 */	i386_protection_init();#ifdef notdef	/*	 * Create Kernel page directory table and page maps.	 * [ currently done in locore. i have wild and crazy ideas -wfj ]	 */	bzero(firstaddr, (1+NKPDE)*NBPG);	pmap_kernel()->pm_pdir = firstaddr + VM_MIN_KERNEL_ADDRESS;	pmap_kernel()->pm_ptab = firstaddr + VM_MIN_KERNEL_ADDRESS + NBPG;	firstaddr += NBPG;	for (x = i386_btod(VM_MIN_KERNEL_ADDRESS);	     x < i386_btod(VM_MIN_KERNEL_ADDRESS) + NKPDE; x++) {		pd_entry_t *pde;		pde = pmap_kernel()->pm_pdir + x;		*pde = (firstaddr + x*NBPG) | PG_V | PG_KW;	}#else	pmap_kernel()->pm_pdir =	    (pd_entry_t *)(proc0.p_addr->u_pcb.pcb_cr3 + KERNBASE);#endif	simple_lock_init(&pmap_kernel()->pm_lock);	pmap_kernel()->pm_count = 1;#if BSDVM_COMPAT	/*	 * Allocate all the submaps we need	 */#define	SYSMAP(c, p, v, n)	\	v = (c)va; va += ((n)*NBPG); p = pte; pte += (n);	va = virtual_avail;	pte = pmap_pte(pmap_kernel(), va);	SYSMAP(caddr_t		,CMAP1		,CADDR1	   ,1		)	SYSMAP(caddr_t		,CMAP2		,CADDR2	   ,1		)	SYSMAP(caddr_t		,XXX_mmap	,vmmap	   ,1		)	SYSMAP(struct msgbuf *	,msgbufmap	,msgbufp   ,1		)	virtual_avail = va;#endif	/*	 * Reserve pmap space for mapping physical pages during dump.	 */	virtual_avail = reserve_dumppages(virtual_avail);	/*	 * reserve special hunk of memory for use by bus dma as a bounce	 * buffer (contiguous virtual *and* physical memory).  XXX	 */#if NISA > 0 && NISADMA > 0	if (ctob(physmem) >= 0x1000000) {		isaphysmem = pmap_steal_memory(DMA_BOUNCE * NBPG);		isaphysmempgs = DMA_BOUNCE;	} else {		isaphysmem = pmap_steal_memory(DMA_BOUNCE_LOW * NBPG);		isaphysmempgs = DMA_BOUNCE_LOW;	}#endif	pmap_update();}voidpmap_virtual_space(startp, endp)	vm_offset_t *startp;	vm_offset_t *endp;{	*startp = virtual_avail;	*endp = virtual_end;}/* *	Initialize the pmap module. *	Called by vm_init, to initialize any structures that the pmap *	system needs to map virtual memory. */voidpmap_init(){	vm_offset_t addr;	vm_size_t s;	if (PAGE_SIZE != NBPG)		panic("pmap_init: CLSIZE != 1");	npages = pmap_page_index(avail_end - 1) + 1;	s = (vm_size_t) (sizeof(struct pv_entry) * npages + npages);	s = round_page(s);	addr = (vm_offset_t) kmem_alloc(kernel_map, s);	pv_table = (struct pv_entry *) addr;	addr += sizeof(struct pv_entry) * npages;	pmap_attributes = (char *) addr;	TAILQ_INIT(&pv_page_freelist);#ifdef DEBUG	if (pmapdebug & PDB_INIT)		printf("pmap_init: %x bytes (%x pgs): tbl %x attr %x\n",		       s, npages, pv_table, pmap_attributes);#endif	/*	 * Now it is safe to enable pv_table recording.	 */	pmap_initialized = TRUE;}struct pv_entry *pmap_alloc_pv(){	struct pv_page *pvp;	struct pv_entry *pv;	int i;	if (pv_nfree == 0) {		pvp = (struct pv_page *)kmem_alloc(kernel_map, NBPG);		if (pvp == 0)			panic("pmap_alloc_pv: kmem_alloc() failed");		pvp->pvp_pgi.pgi_freelist = pv = &pvp->pvp_pv[1];		for (i = NPVPPG - 2; i; i--, pv++)			pv->pv_next = pv + 1;		pv->pv_next = 0;		pv_nfree += pvp->pvp_pgi.pgi_nfree = NPVPPG - 1;		TAILQ_INSERT_HEAD(&pv_page_freelist, pvp, pvp_pgi.pgi_list);		pv = &pvp->pvp_pv[0];	} else {		--pv_nfree;		pvp = pv_page_freelist.tqh_first;		if (--pvp->pvp_pgi.pgi_nfree == 0) {			TAILQ_REMOVE(&pv_page_freelist, pvp, pvp_pgi.pgi_list);		}		pv = pvp->pvp_pgi.pgi_freelist;#ifdef DIAGNOSTIC		if (pv == 0)			panic("pmap_alloc_pv: pgi_nfree inconsistent");#endif		pvp->pvp_pgi.pgi_freelist = pv->pv_next;	}	return pv;}voidpmap_free_pv(pv)	struct pv_entry *pv;{	register struct pv_page *pvp;	pvp = (struct pv_page *) trunc_page(pv);	switch (++pvp->pvp_pgi.pgi_nfree) {	case 1:		TAILQ_INSERT_TAIL(&pv_page_freelist, pvp, pvp_pgi.pgi_list);	default:		pv->pv_next = pvp->pvp_pgi.pgi_freelist;		pvp->pvp_pgi.pgi_freelist = pv;		++pv_nfree;		break;	case NPVPPG:		pv_nfree -= NPVPPG - 1;		TAILQ_REMOVE(&pv_page_freelist, pvp, pvp_pgi.pgi_list);		kmem_free(kernel_map, (vm_offset_t)pvp, NBPG);		break;	}}voidpmap_collect_pv(){	struct pv_page_list pv_page_collectlist;	struct pv_page *pvp, *npvp;	struct pv_entry *ph, *ppv, *pv, *npv;	int s;	TAILQ_INIT(&pv_page_collectlist);	for (pvp = pv_page_freelist.tqh_first; pvp; pvp = npvp) {		if (pv_nfree < NPVPPG)			break;		npvp = pvp->pvp_pgi.pgi_list.tqe_next;		if (pvp->pvp_pgi.pgi_nfree > NPVPPG / 3) {			TAILQ_REMOVE(&pv_page_freelist, pvp, pvp_pgi.pgi_list);			TAILQ_INSERT_TAIL(&pv_page_collectlist, pvp, pvp_pgi.pgi_list);			pv_nfree -= pvp->pvp_pgi.pgi_nfree;			pvp->pvp_pgi.pgi_nfree = -1;		}	}	if (pv_page_collectlist.tqh_first == 0)		return;	for (ph = &pv_table[npages - 1]; ph >= &pv_table[0]; ph--) {		if (ph->pv_pmap == 0)			continue;		s = splimp();		for (ppv = ph; (pv = ppv->pv_next) != 0; ) {			pvp = (struct pv_page *) trunc_page(pv);			if (pvp->pvp_pgi.pgi_nfree == -1) {				pvp = pv_page_freelist.tqh_first;				if (--pvp->pvp_pgi.pgi_nfree == 0) {					TAILQ_REMOVE(&pv_page_freelist, pvp, pvp_pgi.pgi_list);				}				npv = pvp->pvp_pgi.pgi_freelist;#ifdef DIAGNOSTIC				if (npv == 0)					panic("pmap_collect_pv: pgi_nfree inconsistent");#endif				pvp->pvp_pgi.pgi_freelist = npv->pv_next;				*npv = *pv;				ppv->pv_next = npv;				ppv = npv;			} else				ppv = pv;		}		splx(s);	}	for (pvp = pv_page_collectlist.tqh_first; pvp; pvp = npvp) {		npvp = pvp->pvp_pgi.pgi_list.tqe_next;		kmem_free(kernel_map, (vm_offset_t)pvp, NBPG);	}}__inline voidpmap_enter_pv(pmap, va, pind)	register pmap_t pmap;	vm_offset_t va;	u_int pind;{		register struct pv_entry *pv, *npv;	int s;	if (!pmap_initialized)		return;#ifdef DEBUG	if (pmapdebug & PDB_ENTER)		printf("pmap_enter_pv: pv %x: %x/%x/%x\n",		       pv, pv->pv_va, pv->pv_pmap, pv->pv_next);#endif	pv = &pv_table[pind];	s = splimp();	if (pv->pv_pmap == NULL) {		/*		 * No entries yet, use header as the first entry		 */#ifdef DEBUG		enter_stats.firstpv++;#endif		pv->pv_va = va;		pv->pv_pmap = pmap;		pv->pv_next = NULL;	} else {		/*		 * There is at least one other VA mapping this page.		 * Place this entry after the header.		 */#ifdef DEBUG		for (npv = pv; npv; npv = npv->pv_next)			if (pmap == npv->pv_pmap && va == npv->pv_va)				panic("pmap_enter_pv: already in pv_tab");#endif		npv = pmap_alloc_pv();		npv->pv_va = va;		npv->pv_pmap = pmap;		npv->pv_next = pv->pv_next;		pv->pv_next = npv;#ifdef DEBUG		if (!npv->pv_next)			enter_stats.secondpv++;#endif	}	splx(s);}__inline voidpmap_remove_pv(pmap, va, pind)	register pmap_t pmap;	vm_offset_t va;	u_int pind;{		register struct pv_entry *pv, *npv;	int s;	/*	 * Remove from the PV table (raise IPL since we	 * may be called at interrupt time).	 */	pv = &pv_table[pind];	s = splimp();	/*	 * If it is the first entry on the list, it is actually	 * in the header and we must copy the following entry up	 * to the header.  Otherwise we must search the list for	 * the entry.  In either case we free the now unused entry.	 */	if (pmap == pv->pv_pmap && va == pv->pv_va) {		npv = pv->pv_next;		if (npv) {			*pv = *npv;			pmap_free_pv(npv);		} else			pv->pv_pmap = NULL;	} else {		for (npv = pv->pv_next; npv; pv = npv, npv = npv->pv_next) {			if (pmap == npv->pv_pmap && va == npv->pv_va)				break;		}		if (npv) {			pv->pv_next = npv->pv_next;			pmap_free_pv(npv);		}	}	splx(s);}/* *	Used to map a range of physical addresses into kernel *	virtual address space. * *	For now, VM is already on, we only need to map the *	specified memory. */vm_offset_tpmap_map(va, spa, epa, prot)	vm_offset_t va, spa, epa;	int prot;{#ifdef DEBUG	if (pmapdebug & PDB_FOLLOW)		printf("pmap_map(%x, %x, %x, %x)\n", va, spa, epa, prot);#endif	while (spa < epa) {		pmap_enter(pmap_kernel(), va, spa, prot, FALSE);		va += NBPG;		spa += NBPG;	}	return va;}/* *	Create and return a physical map. * *	If the size specified for the map *	is zero, the map is an actual physical *	map, and may be referenced by the *	hardware. * *	If the size specified is non-zero, *	the map will be used in software only, and *	is bounded by that size. * * [ just allocate a ptd and mark it uninitialize -- should we track *   with a table which process has which ptd? -wfj ] */pmap_tpmap_create(size)	vm_size_t size;{	register pmap_t pmap;#ifdef DEBUG	if (pmapdebug & (PDB_FOLLOW|PDB_CREATE))		printf("pmap_create(%x)\n", size);#endif	/*	 * Software use map does not need a pmap	 */	if (size)		return NULL;	pmap = (pmap_t) malloc(sizeof *pmap, M_VMPMAP, M_WAITOK);	bzero(pmap, sizeof(*pmap));	pmap_pinit(pmap);	return pmap;}/* * Initialize a preallocated and zeroed pmap structure, * such as one in a vmspace structure. */voidpmap_pinit(pmap)	register struct pmap *pmap;{#ifdef DEBUG	if (pmapdebug & (PDB_FOLLOW|PDB_CREATE))		printf("pmap_pinit(%x)\n", pmap);#endif	/*	 * No need to allocate page table space yet but we do need a	 * valid page directory table.	 */	pmap->pm_pdir = (pd_entry_t *) kmem_alloc(kernel_map, NBPG);	/* wire in kernel global address entries */	bcopy(&PTD[KPTDI], &pmap->pm_pdir[KPTDI], NKPDE * sizeof(pd_entry_t));	/* install self-referential address mapping entry */	pmap->pm_pdir[PTDPTDI] =	    pmap_extract(pmap_kernel(), (vm_offset_t)pmap->pm_pdir) | PG_V | PG_KW;	pmap->pm_count = 1;	simple_lock_init(&pmap->pm_lock);}/* *	Retire the given physical map from service. *	Should only be called if the map contains *	no valid mappings. */voidpmap_destroy(pmap)	register pmap_t pmap;{	int count;	if (pmap == NULL)		return;#ifdef DEBUG	if (pmapdebug & PDB_FOLLOW)		printf("pmap_destroy(%x)\n", pmap);#endif	simple_lock(&pmap->pm_lock);	count = --pmap->pm_count;	simple_unlock(&pmap->pm_lock);	if (count == 0) {		pmap_release(pmap);		free((caddr_t)pmap, M_VMPMAP);	}}/* * Release any resources held by the given physical map. * Called when a pmap initialized by pmap_pinit is being released. * Should only be called if the map contains no valid mappings. */voidpmap_release(pmap)	register struct pmap *pmap;{#ifdef DEBUG	if (pmapdebug & PDB_FOLLOW)		printf("pmap_release(%x)\n", pmap);#endif#ifdef DIAGNOSTICx	/* sometimes 1, sometimes 0; could rearrange pmap_destroy */	if (pmap->pm_count != 1)		panic("pmap_release count");#endif	kmem_free(kernel_map, (vm_offset_t)pmap->pm_pdir, NBPG);}/* *	Add a reference to the specified pmap. */voidpmap_reference(pmap)	pmap_t pmap;{	if (pmap == NULL)		return;#ifdef DEBUG	if (pmapdebug & PDB_FOLLOW)		printf("pmap_reference(%x)", pmap);#endif	simple_lock(&pmap->pm_lock);	pmap->pm_count++;	simple_unlock(&pmap->pm_lock);}voidpmap_activate(pmap, pcb)	pmap_t pmap;	struct pcb *pcb;{	if (pmap /*&& pmap->pm_pdchanged */) {		pcb->pcb_cr3 =		    pmap_extract(pmap_kernel(), (vm_offset_t)pmap->pm_pdir);		if (pmap == &curproc->p_vmspace->vm_pmap)			lcr3(pcb->pcb_cr3);		pmap->pm_pdchanged = FALSE;	}}voidpmap_deactivate(pmap, pcb)	pmap_t pmap;	struct pcb *pcb;{}/* *	Remove the given range of addresses from the specified map. * *	It is assumed that the start and end are properly *	rounded to the page size. */voidpmap_remove(pmap, sva, eva)	struct pmap *pmap;	register vm_offset_t sva, eva;{	register pt_entry_t *pte;	vm_offset_t pa;	u_int pind;	int flush = 0;	sva &= PG_FRAME;	eva &= PG_FRAME;	/*	 * We need to acquire a pointer to a page table page before entering	 * the following loop.	 */	while (sva < eva) {		pte = pmap_pte(pmap, sva);		if (pte)			break;		sva = (sva & PD_MASK) + NBPD;	}	while (sva < eva) {		/* only check once in a while */		if ((sva & PT_MASK) == 0) {			if (!pmap_pde_v(pmap_pde(pmap, sva))) {				/* We can race ahead here, to the next pde. */				sva += NBPD;				pte += i386_btop(NBPD);				continue;			}		}		if (!pmap_pte_v(pte)) {#ifdef __GNUC__			/*			 * Scan ahead in a tight loop for the next used PTE in			 * this page.  We don't scan the whole region here			 * because we don't want to zero-fill unused page table			 * pages.			 */			int n, m;			n = min(eva - sva, NBPD - (sva & PT_MASK)) >> PGSHIFT;			__asm __volatile(			    "cld\n\trepe\n\tscasl\n\tje 1f\n\tincl %1\n\t1:"			    : "=D" (pte), "=c" (m)			    : "0" (pte), "1" (n), "a" (0));			sva += (n - m) << PGSHIFT;			if (!m)				continue;			/* Overshot. */			--pte;#else			goto next;#endif		}		flush = 1;		/*		 * Update statistics		 */		if (pmap_pte_w(pte))			pmap->pm_stats.wired_count--;		pmap->pm_stats.resident_count--;		pa = pmap_pte_pa(pte);		/*		 * Invalidate the PTEs.		 * XXX: should cluster them up and invalidate as many		 * as possible at once.		 */#ifdef DEBUG		if (pmapdebug & PDB_REMOVE)			printf("remove: inv pte at %x(%x) ", pte, *pte);#endif#ifdef needednotdonereduce wiring count on page table pages as references drop#endif		if ((pind = pmap_page_index(pa)) != -1) {			pmap_attributes[pind] |= *pte & (PG_M | PG_U);			pmap_remove_pv(pmap, sva, pind);		}		*pte = 0;#ifndef __GNUC__	next:#endif		sva += NBPG;		pte++;	}	if (flush)		pmap_update();}/* *	Routine:	pmap_remove_all *	Function: *		Removes this physical page from *		all physical maps in which it resides. *		Reflects back modify bits to the pager. */voidpmap_remove_all(pa)	vm_offset_t pa;{	struct pv_entry *ph, *pv, *npv;	register pmap_t pmap;	register pt_entry_t *pte;	u_int pind;	int s;#ifdef DEBUG	if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT))		printf("pmap_remove_all(%x)", pa);	/*pmap_pvdump(pa);*/#endif	if ((pind = pmap_page_index(pa)) == -1)		return;	pv = ph = &pv_table[pind];	s = splimp();	if (ph->pv_pmap == NULL) {		splx(s);		return;	}	while (pv) {		pmap = pv->pv_pmap;		pte = pmap_pte(pmap, pv->pv_va);#ifdef DEBUG		if (!pte || !pmap_pte_v(pte) || pmap_pte_pa(pte) != pa)			panic("pmap_remove_all: bad mapping");#endif		/*		 * Update statistics		 */		if (pmap_pte_w(pte))			pmap->pm_stats.wired_count--;		pmap->pm_stats.resident_count--;		/*		 * Invalidate the PTEs.		 * XXX: should cluster them up and invalidate as many		 * as possible at once.		 */#ifdef DEBUG		if (pmapdebug & PDB_REMOVE)			printf("remove: inv pte at %x(%x) ", pte, *pte);#endif#ifdef needednotdonereduce wiring count on page table pages as references drop#endif		/*		 * Update saved attributes for managed page		 */		pmap_attributes[pind] |= *pte & (PG_M | PG_U);		*pte = 0;		npv = pv->pv_next;		if (pv == ph)			ph->pv_pmap = NULL;		else			pmap_free_pv(pv);		pv = npv;	}	splx(s);	pmap_update();}/* *	Set the physical protection on the *	specified range of this map as requested. */voidpmap_protect(pmap, sva, eva, prot)	register pmap_t pmap;	vm_offset_t sva, eva;	vm_prot_t prot;{	register pt_entry_t *pte;	register int i386prot;	int flush = 0;#ifdef DEBUG	if (pmapdebug & (PDB_FOLLOW|PDB_PROTECT))		printf("pmap_protect(%x, %x, %x, %x)", pmap, sva, eva, prot);#endif	if ((prot & VM_PROT_READ) == VM_PROT_NONE) {		pmap_remove(pmap, sva, eva);		return;	}	if (prot & VM_PROT_WRITE)		return;	sva &= PG_FRAME;	eva &= PG_FRAME;	/*	 * We need to acquire a pointer to a page table page before entering	 * the following loop.	 */	while (sva < eva) {		pte = pmap_pte(pmap, sva);		if (pte)			break;		sva = (sva & PD_MASK) + NBPD;	}	while (sva < eva) {		/* only check once in a while */		if ((sva & PT_MASK) == 0) {			if (!pmap_pde_v(pmap_pde(pmap, sva))) {				/* We can race ahead here, to the next pde. */				sva += NBPD;				pte += i386_btop(NBPD);				continue;			}		}		if (!pmap_pte_v(pte)) {#ifdef __GNUC__			/*			 * Scan ahead in a tight loop for the next used PTE in			 * this page.  We don't scan the whole region here			 * because we don't want to zero-fill unused page table			 * pages.			 */			int n, m;			n = min(eva - sva, NBPD - (sva & PT_MASK)) >> PGSHIFT;			__asm __volatile(			    "cld\n\trepe\n\tscasl\n\tje 1f\n\tincl %1\n\t1:"			    : "=D" (pte), "=c" (m)			    : "0" (pte), "1" (n), "a" (0));			sva += (n - m) << PGSHIFT;			if (!m)				continue;			/* Overshot. */			--pte;#else			goto next;#endif		}		flush = 1;		i386prot = protection_codes[prot];		if (sva < VM_MAXUSER_ADDRESS)	/* see also pmap_enter() */			i386prot |= PG_u;		else if (sva < VM_MAX_ADDRESS)			i386prot |= PG_u | PG_RW;		pmap_pte_set_prot(pte, i386prot);#ifndef __GNUC__	next:#endif		sva += NBPG;		pte++;	}	if (flush)		pmap_update();}/* *	Insert the given physical page (p) at *	the specified virtual address (v) in the *	target physical map with the protection requested. * *	If specified, the page will be wired down, meaning *	that the related pte can not be reclaimed. * *	NB:  This is the only routine which MAY NOT lazy-evaluate *	or lose information.  That is, this routine must actually *	insert this page into the given map NOW. */voidpmap_enter(pmap, va, pa, prot, wired)	register pmap_t pmap;	vm_offset_t va;	register vm_offset_t pa;	vm_prot_t prot;	boolean_t wired;{	register pt_entry_t *pte;	register pt_entry_t npte;	u_int pind;	int flush = 0;	boolean_t cacheable;#ifdef DEBUG	if (pmapdebug & (PDB_FOLLOW|PDB_ENTER))		printf("pmap_enter(%x, %x, %x, %x, %x)",		       pmap, va, pa, prot, wired);#endif	if (pmap == NULL)		return;	if (va >= VM_MAX_KERNEL_ADDRESS)		panic("pmap_enter: too big");	/* also, should not muck with PTD va! */#ifdef DEBUG	if (pmap == pmap_kernel())		enter_stats.kernel++;	else		enter_stats.user++;#endif	pte = pmap_pte(pmap, va);	if (!pte) {		/*		 * Page Directory table entry not valid, we need a new PT page		 *		 * we want to vm_fault in a new zero-filled PT page for our		 * use.   in order to do this, we want to call vm_fault()		 * with the VA of where we want to put the PTE.   but in		 * order to call vm_fault() we need to know which vm_map		 * we are faulting in.    in the m68k pmap's this is easy		 * since all PT pages live in one global vm_map ("pt_map")		 * and we have a lot of virtual space we can use for the		 * pt_map (since the kernel doesn't have to share its 4GB		 * address space with processes).    but in the i386 port		 * the kernel must live in the top part of the virtual 		 * address space and PT pages live in their process' vm_map		 * rather than a global one.    the problem is that we have		 * no way of knowing which vm_map is the correct one to 		 * fault on.		 * 		 * XXX: see NetBSD PR#1834 and Mycroft's posting to 		 *	tech-kern on 7 Jan 1996.		 *		 * rather than always calling panic, we try and make an 		 * educated guess as to which vm_map to use by using curproc.		 * this is a workaround and may not fully solve the problem?	 	 */		struct vm_map *vmap;		int rv;		vm_offset_t v;		if (curproc == NULL || curproc->p_vmspace == NULL ||		  	pmap != &curproc->p_vmspace->vm_pmap)				panic("ptdi %x", pmap->pm_pdir[PTDPTDI]);		/* our guess about the vm_map was good!  fault it in.  */		vmap = &curproc->p_vmspace->vm_map;		v = trunc_page(vtopte(va));		rv = vm_fault(vmap, v, VM_PROT_READ|VM_PROT_WRITE, FALSE);		if (rv != KERN_SUCCESS)			panic("ptdi2 %x", pmap->pm_pdir[PTDPTDI]);		vm_map_pageable(vmap, v, round_page(v+1), FALSE);		pte = pmap_pte(pmap, va);		if (!pte) 			panic("ptdi3 %x", pmap->pm_pdir[PTDPTDI]);	}#ifdef DEBUG	if (pmapdebug & PDB_ENTER)		printf("enter: pte %x, *pte %x ", pte, *pte);#endif	if (pmap_pte_v(pte)) {		register vm_offset_t opa;		/*		 * Check for wiring change and adjust statistics.		 */		if ((wired && !pmap_pte_w(pte)) ||		    (!wired && pmap_pte_w(pte))) {			/*			 * We don't worry about wiring PT pages as they remain			 * resident as long as there are valid mappings in them.			 * Hence, if a user page is wired, the PT page will be also.			 */#ifdef DEBUG			if (pmapdebug & PDB_ENTER)				printf("enter: wiring change -> %x ", wired);#endif			if (wired)				pmap->pm_stats.wired_count++;			else				pmap->pm_stats.wired_count--;#ifdef DEBUG			enter_stats.wchange++;#endif		}		flush = 1;		opa = pmap_pte_pa(pte);		/*		 * Mapping has not changed, must be protection or wiring change.		 */		if (opa == pa) {#ifdef DEBUG			enter_stats.pwchange++;#endif			goto validate;		}				/*		 * Mapping has changed, invalidate old range and fall through to		 * handle validating new mapping.		 */#ifdef DEBUG		if (pmapdebug & PDB_ENTER)			printf("enter: removing old mapping %x pa %x ", va, opa);#endif		if ((pind = pmap_page_index(opa)) != -1) {			pmap_attributes[pind] |= *pte & (PG_M | PG_U);			pmap_remove_pv(pmap, va, pind);		}#ifdef DEBUG		enter_stats.mchange++;#endif	} else {		/*		 * Increment counters		 */		pmap->pm_stats.resident_count++;		if (wired)			pmap->pm_stats.wired_count++;	}	/*	 * Enter on the PV list if part of our managed memory	 */	if ((pind = pmap_page_index(pa)) != -1) {#ifdef DEBUG		enter_stats.managed++;#endif		pmap_enter_pv(pmap, va, pind);		cacheable = TRUE;	} else if (pmap_initialized) {#ifdef DEBUG		enter_stats.unmanaged++;#endif		/*		 * Assumption: if it is not part of our managed memory		 * then it must be device memory which may be volatile.		 */		cacheable = FALSE;	}validate:	/*	 * Now validate mapping with desired protection/wiring.	 * Assume uniform modified and referenced status for all	 * I386 pages in a MACH page.	 */	npte = (pa & PG_FRAME) | protection_codes[prot] | PG_V;	if (wired)		npte |= PG_W;	if (va < VM_MAXUSER_ADDRESS)	/* i.e. below USRSTACK */		npte |= PG_u;	else if (va < VM_MAX_ADDRESS)		/*		 * Page tables need to be user RW, for some reason, and the		 * user area must be writable too.  Anything above		 * VM_MAXUSER_ADDRESS is protected from user access by		 * the user data and code segment descriptors, so this is OK.		 */		npte |= PG_u | PG_RW;#ifdef DEBUG	if (pmapdebug & PDB_ENTER)		printf("enter: new pte value %x ", npte);#endif	*pte = npte;	if (flush)		pmap_update();}/* *      pmap_page_protect: * *      Lower the permission for all mappings to a given page. */voidpmap_page_protect(phys, prot)	vm_offset_t     phys;	vm_prot_t       prot;{	switch (prot) {	case VM_PROT_READ:	case VM_PROT_READ|VM_PROT_EXECUTE:		pmap_copy_on_write(phys);		break;	case VM_PROT_ALL:		break;	default:		pmap_remove_all(phys);		break;	}}/* *	Routine:	pmap_change_wiring *	Function:	Change the wiring attribute for a map/virtual-address *			pair. *	In/out conditions: *			The mapping must already exist in the pmap. */voidpmap_change_wiring(pmap, va, wired)	register pmap_t pmap;	vm_offset_t va;	boolean_t wired;{	register pt_entry_t *pte;#ifdef DEBUG	if (pmapdebug & PDB_FOLLOW)		printf("pmap_change_wiring(%x, %x, %x)", pmap, va, wired);#endif	pte = pmap_pte(pmap, va);	if (!pte)		return;#ifdef DEBUG	/*	 * Page not valid.  Should this ever happen?	 * Just continue and change wiring anyway.	 */	if (!pmap_pte_v(pte)) {		if (pmapdebug & PDB_PARANOIA)			printf("pmap_change_wiring: invalid PTE for %x ", va);	}#endif	if ((wired && !pmap_pte_w(pte)) || (!wired && pmap_pte_w(pte))) {		if (wired)			pmap->pm_stats.wired_count++;		else			pmap->pm_stats.wired_count--;		pmap_pte_set_w(pte, wired);	}}/* *	Routine:	pmap_pte *	Function: *		Extract the page table entry associated *		with the given map/virtual_address pair. */pt_entry_t *pmap_pte(pmap, va)	register pmap_t pmap;	vm_offset_t va;{	pt_entry_t *ptp;#ifdef DEBUG	if (pmapdebug & PDB_FOLLOW)		printf("pmap_pte(%x, %x) ->\n", pmap, va);#endif	if (!pmap || !pmap_pde_v(pmap_pde(pmap, va)))		return NULL;	if ((pmap->pm_pdir[PTDPTDI] & PG_FRAME) == (PTDpde & PG_FRAME) ||	    pmap == pmap_kernel())		/* current address space or kernel */		ptp = PTmap;	else {		/* alternate address space */		if ((pmap->pm_pdir[PTDPTDI] & PG_FRAME) != (APTDpde & PG_FRAME)) {			APTDpde = pmap->pm_pdir[PTDPTDI];			pmap_update();		}		ptp = APTmap;	}	return ptp + i386_btop(va);}