pmap.c revision 59440
1121474Sume/*
262614Sitojun * Copyright (c) 1991 Regents of the University of California.
355163Sshin * All rights reserved.
455163Sshin * Copyright (c) 1994 John S. Dyson
555163Sshin * All rights reserved.
655163Sshin * Copyright (c) 1994 David Greenman
755163Sshin * All rights reserved.
855163Sshin *
955163Sshin * This code is derived from software contributed to Berkeley by
1055163Sshin * the Systems Programming Group of the University of Utah Computer
1155163Sshin * Science Department and William Jolitz of UUNET Technologies Inc.
1255163Sshin *
1355163Sshin * Redistribution and use in source and binary forms, with or without
1455163Sshin * modification, are permitted provided that the following conditions
1555163Sshin * are met:
1655163Sshin * 1. Redistributions of source code must retain the above copyright
1755163Sshin *    notice, this list of conditions and the following disclaimer.
1855163Sshin * 2. Redistributions in binary form must reproduce the above copyright
1955163Sshin *    notice, this list of conditions and the following disclaimer in the
2055163Sshin *    documentation and/or other materials provided with the distribution.
2155163Sshin * 3. All advertising materials mentioning features or use of this software
2255163Sshin *    must display the following acknowledgement:
2355163Sshin *	This product includes software developed by the University of
2455163Sshin *	California, Berkeley and its contributors.
2555163Sshin * 4. Neither the name of the University nor the names of its contributors
2655163Sshin *    may be used to endorse or promote products derived from this software
2755163Sshin *    without specific prior written permission.
2855163Sshin *
2955163Sshin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
3055163Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3155163Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3255163Sshin * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3355163Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3455163Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3555163Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3655163Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3755163Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3855163Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3955163Sshin * SUCH DAMAGE.
4061877Sume *
41105940Sume *	from:	@(#)pmap.c	7.7 (Berkeley)	5/12/91
42105940Sume * $FreeBSD: head/sys/i386/i386/pmap.c 59440 2000-04-20 14:40:11Z luoqi $
4356627Sshin */
4456627Sshin
4556627Sshin/*
4656627Sshin *	Manages physical address maps.
4756627Sshin *
4861877Sume *	In addition to hardware address maps, this
4961877Sume *	module is called upon to provide software-use-only
5061877Sume *	maps which may or may not be stored in the same
5161877Sume *	form as hardware maps.  These pseudo-maps are
52105940Sume *	used to store intermediate results from copy
53105940Sume *	operations to and from address spaces.
5461877Sume *
5561877Sume *	Since the information managed by this module is
5661877Sume *	also stored by the logical address mapping module,
5761877Sume *	this module may throw away valid virtual-to-physical
58105940Sume *	mappings at almost any time.  However, invalidations
59105940Sume *	of virtual-to-physical mappings must be done as
60105940Sume *	requested.
61105940Sume *
62105940Sume *	In order to cope with hardware architectures which
6355163Sshin *	make virtual-to-physical map invalidates expensive,
6455163Sshin *	this module may delay invalidate or reduced protection
6592986Sobrien *	operations until such time as they are actually
6692986Sobrien *	necessary.  This module is given full information as
6792986Sobrien *	to which processors are currently using which maps,
6871579Sdeischen *	and to when physical maps must be made correct.
6955163Sshin */
7055163Sshin
7155163Sshin#include "opt_disable_pse.h"
7255163Sshin#include "opt_pmap.h"
7355163Sshin#include "opt_msgbuf.h"
74121747Sume#include "opt_user_ldt.h"
75121747Sume
76121747Sume#include <sys/param.h>
77121747Sume#include <sys/systm.h>
78129901Sume#include <sys/proc.h>
79121747Sume#include <sys/msgbuf.h>
80121747Sume#include <sys/vmmeter.h>
8155163Sshin#include <sys/mman.h>
8255163Sshin
83121474Sume#include <vm/vm.h>
84121474Sume#include <vm/vm_param.h>
85121474Sume#include <sys/lock.h>
8655163Sshin#include <vm/vm_kern.h>
87114681Sdeischen#include <vm/vm_page.h>
8855163Sshin#include <vm/vm_map.h>
8955163Sshin#include <vm/vm_object.h>
9055163Sshin#include <vm/vm_extern.h>
9155163Sshin#include <vm/vm_pageout.h>
9255163Sshin#include <vm/vm_pager.h>
9355163Sshin#include <vm/vm_zone.h>
9455163Sshin
9561877Sume#include <sys/user.h>
96102237Spirzyk
97102237Spirzyk#include <machine/cputypes.h>
98102237Spirzyk#include <machine/md_var.h>
9978012Sume#include <machine/specialreg.h>
10078012Sume#if defined(SMP) || defined(APIC_IO)
10178012Sume#include <machine/smp.h>
10255163Sshin#include <machine/apic.h>
10365532Snectar#include <machine/segments.h>
10465532Snectar#include <machine/tss.h>
10571579Sdeischen#include <machine/globaldata.h>
106111618Snectar#endif /* SMP || APIC_IO */
10765532Snectar
10855163Sshin#define PMAP_KEEP_PDIRS
10955163Sshin#ifndef PMAP_SHPGPERPROC
11055163Sshin#define PMAP_SHPGPERPROC 200
11155163Sshin#endif
112105940Sume
113105940Sume#if defined(DIAGNOSTIC)
114105940Sume#define PMAP_DIAGNOSTIC
115105940Sume#endif
11655163Sshin
11755163Sshin#define MINPV 2048
118105940Sume
119105940Sume#if !defined(PMAP_DIAGNOSTIC)
12055163Sshin#define PMAP_INLINE __inline
12155163Sshin#else
12255163Sshin#define PMAP_INLINE
12355163Sshin#endif
12455163Sshin
12555163Sshin/*
126105940Sume * Get PDEs and PTEs for user/kernel address space
12755163Sshin */
128121747Sume#define	pmap_pde(m, v)	(&((m)->pm_pdir[(vm_offset_t)(v) >> PDRSHIFT]))
129121747Sume#define pdir_pde(m, v) (m[(vm_offset_t)(v) >> PDRSHIFT])
130121747Sume
131121747Sume#define pmap_pde_v(pte)		((*(int *)pte & PG_V) != 0)
132121747Sume#define pmap_pte_w(pte)		((*(int *)pte & PG_W) != 0)
133121747Sume#define pmap_pte_m(pte)		((*(int *)pte & PG_M) != 0)
134121747Sume#define pmap_pte_u(pte)		((*(int *)pte & PG_A) != 0)
135121747Sume#define pmap_pte_v(pte)		((*(int *)pte & PG_V) != 0)
13655163Sshin
13755163Sshin#define pmap_pte_set_w(pte, v) ((v)?(*(int *)pte |= PG_W):(*(int *)pte &= ~PG_W))
13855163Sshin#define pmap_pte_set_prot(pte, v) ((*(int *)pte &= ~PG_PROT), (*(int *)pte |= (v)))
13955163Sshin
14055163Sshin/*
14155163Sshin * Given a map and a machine independent protection code,
14273665Sobrien * convert to a vax protection code.
14355163Sshin */
14455163Sshin#define pte_prot(m, p)	(protection_codes[p])
14555163Sshinstatic int protection_codes[8];
14655163Sshin
14755163Sshin#define	pa_index(pa)		atop((pa) - vm_first_phys)
14855163Sshin#define	pa_to_pvh(pa)		(&pv_table[pa_index(pa)])
14955163Sshin
15055163Sshinstatic struct pmap kernel_pmap_store;
15155163Sshinpmap_t kernel_pmap;
15255163Sshin
15355163Sshinvm_offset_t avail_start;	/* PA of first available physical page */
15455163Sshinvm_offset_t avail_end;		/* PA of last available physical page */
15555163Sshinvm_offset_t virtual_avail;	/* VA of first avail page (after kernel bss) */
15655163Sshinvm_offset_t virtual_end;	/* VA of last avail page (end of kernel AS) */
15755163Sshinstatic boolean_t pmap_initialized = FALSE;	/* Has pmap_init completed? */
15855163Sshinstatic vm_offset_t vm_first_phys;
15955163Sshinstatic int pgeflag;		/* PG_G or-in */
16055163Sshinstatic int pseflag;		/* PG_PS or-in */
16155163Sshinstatic int pv_npg;
16255163Sshin
16361877Sumestatic vm_object_t kptobj;
16455163Sshin
16555163Sshinstatic int nkpt;
16655163Sshinvm_offset_t kernel_vm_end;
16755163Sshin
168105940Sume/*
169105940Sume * Data for the pv entry allocation mechanism
170105940Sume */
17155163Sshinstatic vm_zone_t pvzone;
17255163Sshinstatic struct vm_zone pvzone_store;
17355163Sshinstatic struct vm_object pvzone_obj;
17461877Sumestatic int pv_entry_count=0, pv_entry_max=0, pv_entry_high_water=0;
175121474Sumestatic int pmap_pagedaemon_waken = 0;
17661877Sumestatic struct pv_entry *pvinit;
17761877Sume
178121474Sume/*
179121474Sume * All those kernel PT submaps that BSD is so fond of
180121474Sume */
18161877Sumept_entry_t *CMAP1 = 0;
182121474Sumestatic pt_entry_t *CMAP2, *ptmmap;
183121474Sumestatic pv_table_t *pv_table;
184121474Sumecaddr_t CADDR1 = 0, ptvmmap = 0;
185121474Sumestatic caddr_t CADDR2;
186121474Sumestatic pt_entry_t *msgbufmap;
187121474Sumestruct msgbuf *msgbufp=0;
18861877Sume
18955163Sshin#ifdef SMP
19055163Sshinextern pt_entry_t *SMPpt;
19155163Sshin#else
192105940Sumestatic pt_entry_t *PMAP1 = 0;
19355163Sshinstatic unsigned *PADDR1 = 0;
194105940Sume#endif
19555163Sshin
19655163Sshinstatic PMAP_INLINE void	free_pv_entry __P((pv_entry_t pv));
197121747Sumestatic unsigned * get_ptbase __P((pmap_t pmap));
198121747Sumestatic pv_entry_t get_pv_entry __P((void));
199121747Sumestatic void	i386_protection_init __P((void));
200121747Sumestatic __inline void	pmap_changebit __P((vm_offset_t pa, int bit, boolean_t setem));
201121747Sumestatic void	pmap_clearbit __P((vm_offset_t pa, int bit));
202121747Sume
203121747Sumestatic PMAP_INLINE int	pmap_is_managed __P((vm_offset_t pa));
204121747Sumestatic void	pmap_remove_all __P((vm_offset_t pa));
205121747Sumestatic vm_page_t pmap_enter_quick __P((pmap_t pmap, vm_offset_t va,
206121747Sume				      vm_offset_t pa, vm_page_t mpte));
207121747Sumestatic int pmap_remove_pte __P((struct pmap *pmap, unsigned *ptq,
208121747Sume					vm_offset_t sva));
209121747Sumestatic void pmap_remove_page __P((struct pmap *pmap, vm_offset_t va));
210121747Sumestatic int pmap_remove_entry __P((struct pmap *pmap, pv_table_t *pv,
211121747Sume					vm_offset_t va));
212121747Sumestatic boolean_t pmap_testbit __P((vm_offset_t pa, int bit));
213121747Sumestatic void pmap_insert_entry __P((pmap_t pmap, vm_offset_t va,
21465532Snectar		vm_page_t mpte, vm_offset_t pa));
21565532Snectar
21665532Snectarstatic vm_page_t pmap_allocpte __P((pmap_t pmap, vm_offset_t va));
21765532Snectar
21865532Snectarstatic int pmap_release_free_page __P((pmap_t pmap, vm_page_t p));
21965532Snectarstatic vm_page_t _pmap_allocpte __P((pmap_t pmap, unsigned ptepindex));
22061877Sumestatic unsigned * pmap_pte_quick __P((pmap_t pmap, vm_offset_t va));
22161877Sumestatic vm_page_t pmap_page_lookup __P((vm_object_t object, vm_pindex_t pindex));
22261877Sumestatic int pmap_unuse_pt __P((pmap_t, vm_offset_t, vm_page_t));
22362614Sitojunstatic vm_offset_t pmap_kmem_choose(vm_offset_t addr);
22461877Sume
22561877Sumestatic unsigned pdir4mb;
22661877Sume
22761877Sume/*
22861877Sume *	Routine:	pmap_pte
229121426Sume *	Function:
230121426Sume *		Extract the page table entry associated
231121426Sume *		with the given map/virtual_address pair.
232121426Sume */
233121426Sume
234121426SumePMAP_INLINE unsigned *
235121426Sumepmap_pte(pmap, va)
23692905Sobrien	register pmap_t pmap;
23792941Sobrien	vm_offset_t va;
23892941Sobrien{
23992941Sobrien	unsigned *pdeaddr;
240140906Sume
24192941Sobrien	if (pmap) {
24292941Sobrien		pdeaddr = (unsigned *) pmap_pde(pmap, va);
24392941Sobrien		if (*pdeaddr & PG_PS)
24492941Sobrien			return pdeaddr;
24592941Sobrien		if (*pdeaddr) {
24692941Sobrien			return get_ptbase(pmap) + i386_btop(va);
24792905Sobrien		}
24892905Sobrien	}
24992905Sobrien	return (0);
250121474Sume}
251129901Sume
252121747Sume/*
25361877Sume * Move the kernel virtual free pointer to the next
254105943Sume * 4MB.  This is used to help improve performance
25561877Sume * by using a large (4MB) page for much of the kernel
256121747Sume * (.text, .data, .bss)
25755163Sshin */
258121426Sumestatic vm_offset_t
259121426Sumepmap_kmem_choose(vm_offset_t addr) {
260121426Sume	vm_offset_t newaddr = addr;
261121747Sume#ifndef DISABLE_PSE
262121747Sume	if (cpu_feature & CPUID_PSE) {
263121747Sume		newaddr = (addr + (NBPDR - 1)) & ~(NBPDR - 1);
264121747Sume	}
265121747Sume#endif
266129901Sume	return newaddr;
267121747Sume}
26892941Sobrien
26992941Sobrien/*
270121426Sume *	Bootstrap the system enough to run with virtual memory.
271121426Sume *
272121426Sume *	On the i386 this is called after mapping has already been enabled
273105943Sume *	and just syncs the pmap module with what has already been done.
27492905Sobrien *	[We can't call it easily with mapping off since the kernel is not
27592905Sobrien *	mapped with PA == VA, hence we would have to relocate every address
27692905Sobrien *	from the linked base (virtual) address "KERNBASE" to the actual
27792905Sobrien *	(physical) address starting relative to 0]
27861877Sume */
27992905Sobrienvoid
28092905Sobrienpmap_bootstrap(firstaddr, loadaddr)
28161877Sume	vm_offset_t firstaddr;
28261877Sume	vm_offset_t loadaddr;
28392905Sobrien{
28492905Sobrien	vm_offset_t va;
28592941Sobrien	pt_entry_t *pte;
28692941Sobrien#ifdef SMP
28761877Sume	int i, j;
288121347Sume	struct globaldata *gd;
289121347Sume#endif
290121347Sume
291121347Sume	avail_start = firstaddr;
292121347Sume
293121347Sume	/*
294121347Sume	 * XXX The calculation of virtual_avail is wrong. It's NKPT*PAGE_SIZE too
295121347Sume	 * large. It should instead be correctly calculated in locore.s and
296121347Sume	 * not based on 'first' (which is a physical address, not a virtual
297121347Sume	 * address, for the start of unused physical memory). The kernel
298121347Sume	 * page tables are NOT double mapped and thus should not be included
299121347Sume	 * in this calculation.
300121347Sume	 */
301121347Sume	virtual_avail = (vm_offset_t) KERNBASE + firstaddr;
302121347Sume	virtual_avail = pmap_kmem_choose(virtual_avail);
303121347Sume
304121347Sume	virtual_end = VM_MAX_KERNEL_ADDRESS;
305121347Sume
306121347Sume	/*
307121347Sume	 * Initialize protection array.
30855163Sshin	 */
30955163Sshin	i386_protection_init();
310104558Sume
311126243Sgreen	/*
312104558Sume	 * The kernel's pmap is statically allocated so we don't have to use
313104558Sume	 * pmap_create, which is unlikely to work correctly at this part of
314126243Sgreen	 * the boot sequence (XXX and which no longer exists).
315104558Sume	 */
316114681Sdeischen	kernel_pmap = &kernel_pmap_store;
317104558Sume
318114681Sdeischen	kernel_pmap->pm_pdir = (pd_entry_t *) (KERNBASE + (u_int)IdlePTD);
319104558Sume	kernel_pmap->pm_count = 1;
320114681Sdeischen	kernel_pmap->pm_active = -1;	/* don't allow deactivation */
321104558Sume	TAILQ_INIT(&kernel_pmap->pm_pvlist);
32255163Sshin	nkpt = NKPT;
32355163Sshin
324105940Sume	/*
32555163Sshin	 * Reserve some special page table entries/VA space for temporary
32655163Sshin	 * mapping of pages.
32755163Sshin	 */
32855163Sshin#define	SYSMAP(c, p, v, n)	\
32955163Sshin	v = (c)va; va += ((n)*PAGE_SIZE); p = pte; pte += (n);
33055163Sshin
33155163Sshin	va = virtual_avail;
33261877Sume	pte = (pt_entry_t *) pmap_pte(kernel_pmap, va);
33355163Sshin
334105940Sume	/*
33555163Sshin	 * CMAP1/CMAP2 are used for zeroing and copying pages.
33655163Sshin	 */
33755163Sshin	SYSMAP(caddr_t, CMAP1, CADDR1, 1)
33855163Sshin	SYSMAP(caddr_t, CMAP2, CADDR2, 1)
33955163Sshin
34061877Sume	/*
34155163Sshin	 * ptvmmap is used for reading arbitrary physical pages via /dev/mem.
342105940Sume	 * XXX ptmmap is not used.
34355163Sshin	 */
34455163Sshin	SYSMAP(caddr_t, ptmmap, ptvmmap, 1)
34555163Sshin
34655163Sshin	/*
34755163Sshin	 * msgbufp is used to map the system message buffer.
34861877Sume	 * XXX msgbufmap is not used.
34955163Sshin	 */
350105940Sume	SYSMAP(struct msgbuf *, msgbufmap, msgbufp,
35155163Sshin	       atop(round_page(MSGBUF_SIZE)))
35255163Sshin
35355163Sshin#if !defined(SMP)
35455163Sshin	/*
35561877Sume	 * ptemap is used for pmap_pte_quick
35661877Sume	 */
35755163Sshin	SYSMAP(unsigned *, PMAP1, PADDR1, 1);
358105940Sume#endif
35961877Sume
360105940Sume	virtual_avail = va;
36161877Sume
36255163Sshin	*(int *) CMAP1 = *(int *) CMAP2 = 0;
36355163Sshin	*(int *) PTD = 0;
36455163Sshin
36555163Sshin
36655163Sshin	pgeflag = 0;
367121347Sume#if !defined(SMP)
368121347Sume	if (cpu_feature & CPUID_PGE) {
369121347Sume		pgeflag = PG_G;
370121347Sume	}
371121347Sume#endif
372121347Sume
373121348Sume/*
37455163Sshin * Initialize the 4MB page size flag
37555163Sshin */
37655163Sshin	pseflag = 0;
37755163Sshin/*
37855163Sshin * The 4MB page version of the initial
37955163Sshin * kernel page mapping.
38055163Sshin */
38155163Sshin	pdir4mb = 0;
38255163Sshin
38355163Sshin#if !defined(DISABLE_PSE)
38455163Sshin	if (cpu_feature & CPUID_PSE) {
38555163Sshin		unsigned ptditmp;
38655163Sshin		/*
38755163Sshin		 * Note that we have enabled PSE mode
38861877Sume		 */
38961877Sume		pseflag = PG_PS;
39055163Sshin		ptditmp = *((unsigned *)PTmap + i386_btop(KERNBASE));
39155163Sshin		ptditmp &= ~(NBPDR - 1);
39255163Sshin		ptditmp |= PG_V | PG_RW | PG_PS | PG_U | pgeflag;
39355163Sshin		pdir4mb = ptditmp;
39455163Sshin
39555163Sshin#if !defined(SMP)
39662836Sitojun		/*
39762836Sitojun		 * Enable the PSE mode.
39862836Sitojun		 */
39962836Sitojun		load_cr4(rcr4() | CR4_PSE);
40062836Sitojun
401105943Sume		/*
40262836Sitojun		 * We can do the mapping here for the single processor
403105943Sume		 * case.  We simply ignore the old page table page from
40462836Sitojun		 * now on.
40562836Sitojun		 */
40662836Sitojun		/*
40755163Sshin		 * For SMP, we still need 4K pages to bootstrap APs,
40855163Sshin		 * PSE will be enabled as soon as all APs are up.
40955163Sshin		 */
41055163Sshin		PTD[KPTDI] = (pd_entry_t) ptditmp;
41155163Sshin		kernel_pmap->pm_pdir[KPTDI] = (pd_entry_t) ptditmp;
41255163Sshin		invltlb();
41355163Sshin#endif
41455163Sshin	}
41555163Sshin#endif
41655163Sshin
41755163Sshin#ifdef SMP
418121474Sume	if (cpu_apic_address == 0)
419121474Sume		panic("pmap_bootstrap: no local apic!");
42055163Sshin
42155163Sshin	/* local apic is mapped on last page */
422121747Sume	SMPpt[NPTEPG - 1] = (pt_entry_t)(PG_V | PG_RW | PG_N | pgeflag |
42355163Sshin	    (cpu_apic_address & PG_FRAME));
42461877Sume
42555163Sshin	for (i = 0; i < mp_napics; i++) {
42655163Sshin		for (j = 0; j < mp_napics; j++) {
42755163Sshin			/* same page frame as a previous IO apic? */
42855163Sshin			if (((vm_offset_t)SMPpt[NPTEPG-2-j] & PG_FRAME) ==
42955163Sshin			    (io_apic_address[i] & PG_FRAME)) {
43055163Sshin				ioapic[i] = (ioapic_t *)((u_int)SMP_prvspace
43155163Sshin					+ (NPTEPG-2-j) * PAGE_SIZE
43255163Sshin					+ (io_apic_address[i] & PAGE_MASK));
43355163Sshin				break;
43455163Sshin			}
43555163Sshin			/* use this slot if available */
43655163Sshin			if (((vm_offset_t)SMPpt[NPTEPG-2-j] & PG_FRAME) == 0) {
43755163Sshin				SMPpt[NPTEPG-2-j] = (pt_entry_t)(PG_V | PG_RW |
43855163Sshin				    pgeflag | (io_apic_address[i] & PG_FRAME));
43955163Sshin				ioapic[i] = (ioapic_t *)((u_int)SMP_prvspace
44055163Sshin					+ (NPTEPG-2-j) * PAGE_SIZE
44155163Sshin					+ (io_apic_address[i] & PAGE_MASK));
44255163Sshin				break;
44355163Sshin			}
44455163Sshin		}
44555163Sshin	}
44655163Sshin
44755163Sshin	/* BSP does this itself, AP's get it pre-set */
44855163Sshin	gd = &SMP_prvspace[0].globaldata;
44955163Sshin	gd->gd_prv_CMAP1 = &SMPpt[1];
45055163Sshin	gd->gd_prv_CMAP2 = &SMPpt[2];
45155163Sshin	gd->gd_prv_CMAP3 = &SMPpt[3];
45255163Sshin	gd->gd_prv_PMAP1 = &SMPpt[4];
45355163Sshin	gd->gd_prv_CADDR1 = SMP_prvspace[0].CPAGE1;
45455163Sshin	gd->gd_prv_CADDR2 = SMP_prvspace[0].CPAGE2;
45555163Sshin	gd->gd_prv_CADDR3 = SMP_prvspace[0].CPAGE3;
45655163Sshin	gd->gd_prv_PADDR1 = (unsigned *)SMP_prvspace[0].PPAGE1;
45755163Sshin#endif
45855163Sshin
45955163Sshin	invltlb();
46055163Sshin}
46155163Sshin
46261877Sume#ifdef SMP
463121474Sume/*
46461877Sume * Set 4mb pdir for mp startup
465121474Sume */
46655163Sshinvoid
467121474Sumepmap_set_opt(void)
46855163Sshin{
469121474Sume	if (pseflag && (cpu_feature & CPUID_PSE)) {
470121474Sume		load_cr4(rcr4() | CR4_PSE);
471121474Sume		if (pdir4mb && cpuid == 0) {	/* only on BSP */
472121474Sume			kernel_pmap->pm_pdir[KPTDI] =
47355163Sshin			    PTD[KPTDI] = (pd_entry_t)pdir4mb;
47455163Sshin			cpu_invltlb();
47555163Sshin		}
47655163Sshin	}
47761877Sume}
47861877Sume#endif
479105940Sume
48061877Sume/*
48161877Sume *	Initialize the pmap module.
48261877Sume *	Called by vm_init, to initialize any structures that the pmap
48361877Sume *	system needs to map virtual memory.
48461877Sume *	pmap_init has been enhanced to support in a fairly consistant
48561877Sume *	way, discontiguous physical memory.
48661877Sume */
48761877Sumevoid
48861877Sumepmap_init(phys_start, phys_end)
48961877Sume	vm_offset_t phys_start, phys_end;
49061877Sume{
49161877Sume	vm_offset_t addr;
49261877Sume	vm_size_t s;
49361877Sume	int i;
49461877Sume	int initial_pvs;
49561877Sume
49661877Sume	/*
49755163Sshin	 * object for kernel page table pages
49855163Sshin	 */
49961877Sume	kptobj = vm_object_allocate(OBJT_DEFAULT, NKPDE);
50061877Sume
50161877Sume	/*
50255163Sshin	 * calculate the number of pv_entries needed
50355163Sshin	 */
50461877Sume	vm_first_phys = phys_avail[0];
505121474Sume	for (i = 0; phys_avail[i + 1]; i += 2);
50655163Sshin	pv_npg = (phys_avail[(i - 2) + 1] - vm_first_phys) / PAGE_SIZE;
50755163Sshin
50861877Sume	/*
50955163Sshin	 * Allocate memory for random pmap data structures.  Includes the
51061877Sume	 * pv_head_table.
51161877Sume	 */
51255163Sshin	s = (vm_size_t) (sizeof(pv_table_t) * pv_npg);
51355163Sshin	s = round_page(s);
51455163Sshin
51555163Sshin	addr = (vm_offset_t) kmem_alloc(kernel_map, s);
51661877Sume	pv_table = (pv_table_t *) addr;
51755163Sshin	for(i = 0; i < pv_npg; i++) {
51855163Sshin		vm_offset_t pa;
51955163Sshin		TAILQ_INIT(&pv_table[i].pv_list);
52061877Sume		pv_table[i].pv_list_count = 0;
52161877Sume		pa = vm_first_phys + i * PAGE_SIZE;
52255163Sshin		pv_table[i].pv_vm_page = PHYS_TO_VM_PAGE(pa);
52355163Sshin	}
52461877Sume
52561877Sume	/*
526121474Sume	 * init the pv free list
527121474Sume	 */
52855163Sshin	initial_pvs = pv_npg;
52955163Sshin	if (initial_pvs < MINPV)
530121474Sume		initial_pvs = MINPV;
531121474Sume	pvzone = &pvzone_store;
53255163Sshin	pvinit = (struct pv_entry *) kmem_alloc(kernel_map,
53361877Sume		initial_pvs * sizeof (struct pv_entry));
534121474Sume	zbootinit(pvzone, "PV ENTRY", sizeof (struct pv_entry), pvinit, pv_npg);
535121474Sume
536121474Sume	/*
537121474Sume	 * Now it is safe to enable pv_table recording.
538121474Sume	 */
539121474Sume	pmap_initialized = TRUE;
540121474Sume}
54155163Sshin
542121474Sume/*
543121474Sume * Initialize the address space (zone) for the pv_entries.  Set a
544121474Sume * high water mark so that the system can recover from excessive
545121474Sume * numbers of pv entries.
546121474Sume */
54755163Sshinvoid
548121474Sumepmap_init2() {
549121474Sume	pv_entry_max = PMAP_SHPGPERPROC * maxproc + pv_npg;
550121474Sume	pv_entry_high_water = 9 * (pv_entry_max / 10);
551140906Sume	zinitna(pvzone, &pvzone_obj, NULL, 0, pv_entry_max, ZONE_INTERRUPT, 1);
552140906Sume}
55355163Sshin
554121474Sume/*
555121474Sume *	Used to map a range of physical addresses into kernel
556121474Sume *	virtual address space.
557121474Sume *
558121474Sume *	For now, VM is already on, we only need to map the
55955163Sshin *	specified memory.
56055163Sshin */
561121474Sumevm_offset_t
562121474Sumepmap_map(virt, start, end, prot)
563121474Sume	vm_offset_t virt;
564121474Sume	vm_offset_t start;
565121474Sume	vm_offset_t end;
566121747Sume	int prot;
567121747Sume{
568121474Sume	while (start < end) {
569121747Sume		pmap_enter(kernel_pmap, virt, start, prot, FALSE);
570121474Sume		virt += PAGE_SIZE;
571121425Sume		start += PAGE_SIZE;
572121425Sume	}
57355163Sshin	return (virt);
57490053Sroam}
57555163Sshin
576121474Sume
577121474Sume/***************************************************
578121474Sume * Low level helper routines.....
57961877Sume ***************************************************/
58061877Sume
581121474Sume#if defined(PMAP_DIAGNOSTIC)
582121474Sume
58361877Sume/*
58461877Sume * This code checks for non-writeable/modified pages.
58561877Sume * This should be an invalid condition.
58655163Sshin */
587121474Sumestatic int
588121474Sumepmap_nw_modified(pt_entry_t ptea) {
58961877Sume	int pte;
59055163Sshin
591121474Sume	pte = (int) ptea;
592121474Sume
59361877Sume	if ((pte & (PG_M|PG_RW)) == PG_M)
594121474Sume		return 1;
595121474Sume	else
596121474Sume		return 0;
59761877Sume}
598121474Sume#endif
59955163Sshin
60061877Sume
60161877Sume/*
60261877Sume * this routine defines the region(s) of memory that should
60361877Sume * not be tested for the modified bit.
60461877Sume */
605121474Sumestatic PMAP_INLINE int
606121474Sumepmap_track_modified( vm_offset_t va) {
60761877Sume	if ((va < clean_sva) || (va >= clean_eva))
60861877Sume		return 1;
60961877Sume	else
61055163Sshin		return 0;
61155163Sshin}
612121747Sume
61361877Sumestatic PMAP_INLINE void
61461877Sumeinvltlb_1pg( vm_offset_t va) {
61561877Sume#if defined(I386_CPU)
616121747Sume	if (cpu_class == CPUCLASS_386) {
617121747Sume		invltlb();
618121747Sume	} else
619121747Sume#endif
620121747Sume	{
621121747Sume		invlpg(va);
62261877Sume	}
62361877Sume}
624121747Sume
625121747Sumestatic __inline void
626121747Sumepmap_TLB_invalidate(pmap_t pmap, vm_offset_t va)
627121747Sume{
628121747Sume#if defined(SMP)
629121747Sume	if (pmap->pm_active & (1 << cpuid))
630121747Sume		cpu_invlpg((void *)va);
631121747Sume	if (pmap->pm_active & other_cpus)
632121747Sume		smp_invltlb();
633121747Sume#else
63461877Sume	if (pmap->pm_active)
635121474Sume		invltlb_1pg(va);
63661877Sume#endif
63761877Sume}
63855163Sshin
639121747Sumestatic __inline void
640121747Sumepmap_TLB_invalidate_all(pmap_t pmap)
641121474Sume{
642121474Sume#if defined(SMP)
643121474Sume	if (pmap->pm_active & (1 << cpuid))
64455163Sshin		cpu_invltlb();
64555163Sshin	if (pmap->pm_active & other_cpus)
64655163Sshin		smp_invltlb();
647121747Sume#else
648121747Sume	if (pmap->pm_active)
649121747Sume		invltlb();
650121747Sume#endif
651121747Sume}
652121747Sume
653121747Sumestatic unsigned *
654121747Sumeget_ptbase(pmap)
655121747Sume	pmap_t pmap;
656121747Sume{
657121747Sume	unsigned frame = (unsigned) pmap->pm_pdir[PTDPTDI] & PG_FRAME;
658121747Sume
659121747Sume	/* are we current address space or kernel? */
660121747Sume	if (pmap == kernel_pmap || frame == (((unsigned) PTDpde) & PG_FRAME)) {
661121747Sume		return (unsigned *) PTmap;
662121747Sume	}
663121747Sume	/* otherwise, we are alternate address space */
664121747Sume	if (frame != (((unsigned) APTDpde) & PG_FRAME)) {
665121747Sume		APTDpde = (pd_entry_t) (frame | PG_RW | PG_V);
666121747Sume#if defined(SMP)
667121747Sume		/* The page directory is not shared between CPUs */
668121747Sume		cpu_invltlb();
669121747Sume#else
670121747Sume		invltlb();
671121747Sume#endif
672121747Sume	}
673121747Sume	return (unsigned *) APTmap;
674121747Sume}
675121747Sume
676121747Sume/*
677121747Sume * Super fast pmap_pte routine best used when scanning
678121747Sume * the pv lists.  This eliminates many coarse-grained
679121747Sume * invltlb calls.  Note that many of the pv list
680121747Sume * scans are across different pmaps.  It is very wasteful
681121747Sume * to do an entire invltlb for checking a single mapping.
682121747Sume */
683121747Sume
684129901Sumestatic unsigned *
685121747Sumepmap_pte_quick(pmap, va)
686121747Sume	register pmap_t pmap;
687121747Sume	vm_offset_t va;
688121747Sume{
689121747Sume	unsigned pde, newpf;
690121747Sume	if ((pde = (unsigned) pmap->pm_pdir[va >> PDRSHIFT]) != 0) {
691121747Sume		unsigned frame = (unsigned) pmap->pm_pdir[PTDPTDI] & PG_FRAME;
692121747Sume		unsigned index = i386_btop(va);
693121747Sume		/* are we current address space or kernel? */
694121747Sume		if ((pmap == kernel_pmap) ||
695121747Sume			(frame == (((unsigned) PTDpde) & PG_FRAME))) {
696121747Sume			return (unsigned *) PTmap + index;
697121747Sume		}
698121747Sume		newpf = pde & PG_FRAME;
699121747Sume#ifdef SMP
700121747Sume		if ( ((* (unsigned *) prv_PMAP1) & PG_FRAME) != newpf) {
701121747Sume			* (unsigned *) prv_PMAP1 = newpf | PG_RW | PG_V;
702121747Sume			cpu_invlpg(prv_PADDR1);
703121747Sume		}
704121747Sume		return prv_PADDR1 + ((unsigned) index & (NPTEPG - 1));
705121747Sume#else
706121747Sume		if ( ((* (unsigned *) PMAP1) & PG_FRAME) != newpf) {
707121747Sume			* (unsigned *) PMAP1 = newpf | PG_RW | PG_V;
708121747Sume			invltlb_1pg((vm_offset_t) PADDR1);
709121747Sume		}
710121747Sume		return PADDR1 + ((unsigned) index & (NPTEPG - 1));
711121747Sume#endif
712121747Sume	}
713121747Sume	return (0);
714121747Sume}
715121747Sume
716121747Sume/*
717121747Sume *	Routine:	pmap_extract
718121747Sume *	Function:
719121747Sume *		Extract the physical page address associated
720121747Sume *		with the given map/virtual_address pair.
721121747Sume */
722121747Sumevm_offset_t
723121747Sumepmap_extract(pmap, va)
724121747Sume	register pmap_t pmap;
725121747Sume	vm_offset_t va;
726121747Sume{
727121747Sume	vm_offset_t rtval;
728121747Sume	vm_offset_t pdirindex;
729121747Sume	pdirindex = va >> PDRSHIFT;
730121747Sume	if (pmap && (rtval = (unsigned) pmap->pm_pdir[pdirindex])) {
731121747Sume		unsigned *pte;
732121747Sume		if ((rtval & PG_PS) != 0) {
733121747Sume			rtval &= ~(NBPDR - 1);
734121747Sume			rtval |= va & (NBPDR - 1);
735121747Sume			return rtval;
736121747Sume		}
737121747Sume		pte = get_ptbase(pmap) + i386_btop(va);
738121747Sume		rtval = ((*pte & PG_FRAME) | (va & PAGE_MASK));
739121747Sume		return rtval;
740121747Sume	}
741121747Sume	return 0;
742121747Sume
743121747Sume}
744121747Sume
745121747Sume/*
746121747Sume * determine if a page is managed (memory vs. device)
747121747Sume */
748121747Sumestatic PMAP_INLINE int
749121747Sumepmap_is_managed(pa)
750121747Sume	vm_offset_t pa;
751121747Sume{
752121747Sume	int i;
753121747Sume
754121747Sume	if (!pmap_initialized)
755121747Sume		return 0;
756121747Sume
757121747Sume	for (i = 0; phys_avail[i + 1]; i += 2) {
758121747Sume		if (pa < phys_avail[i + 1] && pa >= phys_avail[i])
759121747Sume			return 1;
760121747Sume	}
761121747Sume	return 0;
762121747Sume}
763121747Sume
764121747Sume
765121747Sume/***************************************************
766121747Sume * Low level mapping routines.....
767121747Sume ***************************************************/
768121747Sume
769121747Sume/*
770121747Sume * add a wired page to the kva
771121747Sume * note that in order for the mapping to take effect -- you
772121747Sume * should do a invltlb after doing the pmap_kenter...
773121747Sume */
774121747SumePMAP_INLINE void
775121747Sumepmap_kenter(va, pa)
776121747Sume	vm_offset_t va;
777121747Sume	register vm_offset_t pa;
778121747Sume{
779121747Sume	register unsigned *pte;
780121747Sume	unsigned npte, opte;
781121747Sume
782121747Sume	npte = pa | PG_RW | PG_V | pgeflag;
783121747Sume	pte = (unsigned *)vtopte(va);
784121747Sume	opte = *pte;
785121747Sume	*pte = npte;
786121747Sume	/*if (opte)*/
787121747Sume		invltlb_1pg(va);	/* XXX what about SMP? */
788121747Sume}
789121747Sume
790121747Sume/*
791121747Sume * remove a page from the kernel pagetables
792121747Sume */
793121747SumePMAP_INLINE void
794121747Sumepmap_kremove(va)
795121747Sume	vm_offset_t va;
796121747Sume{
797121747Sume	register unsigned *pte;
798121747Sume
799121747Sume	pte = (unsigned *)vtopte(va);
800121747Sume	*pte = 0;
801121747Sume	invltlb_1pg(va);	/* XXX what about SMP? */
802121747Sume}
803121747Sume
804121747Sume/*
805121747Sume * Add a list of wired pages to the kva
806121747Sume * this routine is only used for temporary
807121747Sume * kernel mappings that do not need to have
808121747Sume * page modification or references recorded.
809121747Sume * Note that old mappings are simply written
810121747Sume * over.  The page *must* be wired.
811121747Sume */
812121747Sumevoid
813121747Sumepmap_qenter(va, m, count)
814121747Sume	vm_offset_t va;
815121747Sume	vm_page_t *m;
816121747Sume	int count;
817121747Sume{
818121747Sume	int i;
819121747Sume
820121747Sume	for (i = 0; i < count; i++) {
821121747Sume		vm_offset_t tva = va + i * PAGE_SIZE;
822121747Sume		pmap_kenter(tva, VM_PAGE_TO_PHYS(m[i]));
823129901Sume	}
824129901Sume}
825129901Sume
826129901Sume/*
827129901Sume * this routine jerks page mappings from the
828129901Sume * kernel -- it is meant only for temporary mappings.
829129901Sume */
830129901Sumevoid
831129901Sumepmap_qremove(va, count)
832129901Sume	vm_offset_t va;
833129901Sume	int count;
834129901Sume{
835129901Sume	vm_offset_t end_va;
836129901Sume
837129901Sume	end_va = va + count*PAGE_SIZE;
838129901Sume
839129901Sume	while (va < end_va) {
840129901Sume		unsigned *pte;
841129901Sume
842129901Sume		pte = (unsigned *)vtopte(va);
843129901Sume		*pte = 0;
844129901Sume#ifdef SMP
845129901Sume		cpu_invlpg((void *)va);
846129901Sume#else
847129901Sume		invltlb_1pg(va);
848129901Sume#endif
849129901Sume		va += PAGE_SIZE;
850129901Sume	}
851129901Sume#ifdef SMP
852129901Sume	smp_invltlb();
853129901Sume#endif
854129901Sume}
855129901Sume
856129901Sumestatic vm_page_t
857129901Sumepmap_page_lookup(object, pindex)
858129901Sume	vm_object_t object;
859129901Sume	vm_pindex_t pindex;
860129901Sume{
861129901Sume	vm_page_t m;
862129901Sumeretry:
863129901Sume	m = vm_page_lookup(object, pindex);
864129901Sume	if (m && vm_page_sleep_busy(m, FALSE, "pplookp"))
865129901Sume		goto retry;
866129901Sume	return m;
867129901Sume}
868129901Sume
869129901Sume/*
870129901Sume * Create the UPAGES for a new process.
871129901Sume * This routine directly affects the fork perf for a process.
872129901Sume */
873129901Sumevoid
874129901Sumepmap_new_proc(p)
875129901Sume	struct proc *p;
876129901Sume{
877129901Sume	int i, updateneeded;
878129901Sume	vm_object_t upobj;
879129901Sume	vm_page_t m;
880129901Sume	struct user *up;
881129901Sume	unsigned *ptek, oldpte;
882129901Sume
883129901Sume	/*
884129901Sume	 * allocate object for the upages
885129901Sume	 */
886129901Sume	if ((upobj = p->p_upages_obj) == NULL) {
887129901Sume		upobj = vm_object_allocate( OBJT_DEFAULT, UPAGES);
888129901Sume		p->p_upages_obj = upobj;
889129901Sume	}
890121747Sume
891129901Sume	/* get a kernel virtual address for the UPAGES for this proc */
892129901Sume	if ((up = p->p_addr) == NULL) {
893129901Sume		up = (struct user *) kmem_alloc_nofault(kernel_map,
894129901Sume				UPAGES * PAGE_SIZE);
895129901Sume		if (up == NULL)
896129901Sume			panic("pmap_new_proc: u_map allocation failed");
897129901Sume		p->p_addr = up;
898129901Sume	}
899129901Sume
900129901Sume	ptek = (unsigned *) vtopte((vm_offset_t) up);
901129901Sume
902129901Sume	updateneeded = 0;
903129901Sume	for(i=0;i<UPAGES;i++) {
904129901Sume		/*
905129901Sume		 * Get a kernel stack page
906129901Sume		 */
907129901Sume		m = vm_page_grab(upobj, i, VM_ALLOC_NORMAL | VM_ALLOC_RETRY);
908129901Sume
909129901Sume		/*
910129901Sume		 * Wire the page
911129901Sume		 */
912129901Sume		m->wire_count++;
913129901Sume		cnt.v_wire_count++;
914129901Sume
915129901Sume		oldpte = *(ptek + i);
916129901Sume		/*
917129901Sume		 * Enter the page into the kernel address space.
918129901Sume		 */
919129901Sume		*(ptek + i) = VM_PAGE_TO_PHYS(m) | PG_RW | PG_V | pgeflag;
920129901Sume		if (oldpte) {
921129901Sume			if ((oldpte & PG_G) || (cpu_class > CPUCLASS_386)) {
922129901Sume				invlpg((vm_offset_t) up + i * PAGE_SIZE);
923129901Sume			} else {
924129901Sume				updateneeded = 1;
925129901Sume			}
926129901Sume		}
927129901Sume
928129901Sume		vm_page_wakeup(m);
929129901Sume		vm_page_flag_clear(m, PG_ZERO);
930129901Sume		vm_page_flag_set(m, PG_MAPPED | PG_WRITEABLE);
931121747Sume		m->valid = VM_PAGE_BITS_ALL;
932121747Sume	}
933121747Sume	if (updateneeded)
934121747Sume		invltlb();
935121747Sume}
936121747Sume
937121747Sume/*
938121747Sume * Dispose the UPAGES for a process that has exited.
939121747Sume * This routine directly impacts the exit perf of a process.
940121747Sume */
941121747Sumevoid
942121747Sumepmap_dispose_proc(p)
943121747Sume	struct proc *p;
944121747Sume{
945121747Sume	int i;
946121747Sume	vm_object_t upobj;
947121747Sume	vm_page_t m;
948121747Sume	unsigned *ptek, oldpte;
949121747Sume
950121747Sume	upobj = p->p_upages_obj;
951121747Sume
952121747Sume	ptek = (unsigned *) vtopte((vm_offset_t) p->p_addr);
953121747Sume	for(i=0;i<UPAGES;i++) {
954121747Sume
955121747Sume		if ((m = vm_page_lookup(upobj, i)) == NULL)
956121747Sume			panic("pmap_dispose_proc: upage already missing???");
957121747Sume
958121747Sume		vm_page_busy(m);
959121747Sume
960121747Sume		oldpte = *(ptek + i);
961121747Sume		*(ptek + i) = 0;
962121747Sume		if ((oldpte & PG_G) || (cpu_class > CPUCLASS_386))
963121747Sume			invlpg((vm_offset_t) p->p_addr + i * PAGE_SIZE);
964121747Sume		vm_page_unwire(m, 0);
965121747Sume		vm_page_free(m);
966121747Sume	}
967121747Sume#if defined(I386_CPU)
968121747Sume	if (cpu_class <= CPUCLASS_386)
969121747Sume		invltlb();
970121747Sume#endif
971121747Sume}
972121747Sume
973121747Sume/*
974121747Sume * Allow the UPAGES for a process to be prejudicially paged out.
975121747Sume */
976121747Sumevoid
977121747Sumepmap_swapout_proc(p)
978121747Sume	struct proc *p;
979121747Sume{
980121747Sume	int i;
981121747Sume	vm_object_t upobj;
982121747Sume	vm_page_t m;
983121747Sume
984121747Sume	upobj = p->p_upages_obj;
985121747Sume	/*
986121747Sume	 * let the upages be paged
987121747Sume	 */
988121747Sume	for(i=0;i<UPAGES;i++) {
989121747Sume		if ((m = vm_page_lookup(upobj, i)) == NULL)
990121747Sume			panic("pmap_swapout_proc: upage already missing???");
991121747Sume		vm_page_dirty(m);
992121747Sume		vm_page_unwire(m, 0);
993121747Sume		pmap_kremove( (vm_offset_t) p->p_addr + PAGE_SIZE * i);
994121747Sume	}
995121747Sume}
996121747Sume
997121747Sume/*
998121747Sume * Bring the UPAGES for a specified process back in.
999121747Sume */
1000121747Sumevoid
1001121747Sumepmap_swapin_proc(p)
1002121747Sume	struct proc *p;
1003121747Sume{
1004121747Sume	int i,rv;
1005121747Sume	vm_object_t upobj;
1006121747Sume	vm_page_t m;
1007121747Sume
1008121747Sume	upobj = p->p_upages_obj;
1009121747Sume	for(i=0;i<UPAGES;i++) {
1010121747Sume
1011121747Sume		m = vm_page_grab(upobj, i, VM_ALLOC_NORMAL | VM_ALLOC_RETRY);
1012121747Sume
1013121747Sume		pmap_kenter(((vm_offset_t) p->p_addr) + i * PAGE_SIZE,
1014121747Sume			VM_PAGE_TO_PHYS(m));
1015121747Sume
1016121747Sume		if (m->valid != VM_PAGE_BITS_ALL) {
1017121747Sume			rv = vm_pager_get_pages(upobj, &m, 1, 0);
1018121747Sume			if (rv != VM_PAGER_OK)
1019121747Sume				panic("pmap_swapin_proc: cannot get upages for proc: %d\n", p->p_pid);
1020121747Sume			m = vm_page_lookup(upobj, i);
1021121747Sume			m->valid = VM_PAGE_BITS_ALL;
1022121747Sume		}
1023121747Sume
1024121747Sume		vm_page_wire(m);
1025121747Sume		vm_page_wakeup(m);
1026121747Sume		vm_page_flag_set(m, PG_MAPPED | PG_WRITEABLE);
1027121747Sume	}
1028121747Sume}
1029121747Sume
1030121747Sume/***************************************************
1031121747Sume * Page table page management routines.....
1032121747Sume ***************************************************/
1033121747Sume
1034121747Sume/*
1035121747Sume * This routine unholds page table pages, and if the hold count
1036121747Sume * drops to zero, then it decrements the wire count.
1037121747Sume */
1038121747Sumestatic int
1039121747Sume_pmap_unwire_pte_hold(pmap_t pmap, vm_page_t m) {
1040121747Sume
1041121747Sume	while (vm_page_sleep_busy(m, FALSE, "pmuwpt"))
104255163Sshin		;
1043121747Sume
1044121747Sume	if (m->hold_count == 0) {
1045121747Sume		vm_offset_t pteva;
1046121747Sume		/*
1047121747Sume		 * unmap the page table page
1048121747Sume		 */
1049121747Sume		pmap->pm_pdir[m->pindex] = 0;
1050121747Sume		--pmap->pm_stats.resident_count;
1051121747Sume		if ((((unsigned)pmap->pm_pdir[PTDPTDI]) & PG_FRAME) ==
1052121747Sume			(((unsigned) PTDpde) & PG_FRAME)) {
1053121747Sume			/*
1054121747Sume			 * Do a invltlb to make the invalidated mapping
1055121747Sume			 * take effect immediately.
1056121747Sume			 */
1057121747Sume			pteva = UPT_MIN_ADDRESS + i386_ptob(m->pindex);
1058121747Sume			pmap_TLB_invalidate(pmap, pteva);
1059121747Sume		}
1060121747Sume
1061121747Sume		if (pmap->pm_ptphint == m)
1062121747Sume			pmap->pm_ptphint = NULL;
1063121747Sume
1064121747Sume		/*
1065121747Sume		 * If the page is finally unwired, simply free it.
1066121747Sume		 */
1067121747Sume		--m->wire_count;
1068121747Sume		if (m->wire_count == 0) {
1069121747Sume
1070121747Sume			vm_page_flash(m);
1071121747Sume			vm_page_busy(m);
1072121747Sume			vm_page_free_zero(m);
1073121747Sume			--cnt.v_wire_count;
1074121747Sume		}
1075121747Sume		return 1;
1076121747Sume	}
1077121747Sume	return 0;
1078121747Sume}
1079121747Sume
1080121747Sumestatic PMAP_INLINE int
1081121747Sumepmap_unwire_pte_hold(pmap_t pmap, vm_page_t m) {
1082121747Sume	vm_page_unhold(m);
1083121747Sume	if (m->hold_count == 0)
1084121747Sume		return _pmap_unwire_pte_hold(pmap, m);
1085121747Sume	else
1086121747Sume		return 0;
1087121747Sume}
1088121747Sume
1089121747Sume/*
1090121747Sume * After removing a page table entry, this routine is used to
1091121747Sume * conditionally free the page, and manage the hold/wire counts.
1092121747Sume */
1093129905Sumestatic int
1094121747Sumepmap_unuse_pt(pmap, va, mpte)
1095121747Sume	pmap_t pmap;
1096121747Sume	vm_offset_t va;
1097121747Sume	vm_page_t mpte;
1098121747Sume{
1099121747Sume	unsigned ptepindex;
1100121747Sume	if (va >= UPT_MIN_ADDRESS)
1101121747Sume		return 0;
1102121747Sume
1103121747Sume	if (mpte == NULL) {
1104121747Sume		ptepindex = (va >> PDRSHIFT);
1105121747Sume		if (pmap->pm_ptphint &&
110655163Sshin			(pmap->pm_ptphint->pindex == ptepindex)) {
110755163Sshin			mpte = pmap->pm_ptphint;
110855163Sshin		} else {
110955163Sshin			mpte = pmap_page_lookup( pmap->pm_pteobj, ptepindex);
111055163Sshin			pmap->pm_ptphint = mpte;
111161877Sume		}
111255163Sshin	}
111355163Sshin
111455163Sshin	return pmap_unwire_pte_hold(pmap, mpte);
111555163Sshin}
1116121474Sume
111755163Sshinvoid
111855163Sshinpmap_pinit0(pmap)
111955163Sshin	struct pmap *pmap;
112055163Sshin{
112155163Sshin	pmap->pm_pdir =
112255163Sshin		(pd_entry_t *)kmem_alloc_pageable(kernel_map, PAGE_SIZE);
112355163Sshin	pmap_kenter((vm_offset_t) pmap->pm_pdir, (vm_offset_t) IdlePTD);
112455163Sshin	pmap->pm_count = 1;
112555163Sshin	pmap->pm_active = 0;
112655163Sshin	pmap->pm_ptphint = NULL;
1127121474Sume	TAILQ_INIT(&pmap->pm_pvlist);
1128121474Sume	bzero(&pmap->pm_stats, sizeof pmap->pm_stats);
1129121474Sume}
1130121474Sume
1131121474Sume/*
1132121474Sume * Initialize a preallocated and zeroed pmap structure,
1133121474Sume * such as one in a vmspace structure.
1134121474Sume */
1135121474Sumevoid
1136121474Sumepmap_pinit(pmap)
1137121474Sume	register struct pmap *pmap;
113861877Sume{
113961877Sume	vm_page_t ptdpg;
114061877Sume
114155163Sshin	/*
114261877Sume	 * No need to allocate page table space yet but we do need a valid
114355163Sshin	 * page directory table.
114455163Sshin	 */
114555163Sshin	if (pmap->pm_pdir == NULL)
114655163Sshin		pmap->pm_pdir =
114761877Sume			(pd_entry_t *)kmem_alloc_pageable(kernel_map, PAGE_SIZE);
114861877Sume
114961877Sume	/*
115061877Sume	 * allocate object for the ptes
115161877Sume	 */
115261877Sume	if (pmap->pm_pteobj == NULL)
115361877Sume		pmap->pm_pteobj = vm_object_allocate( OBJT_DEFAULT, PTDPTDI + 1);
115461877Sume
115561877Sume	/*
115661877Sume	 * allocate the page directory page
115761877Sume	 */
115861877Sume	ptdpg = vm_page_grab( pmap->pm_pteobj, PTDPTDI,
115961877Sume			VM_ALLOC_NORMAL | VM_ALLOC_RETRY);
116061877Sume
116155163Sshin	ptdpg->wire_count = 1;
116255163Sshin	++cnt.v_wire_count;
116355163Sshin
116455163Sshin
116555163Sshin	vm_page_flag_clear(ptdpg, PG_MAPPED | PG_BUSY); /* not usually mapped*/
116655163Sshin	ptdpg->valid = VM_PAGE_BITS_ALL;
116755163Sshin
116855163Sshin	pmap_kenter((vm_offset_t) pmap->pm_pdir, VM_PAGE_TO_PHYS(ptdpg));
116955163Sshin	if ((ptdpg->flags & PG_ZERO) == 0)
117055163Sshin		bzero(pmap->pm_pdir, PAGE_SIZE);
117155163Sshin
117255163Sshin#ifdef SMP
117355163Sshin	pmap->pm_pdir[MPPTDI] = PTD[MPPTDI];
117455163Sshin#endif
1175140906Sume
117655163Sshin	/* install self-referential address mapping entry */
117755163Sshin	*(unsigned *) (pmap->pm_pdir + PTDPTDI) =
117855163Sshin		VM_PAGE_TO_PHYS(ptdpg) | PG_V | PG_RW | PG_A | PG_M;
117955163Sshin
1180140906Sume	pmap->pm_count = 1;
118155163Sshin	pmap->pm_active = 0;
118255163Sshin	pmap->pm_ptphint = NULL;
118355163Sshin	TAILQ_INIT(&pmap->pm_pvlist);
118455163Sshin	bzero(&pmap->pm_stats, sizeof pmap->pm_stats);
118555163Sshin}
118655163Sshin
118755163Sshin/*
118855163Sshin * Wire in kernel global address entries.  To avoid a race condition
118955163Sshin * between pmap initialization and pmap_growkernel, this procedure
119055163Sshin * should be called after the vmspace is attached to the process
119155163Sshin * but before this pmap is activated.
1192121474Sume */
1193121474Sumevoid
1194121474Sumepmap_pinit2(pmap)
1195121474Sume	struct pmap *pmap;
1196121474Sume{
1197121474Sume	/* XXX copies current process, does not fill in MPPTDI */
119855163Sshin	bcopy(PTD + KPTDI, pmap->pm_pdir + KPTDI, nkpt * PTESIZE);
119955163Sshin}
120055163Sshin
120155163Sshinstatic int
120262614Sitojunpmap_release_free_page(pmap, p)
120362614Sitojun	struct pmap *pmap;
120462614Sitojun	vm_page_t p;
120562614Sitojun{
120662614Sitojun	unsigned *pde = (unsigned *) pmap->pm_pdir;
120762614Sitojun	/*
120862614Sitojun	 * This code optimizes the case of freeing non-busy
120962614Sitojun	 * page-table pages.  Those pages are zero now, and
1210140906Sume	 * might as well be placed directly into the zero queue.
1211140906Sume	 */
1212140906Sume	if (vm_page_sleep_busy(p, FALSE, "pmaprl"))
1213140906Sume		return 0;
1214140906Sume
1215140906Sume	vm_page_busy(p);
1216140906Sume
1217140906Sume	/*
121862614Sitojun	 * Remove the page table page from the processes address space.
121962614Sitojun	 */
122062614Sitojun	pde[p->pindex] = 0;
122162614Sitojun	pmap->pm_stats.resident_count--;
122262614Sitojun
122362614Sitojun	if (p->hold_count)  {
122462614Sitojun		panic("pmap_release: freeing held page table page");
122562614Sitojun	}
122662614Sitojun	/*
122762614Sitojun	 * Page directory pages need to have the kernel
122862614Sitojun	 * stuff cleared, so they can go into the zero queue also.
122962614Sitojun	 */
123062614Sitojun	if (p->pindex == PTDPTDI) {
1231140906Sume		bzero(pde + KPTDI, nkpt * PTESIZE);
1232140906Sume#ifdef SMP
1233140906Sume		pde[MPPTDI] = 0;
1234140906Sume#endif
1235140906Sume		pde[APTDPTDI] = 0;
1236140906Sume		pmap_kremove((vm_offset_t) pmap->pm_pdir);
1237140906Sume	}
1238140906Sume
123962614Sitojun	if (pmap->pm_ptphint && (pmap->pm_ptphint->pindex == p->pindex))
124062614Sitojun		pmap->pm_ptphint = NULL;
124162614Sitojun
1242105940Sume	p->wire_count--;
124362614Sitojun	cnt.v_wire_count--;
124462614Sitojun	vm_page_free_zero(p);
124555163Sshin	return 1;
124655163Sshin}
124755163Sshin
124855163Sshin/*
124955163Sshin * this routine is called if the page table page is not
125055163Sshin * mapped correctly.
125155163Sshin */
125255163Sshinstatic vm_page_t
125355163Sshin_pmap_allocpte(pmap, ptepindex)
125455163Sshin	pmap_t	pmap;
125555163Sshin	unsigned ptepindex;
125655163Sshin{
125755163Sshin	vm_offset_t pteva, ptepa;
125855163Sshin	vm_page_t m;
125955163Sshin
126055163Sshin	/*
126155163Sshin	 * Find or fabricate a new pagetable page
126255163Sshin	 */
126355163Sshin	m = vm_page_grab(pmap->pm_pteobj, ptepindex,
126455163Sshin			VM_ALLOC_ZERO | VM_ALLOC_RETRY);
126555163Sshin
126655163Sshin	KASSERT(m->queue == PQ_NONE,
126761877Sume		("_pmap_allocpte: %p->queue != PQ_NONE", m));
1268140906Sume
126955163Sshin	if (m->wire_count == 0)
127055163Sshin		cnt.v_wire_count++;
127155163Sshin	m->wire_count++;
127255163Sshin
127361877Sume	/*
127455163Sshin	 * Increment the hold count for the page table page
127555163Sshin	 * (denoting a new mapping.)
1276121474Sume	 */
1277121474Sume	m->hold_count++;
1278121474Sume
1279121474Sume	/*
1280121474Sume	 * Map the pagetable page into the process address space, if
1281121474Sume	 * it isn't already there.
128255163Sshin	 */
128355163Sshin
128455163Sshin	pmap->pm_stats.resident_count++;
128565532Snectar
128655163Sshin	ptepa = VM_PAGE_TO_PHYS(m);
1287140906Sume	pmap->pm_pdir[ptepindex] =
128855163Sshin		(pd_entry_t) (ptepa | PG_U | PG_RW | PG_V | PG_A | PG_M);
128955163Sshin
129055163Sshin	/*
1291140906Sume	 * Set the page table hint
129255163Sshin	 */
129355163Sshin	pmap->pm_ptphint = m;
129455163Sshin
129555163Sshin	/*
129655163Sshin	 * Try to use the new mapping, but if we cannot, then
129755163Sshin	 * do it with the routine that maps the page explicitly.
129855163Sshin	 */
129955163Sshin	if ((m->flags & PG_ZERO) == 0) {
130055163Sshin		if ((((unsigned)pmap->pm_pdir[PTDPTDI]) & PG_FRAME) ==
130161877Sume			(((unsigned) PTDpde) & PG_FRAME)) {
130261877Sume			pteva = UPT_MIN_ADDRESS + i386_ptob(ptepindex);
130355163Sshin			bzero((caddr_t) pteva, PAGE_SIZE);
1304140906Sume		} else {
130561877Sume			pmap_zero_page(ptepa);
1306105943Sume		}
130755163Sshin	}
130855163Sshin
130955163Sshin	m->valid = VM_PAGE_BITS_ALL;
131055163Sshin	vm_page_flag_clear(m, PG_ZERO);
131161877Sume	vm_page_flag_set(m, PG_MAPPED);
1312105943Sume	vm_page_wakeup(m);
131361877Sume
1314121425Sume	return m;
131561877Sume}
131661877Sume
131755163Sshinstatic vm_page_t
131855163Sshinpmap_allocpte(pmap, va)
131955163Sshin	pmap_t	pmap;
132055163Sshin	vm_offset_t va;
132155163Sshin{
132255163Sshin	unsigned ptepindex;
132355163Sshin	vm_offset_t ptepa;
132455163Sshin	vm_page_t m;
132555163Sshin
132655163Sshin	/*
132755163Sshin	 * Calculate pagetable page index
132855163Sshin	 */
132955163Sshin	ptepindex = va >> PDRSHIFT;
133055163Sshin
133155163Sshin	/*
133255163Sshin	 * Get the page directory entry
1333121474Sume	 */
133455163Sshin	ptepa = (vm_offset_t) pmap->pm_pdir[ptepindex];
133555163Sshin
1336121474Sume	/*
133755163Sshin	 * This supports switching from a 4MB page to a
133855163Sshin	 * normal 4K page.
133955163Sshin	 */
134055163Sshin	if (ptepa & PG_PS) {
134155163Sshin		pmap->pm_pdir[ptepindex] = 0;
134255163Sshin		ptepa = 0;
134355163Sshin		invltlb();
134455163Sshin	}
134555163Sshin
134655163Sshin	/*
134755163Sshin	 * If the page table page is mapped, we just increment the
134855163Sshin	 * hold count, and activate it.
134955163Sshin	 */
135055163Sshin	if (ptepa) {
135155163Sshin		/*
135255163Sshin		 * In order to get the page table page, try the
135355163Sshin		 * hint first.
135455163Sshin		 */
135555163Sshin		if (pmap->pm_ptphint &&
135655163Sshin			(pmap->pm_ptphint->pindex == ptepindex)) {
135755163Sshin			m = pmap->pm_ptphint;
135855163Sshin		} else {
135955163Sshin			m = pmap_page_lookup( pmap->pm_pteobj, ptepindex);
136055163Sshin			pmap->pm_ptphint = m;
136155163Sshin		}
136255163Sshin		m->hold_count++;
136355163Sshin		return m;
136455163Sshin	}
136555163Sshin	/*
136655163Sshin	 * Here if the pte page isn't mapped, or if it has been deallocated.
136755163Sshin	 */
136855163Sshin	return _pmap_allocpte(pmap, ptepindex);
136955163Sshin}
137055163Sshin
137155163Sshin
137255163Sshin/***************************************************
137355163Sshin* Pmap allocation/deallocation routines.
137455163Sshin ***************************************************/
137555163Sshin
137655163Sshin/*
137755163Sshin * Release any resources held by the given physical map.
137855163Sshin * Called when a pmap initialized by pmap_pinit is being released.
137955163Sshin * Should only be called if the map contains no valid mappings.
138055163Sshin */
138155163Sshinvoid
138255163Sshinpmap_release(pmap)
138355163Sshin	register struct pmap *pmap;
138455163Sshin{
138555163Sshin	vm_page_t p,n,ptdpg;
138655163Sshin	vm_object_t object = pmap->pm_pteobj;
138755163Sshin	int curgeneration;
138855163Sshin
138955163Sshin#if defined(DIAGNOSTIC)
139055163Sshin	if (object->ref_count != 1)
139155163Sshin		panic("pmap_release: pteobj reference count != 1");
139255163Sshin#endif
139355163Sshin
139455163Sshin	ptdpg = NULL;
139555163Sshinretry:
139655163Sshin	curgeneration = object->generation;
139761877Sume	for (p = TAILQ_FIRST(&object->memq); p != NULL; p = n) {
139861877Sume		n = TAILQ_NEXT(p, listq);
139955163Sshin		if (p->pindex == PTDPTDI) {
140055163Sshin			ptdpg = p;
140155163Sshin			continue;
140265532Snectar		}
140355163Sshin		while (1) {
140455163Sshin			if (!pmap_release_free_page(pmap, p) &&
140565532Snectar				(object->generation != curgeneration))
140655163Sshin				goto retry;
140755163Sshin		}
140865532Snectar	}
140955163Sshin
141055163Sshin	if (ptdpg && !pmap_release_free_page(pmap, ptdpg))
141155163Sshin		goto retry;
141255163Sshin}
141355163Sshin
141455163Sshin/*
141555163Sshin * grow the number of kernel page table entries, if needed
141655163Sshin */
141761877Sumevoid
141855163Sshinpmap_growkernel(vm_offset_t addr)
141961877Sume{
142055163Sshin	struct proc *p;
142155163Sshin	struct pmap *pmap;
142255163Sshin	int s;
142355163Sshin	vm_offset_t ptppaddr;
142455163Sshin	vm_page_t nkpg;
142555163Sshin	pd_entry_t newpdir;
142655163Sshin
142755163Sshin	s = splhigh();
142855163Sshin	if (kernel_vm_end == 0) {
142955163Sshin		kernel_vm_end = KERNBASE;
143055163Sshin		nkpt = 0;
143155163Sshin		while (pdir_pde(PTD, kernel_vm_end)) {
143255163Sshin			kernel_vm_end = (kernel_vm_end + PAGE_SIZE * NPTEPG) & ~(PAGE_SIZE * NPTEPG - 1);
143355163Sshin			nkpt++;
143455163Sshin		}
143555163Sshin	}
143661877Sume	addr = (addr + PAGE_SIZE * NPTEPG) & ~(PAGE_SIZE * NPTEPG - 1);
143761877Sume	while (kernel_vm_end < addr) {
143861877Sume		if (pdir_pde(PTD, kernel_vm_end)) {
143961877Sume			kernel_vm_end = (kernel_vm_end + PAGE_SIZE * NPTEPG) & ~(PAGE_SIZE * NPTEPG - 1);
144055163Sshin			continue;
144161877Sume		}
144261877Sume
144355163Sshin		/*
144461877Sume		 * This index is bogus, but out of the way
144555163Sshin		 */
144655163Sshin		nkpg = vm_page_alloc(kptobj, nkpt, VM_ALLOC_SYSTEM);
144755163Sshin		if (!nkpg)
144855163Sshin			panic("pmap_growkernel: no memory to grow kernel");
144955163Sshin
145055163Sshin		nkpt++;
145155163Sshin
145255163Sshin		vm_page_wire(nkpg);
145355163Sshin		ptppaddr = VM_PAGE_TO_PHYS(nkpg);
145455163Sshin		pmap_zero_page(ptppaddr);
145555163Sshin		newpdir = (pd_entry_t) (ptppaddr | PG_V | PG_RW | PG_A | PG_M);
145655163Sshin		pdir_pde(PTD, kernel_vm_end) = newpdir;
145755163Sshin
145855163Sshin		LIST_FOREACH(p, &allproc, p_list) {
145955163Sshin			if (p->p_vmspace) {
146055163Sshin				pmap = vmspace_pmap(p->p_vmspace);
146155163Sshin				*pmap_pde(pmap, kernel_vm_end) = newpdir;
146255163Sshin			}
1463105940Sume		}
146455163Sshin		*pmap_pde(kernel_pmap, kernel_vm_end) = newpdir;
146555163Sshin		kernel_vm_end = (kernel_vm_end + PAGE_SIZE * NPTEPG) & ~(PAGE_SIZE * NPTEPG - 1);
1466105940Sume	}
146755163Sshin	splx(s);
1468121474Sume}
1469121474Sume
147055163Sshin/*
147155163Sshin *	Retire the given physical map from service.
1472121474Sume *	Should only be called if the map contains
147355163Sshin *	no valid mappings.
147455163Sshin */
147555163Sshinvoid
147655163Sshinpmap_destroy(pmap)
147755163Sshin	register pmap_t pmap;
147855163Sshin{
147955163Sshin	int count;
1480126243Sgreen
1481126243Sgreen	if (pmap == NULL)
1482126243Sgreen		return;
148355163Sshin
1484126243Sgreen	count = --pmap->pm_count;
148555163Sshin	if (count == 0) {
1486126243Sgreen		pmap_release(pmap);
148755163Sshin		panic("destroying a pmap is not yet implemented");
148855163Sshin	}
148955163Sshin}
149055163Sshin
149155163Sshin/*
149261877Sume *	Add a reference to the specified pmap.
149361877Sume */
149455163Sshinvoid
149555163Sshinpmap_reference(pmap)
149655163Sshin	pmap_t pmap;
149761877Sume{
149861877Sume	if (pmap != NULL) {
149955163Sshin		pmap->pm_count++;
150055163Sshin	}
150155163Sshin}
150255163Sshin
150355163Sshin/***************************************************
150455163Sshin* page management routines.
150555163Sshin ***************************************************/
150655163Sshin
150755163Sshin/*
150855163Sshin * free the pv_entry back to the free list
150955163Sshin */
151055163Sshinstatic PMAP_INLINE void
151155163Sshinfree_pv_entry(pv)
151255163Sshin	pv_entry_t pv;
151355163Sshin{
151455163Sshin	pv_entry_count--;
151555163Sshin	zfreei(pvzone, pv);
151655163Sshin}
151755163Sshin
151855163Sshin/*
151955163Sshin * get a new pv_entry, allocating a block from the system
152055163Sshin * when needed.
152161877Sume * the memory allocation is performed bypassing the malloc code
152261877Sume * because of the possibility of allocations at interrupt time.
152361877Sume */
152461877Sumestatic pv_entry_t
152561877Sumeget_pv_entry(void)
152661877Sume{
1527121474Sume	pv_entry_count++;
1528121474Sume	if (pv_entry_high_water &&
1529121474Sume		(pv_entry_count > pv_entry_high_water) &&
153061877Sume		(pmap_pagedaemon_waken == 0)) {
153161877Sume		pmap_pagedaemon_waken = 1;
1532121474Sume		wakeup (&vm_pages_needed);
1533121474Sume	}
153461877Sume	return zalloci(pvzone);
1535121474Sume}
153661877Sume
1537121474Sume/*
1538121474Sume * This routine is very drastic, but can save the system
1539121474Sume * in a pinch.
1540121474Sume */
1541121474Sumevoid
1542121474Sumepmap_collect() {
1543121474Sume	pv_table_t *ppv;
1544121474Sume	int i;
1545121474Sume	vm_offset_t pa;
1546121474Sume	vm_page_t m;
1547121474Sume	static int warningdone=0;
1548121474Sume
1549121474Sume	if (pmap_pagedaemon_waken == 0)
1550121474Sume		return;
1551121474Sume
1552121474Sume	if (warningdone < 5) {
1553121474Sume		printf("pmap_collect: collecting pv entries -- suggest increasing PMAP_SHPGPERPROC\n");
1554121474Sume		warningdone++;
1555121474Sume	}
1556121474Sume
1557121474Sume	for(i = 0; i < pv_npg; i++) {
155861877Sume		if ((ppv = &pv_table[i]) == 0)
1559121474Sume			continue;
1560121474Sume		m = ppv->pv_vm_page;
1561121474Sume		if ((pa = VM_PAGE_TO_PHYS(m)) == 0)
156261877Sume			continue;
156361877Sume		if (m->wire_count || m->hold_count || m->busy ||
156461877Sume			(m->flags & PG_BUSY))
156561877Sume			continue;
156661877Sume		pmap_remove_all(pa);
156761877Sume	}
1568105943Sume	pmap_pagedaemon_waken = 0;
156961877Sume}
157061877Sume
1571105943Sume
157261877Sume/*
1573105943Sume * If it is the first entry on the list, it is actually
1574121474Sume * in the header and we must copy the following entry up
157561877Sume * to the header.  Otherwise we must search the list for
157661877Sume * the entry.  In either case we free the now unused entry.
1577121474Sume */
1578121474Sume
157962836Sitojunstatic int
158062836Sitojunpmap_remove_entry(pmap, ppv, va)
158162836Sitojun	struct pmap *pmap;
158262836Sitojun	pv_table_t *ppv;
1583121474Sume	vm_offset_t va;
158461877Sume{
158561877Sume	pv_entry_t pv;
158661877Sume	int rtval;
158761877Sume	int s;
158861877Sume
1589105943Sume	s = splvm();
1590105943Sume	if (ppv->pv_list_count < pmap->pm_stats.resident_count) {
159161877Sume		for (pv = TAILQ_FIRST(&ppv->pv_list);
1592105943Sume			pv;
159361877Sume			pv = TAILQ_NEXT(pv, pv_list)) {
159461877Sume			if (pmap == pv->pv_pmap && va == pv->pv_va)
159561877Sume				break;
159661877Sume		}
159761877Sume	} else {
159861877Sume		for (pv = TAILQ_FIRST(&pmap->pm_pvlist);
159961877Sume			pv;
160061877Sume			pv = TAILQ_NEXT(pv, pv_plist)) {
160161877Sume			if (va == pv->pv_va)
160261877Sume				break;
160361877Sume		}
1604121474Sume	}
1605105943Sume
1606105943Sume	rtval = 0;
1607105943Sume	if (pv) {
1608105943Sume
1609105943Sume		rtval = pmap_unuse_pt(pmap, va, pv->pv_ptem);
161061877Sume		TAILQ_REMOVE(&ppv->pv_list, pv, pv_list);
161161877Sume		ppv->pv_list_count--;
161261877Sume		if (TAILQ_FIRST(&ppv->pv_list) == NULL)
161361877Sume			vm_page_flag_clear(ppv->pv_vm_page, PG_MAPPED | PG_WRITEABLE);
161461877Sume
1615121426Sume		TAILQ_REMOVE(&pmap->pm_pvlist, pv, pv_plist);
1616121426Sume		free_pv_entry(pv);
1617121426Sume	}
1618102237Spirzyk
1619121426Sume	splx(s);
1620121426Sume	return rtval;
1621121426Sume}
1622121426Sume
1623121426Sume/*
1624102237Spirzyk * Create a pv entry for page at pa for
1625121426Sume * (pmap, va).
1626121426Sume */
1627121426Sumestatic void
1628121426Sumepmap_insert_entry(pmap, va, mpte, pa)
1629121426Sume	pmap_t pmap;
1630121426Sume	vm_offset_t va;
1631121426Sume	vm_page_t mpte;
1632121426Sume	vm_offset_t pa;
1633121426Sume{
1634102237Spirzyk
1635121426Sume	int s;
1636121426Sume	pv_entry_t pv;
1637121426Sume	pv_table_t *ppv;
1638121426Sume
1639121426Sume	s = splvm();
1640126243Sgreen	pv = get_pv_entry();
1641102237Spirzyk	pv->pv_va = va;
1642102237Spirzyk	pv->pv_pmap = pmap;
1643121426Sume	pv->pv_ptem = mpte;
1644121426Sume
1645121426Sume	TAILQ_INSERT_TAIL(&pmap->pm_pvlist, pv, pv_plist);
1646121426Sume
1647121426Sume	ppv = pa_to_pvh(pa);
1648121426Sume	TAILQ_INSERT_TAIL(&ppv->pv_list, pv, pv_list);
1649121426Sume	ppv->pv_list_count++;
1650121426Sume
1651121426Sume	splx(s);
1652121426Sume}
1653121426Sume
1654121426Sume/*
1655121426Sume * pmap_remove_pte: do the things to unmap a page in a process
1656121426Sume */
1657121426Sumestatic int
1658121426Sumepmap_remove_pte(pmap, ptq, va)
1659121426Sume	struct pmap *pmap;
1660121426Sume	unsigned *ptq;
1661102237Spirzyk	vm_offset_t va;
1662102237Spirzyk{
1663121426Sume	unsigned oldpte;
1664121426Sume	pv_table_t *ppv;
1665102237Spirzyk
1666121426Sume	oldpte = loadandclear(ptq);
1667121426Sume	if (oldpte & PG_W)
1668121426Sume		pmap->pm_stats.wired_count -= 1;
1669121426Sume	/*
1670121426Sume	 * Machines that don't support invlpg, also don't support
1671102237Spirzyk	 * PG_G.
1672102237Spirzyk	 */
167361877Sume	if (oldpte & PG_G)
167461877Sume		invlpg(va);
167561877Sume	pmap->pm_stats.resident_count -= 1;
167661877Sume	if (oldpte & PG_MANAGED) {
167765532Snectar		ppv = pa_to_pvh(oldpte);
167861877Sume		if (oldpte & PG_M) {
167961877Sume#if defined(PMAP_DIAGNOSTIC)
168061877Sume			if (pmap_nw_modified((pt_entry_t) oldpte)) {
168161877Sume				printf(
168261877Sume	"pmap_remove: modified page not writable: va: 0x%x, pte: 0x%x\n",
168361877Sume				    va, oldpte);
168461877Sume			}
168561877Sume#endif
168661877Sume			if (pmap_track_modified(va))
168761877Sume				vm_page_dirty(ppv->pv_vm_page);
168861877Sume		}
168961877Sume		if (oldpte & PG_A)
169061877Sume			vm_page_flag_set(ppv->pv_vm_page, PG_REFERENCED);
169161877Sume		return pmap_remove_entry(pmap, ppv, va);
169261877Sume	} else {
169361877Sume		return pmap_unuse_pt(pmap, va, NULL);
169461877Sume	}
1695105940Sume
1696105940Sume	return 0;
169761877Sume}
169861877Sume
169992905Sobrien/*
170061877Sume * Remove a single page from a process address space
170161877Sume */
170261877Sumestatic void
170361877Sumepmap_remove_page(pmap, va)
170461877Sume	struct pmap *pmap;
170561877Sume	register vm_offset_t va;
170661877Sume{
170761877Sume	register unsigned *ptq;
170861877Sume
170961877Sume	/*
171061877Sume	 * if there is no pte for this address, just skip it!!!
171161877Sume	 */
171261877Sume	if (*pmap_pde(pmap, va) == 0) {
171361877Sume		return;
171461877Sume	}
171561877Sume
171661877Sume	/*
171761877Sume	 * get a local va for mappings for this pmap.
171861877Sume	 */
171961877Sume	ptq = get_ptbase(pmap) + i386_btop(va);
172061877Sume	if (*ptq) {
172161877Sume		(void) pmap_remove_pte(pmap, ptq, va);
172261877Sume		pmap_TLB_invalidate(pmap, va);
1723105940Sume	}
172461877Sume	return;
172561877Sume}
172661877Sume
172761877Sume/*
172861877Sume *	Remove the given range of addresses from the specified map.
1729105940Sume *
173061877Sume *	It is assumed that the start and end are properly
173161877Sume *	rounded to the page size.
173261877Sume */
173361877Sumevoid
173461877Sumepmap_remove(pmap, sva, eva)
173561877Sume	struct pmap *pmap;
173661877Sume	register vm_offset_t sva;
173761877Sume	register vm_offset_t eva;
173861877Sume{
173961877Sume	register unsigned *ptbase;
174061877Sume	vm_offset_t pdnxt;
174161877Sume	vm_offset_t ptpaddr;
174261877Sume	vm_offset_t sindex, eindex;
174361877Sume	int anyvalid;
174461877Sume
174561877Sume	if (pmap == NULL)
174661877Sume		return;
174761877Sume
174861877Sume	if (pmap->pm_stats.resident_count == 0)
174961877Sume		return;
175061877Sume
175161877Sume	/*
175261877Sume	 * special handling of removing one page.  a very
1753105940Sume	 * common operation and easy to short circuit some
175461877Sume	 * code.
175561877Sume	 */
175661877Sume	if (((sva + PAGE_SIZE) == eva) &&
175761877Sume		(((unsigned) pmap->pm_pdir[(sva >> PDRSHIFT)] & PG_PS) == 0)) {
175861877Sume		pmap_remove_page(pmap, sva);
175961877Sume		return;
176061877Sume	}
176161877Sume
176261877Sume	anyvalid = 0;
176361877Sume
176461877Sume	/*
176561877Sume	 * Get a local virtual address for the mappings that are being
176661877Sume	 * worked with.
176761877Sume	 */
176861877Sume	ptbase = get_ptbase(pmap);
176961877Sume
177061877Sume	sindex = i386_btop(sva);
177161877Sume	eindex = i386_btop(eva);
177261877Sume
177361877Sume	for (; sindex < eindex; sindex = pdnxt) {
177461877Sume		unsigned pdirindex;
177561877Sume
177661877Sume		/*
177761877Sume		 * Calculate index for next page table.
177861877Sume		 */
177961877Sume		pdnxt = ((sindex + NPTEPG) & ~(NPTEPG - 1));
1780105940Sume		if (pmap->pm_stats.resident_count == 0)
178161877Sume			break;
178261877Sume
178361877Sume		pdirindex = sindex / NPDEPG;
1784114443Snectar		if (((ptpaddr = (unsigned) pmap->pm_pdir[pdirindex]) & PG_PS) != 0) {
178561877Sume			pmap->pm_pdir[pdirindex] = 0;
178661877Sume			pmap->pm_stats.resident_count -= NBPDR / PAGE_SIZE;
178761877Sume			anyvalid++;
178861877Sume			continue;
178961877Sume		}
179061877Sume
179161877Sume		/*
179261877Sume		 * Weed out invalid mappings. Note: we assume that the page
179361877Sume		 * directory table is always allocated, and in kernel virtual.
179461877Sume		 */
179561877Sume		if (ptpaddr == 0)
179661877Sume			continue;
179761877Sume
179861877Sume		/*
179961877Sume		 * Limit our scan to either the end of the va represented
180061877Sume		 * by the current page table page, or to the end of the
180161877Sume		 * range being removed.
180261877Sume		 */
180361877Sume		if (pdnxt > eindex) {
180461877Sume			pdnxt = eindex;
180561877Sume		}
180661877Sume
180761877Sume		for ( ;sindex != pdnxt; sindex++) {
180861877Sume			vm_offset_t va;
180961877Sume			if (ptbase[sindex] == 0) {
181061877Sume				continue;
181161877Sume			}
181261877Sume			va = i386_ptob(sindex);
181361877Sume
181461877Sume			anyvalid++;
181561877Sume			if (pmap_remove_pte(pmap,
181661877Sume				ptbase + sindex, va))
181761877Sume				break;
181861877Sume		}
181961877Sume	}
182061877Sume
182161877Sume	if (anyvalid)
182261877Sume		pmap_TLB_invalidate_all(pmap);
182361877Sume}
182461877Sume
182561877Sume/*
182661877Sume *	Routine:	pmap_remove_all
182761877Sume *	Function:
182861877Sume *		Removes this physical page from
182961877Sume *		all physical maps in which it resides.
183061877Sume *		Reflects back modify bits to the pager.
183161877Sume *
183261877Sume *	Notes:
183361877Sume *		Original versions of this routine were very
183461877Sume *		inefficient because they iteratively called
183561877Sume *		pmap_remove (slow...)
183661877Sume */
183761877Sume
183861877Sumestatic void
183961877Sumepmap_remove_all(pa)
184061877Sume	vm_offset_t pa;
184161877Sume{
184261877Sume	register pv_entry_t pv;
184361877Sume	pv_table_t *ppv;
184461877Sume	register unsigned *pte, tpte;
184561877Sume	int s;
184661877Sume
184761877Sume#if defined(PMAP_DIAGNOSTIC)
184861877Sume	/*
184961877Sume	 * XXX this makes pmap_page_protect(NONE) illegal for non-managed
185061877Sume	 * pages!
185161877Sume	 */
185261877Sume	if (!pmap_is_managed(pa)) {
185361877Sume		panic("pmap_page_protect: illegal for unmanaged page, va: 0x%x", pa);
185461877Sume	}
185561877Sume#endif
185661877Sume
185761877Sume	s = splvm();
185861877Sume	ppv = pa_to_pvh(pa);
185961877Sume	while ((pv = TAILQ_FIRST(&ppv->pv_list)) != NULL) {
186061877Sume		pv->pv_pmap->pm_stats.resident_count--;
186161877Sume
186261877Sume		pte = pmap_pte_quick(pv->pv_pmap, pv->pv_va);
186361877Sume
1864102237Spirzyk		tpte = loadandclear(pte);
1865102237Spirzyk		if (tpte & PG_W)
1866102237Spirzyk			pv->pv_pmap->pm_stats.wired_count--;
1867102237Spirzyk
1868102237Spirzyk		if (tpte & PG_A)
1869102237Spirzyk			vm_page_flag_set(ppv->pv_vm_page, PG_REFERENCED);
1870102237Spirzyk
1871102237Spirzyk		/*
1872102237Spirzyk		 * Update the vm_page_t clean and reference bits.
1873102237Spirzyk		 */
1874102237Spirzyk		if (tpte & PG_M) {
1875102237Spirzyk#if defined(PMAP_DIAGNOSTIC)
1876102237Spirzyk			if (pmap_nw_modified((pt_entry_t) tpte)) {
187761877Sume				printf(
187861877Sume	"pmap_remove_all: modified page not writable: va: 0x%x, pte: 0x%x\n",
187961877Sume				    pv->pv_va, tpte);
188061877Sume			}
188161877Sume#endif
188261877Sume			if (pmap_track_modified(pv->pv_va))
188361877Sume				vm_page_dirty(ppv->pv_vm_page);
188461877Sume		}
188561877Sume		pmap_TLB_invalidate(pv->pv_pmap, pv->pv_va);
188661877Sume
188761877Sume		TAILQ_REMOVE(&pv->pv_pmap->pm_pvlist, pv, pv_plist);
188861877Sume		TAILQ_REMOVE(&ppv->pv_list, pv, pv_list);
1889121426Sume		ppv->pv_list_count--;
1890121426Sume		pmap_unuse_pt(pv->pv_pmap, pv->pv_va, pv->pv_ptem);
1891121426Sume		free_pv_entry(pv);
1892121426Sume	}
1893121426Sume
1894121426Sume	vm_page_flag_clear(ppv->pv_vm_page, PG_MAPPED | PG_WRITEABLE);
1895121426Sume
1896121426Sume	splx(s);
1897121426Sume}
1898121426Sume
1899121426Sume/*
1900121426Sume *	Set the physical protection on the
1901121426Sume *	specified range of this map as requested.
1902121426Sume */
1903121426Sumevoid
1904121426Sumepmap_protect(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, vm_prot_t prot)
1905121426Sume{
1906121426Sume	register unsigned *ptbase;
1907121426Sume	vm_offset_t pdnxt, ptpaddr;
1908121426Sume	vm_pindex_t sindex, eindex;
1909121426Sume	int anychanged;
1910121426Sume
1911121426Sume
1912121426Sume	if (pmap == NULL)
1913121426Sume		return;
1914121426Sume
1915121426Sume	if ((prot & VM_PROT_READ) == VM_PROT_NONE) {
1916121426Sume		pmap_remove(pmap, sva, eva);
1917121426Sume		return;
1918121426Sume	}
1919121426Sume
1920121426Sume	if (prot & VM_PROT_WRITE)
1921121426Sume		return;
1922121426Sume
1923121426Sume	anychanged = 0;
1924121426Sume
1925121426Sume	ptbase = get_ptbase(pmap);
1926121426Sume
1927121426Sume	sindex = i386_btop(sva);
1928121426Sume	eindex = i386_btop(eva);
1929121426Sume
1930121426Sume	for (; sindex < eindex; sindex = pdnxt) {
1931121426Sume
1932121426Sume		unsigned pdirindex;
1933121426Sume
1934121426Sume		pdnxt = ((sindex + NPTEPG) & ~(NPTEPG - 1));
1935121426Sume
1936121426Sume		pdirindex = sindex / NPDEPG;
1937121426Sume		if (((ptpaddr = (unsigned) pmap->pm_pdir[pdirindex]) & PG_PS) != 0) {
1938121426Sume			(unsigned) pmap->pm_pdir[pdirindex] &= ~(PG_M|PG_RW);
1939121426Sume			pmap->pm_stats.resident_count -= NBPDR / PAGE_SIZE;
1940121426Sume			anychanged++;
1941121426Sume			continue;
1942121426Sume		}
1943121426Sume
1944121426Sume		/*
1945121426Sume		 * Weed out invalid mappings. Note: we assume that the page
1946121426Sume		 * directory table is always allocated, and in kernel virtual.
1947121426Sume		 */
1948121426Sume		if (ptpaddr == 0)
1949121426Sume			continue;
1950121426Sume
1951121426Sume		if (pdnxt > eindex) {
1952121426Sume			pdnxt = eindex;
1953121426Sume		}
1954121426Sume
195561877Sume		for (; sindex != pdnxt; sindex++) {
195661877Sume
195765532Snectar			unsigned pbits;
195865532Snectar			pv_table_t *ppv;
195965532Snectar
196065532Snectar			pbits = ptbase[sindex];
196161877Sume
196261877Sume			if (pbits & PG_MANAGED) {
1963103357Sume				ppv = NULL;
1964130600Sume				if (pbits & PG_A) {
196565532Snectar					ppv = pa_to_pvh(pbits);
196661877Sume					vm_page_flag_set(ppv->pv_vm_page, PG_REFERENCED);
196761877Sume					pbits &= ~PG_A;
196861877Sume				}
1969130600Sume				if (pbits & PG_M) {
197065532Snectar					if (pmap_track_modified(i386_ptob(sindex))) {
197165532Snectar						if (ppv == NULL)
197261877Sume							ppv = pa_to_pvh(pbits);
197361877Sume						vm_page_dirty(ppv->pv_vm_page);
197461877Sume						pbits &= ~PG_M;
197561877Sume					}
197661877Sume				}
1977103357Sume			}
1978103357Sume
1979103357Sume			pbits &= ~PG_RW;
1980103357Sume
1981103357Sume			if (pbits != ptbase[sindex]) {
1982103357Sume				ptbase[sindex] = pbits;
1983103357Sume				anychanged = 1;
1984103357Sume			}
1985103357Sume		}
1986103357Sume	}
1987103357Sume	if (anychanged)
1988103357Sume		pmap_TLB_invalidate_all(pmap);
198961877Sume}
199061877Sume
1991130600Sume/*
199262614Sitojun *	Insert the given physical page (p) at
1993140896Sume *	the specified virtual address (v) in the
1994103357Sume *	target physical map with the protection requested.
1995103357Sume *
199661877Sume *	If specified, the page will be wired down, meaning
1997130600Sume *	that the related pte can not be reclaimed.
199862614Sitojun *
1999140896Sume *	NB:  This is the only routine which MAY NOT lazy-evaluate
2000103357Sume *	or lose information.  That is, this routine must actually
2001103357Sume *	insert this page into the given map NOW.
200261877Sume */
200361877Sumevoid
2004130600Sumepmap_enter(pmap_t pmap, vm_offset_t va, vm_offset_t pa, vm_prot_t prot,
200562614Sitojun	   boolean_t wired)
200662614Sitojun{
2007103357Sume	register unsigned *pte;
2008103357Sume	vm_offset_t opa;
200961877Sume	vm_offset_t origpte, newpte;
201061877Sume	vm_page_t mpte;
2011130600Sume
201262614Sitojun	if (pmap == NULL)
201362614Sitojun		return;
2014103357Sume
2015103357Sume	va &= PG_FRAME;
201661877Sume#ifdef PMAP_DIAGNOSTIC
201761877Sume	if (va > VM_MAX_KERNEL_ADDRESS)
2018103357Sume		panic("pmap_enter: toobig");
2019103357Sume	if ((va >= UPT_MIN_ADDRESS) && (va < UPT_MAX_ADDRESS))
202065532Snectar		panic("pmap_enter: invalid to pmap_enter page table pages (va: 0x%x)", va);
202161877Sume#endif
2022130600Sume
2023103357Sume	mpte = NULL;
2024103357Sume	/*
202565532Snectar	 * In the case that a page table page is not
2026103357Sume	 * resident, we are creating it here.
2027140896Sume	 */
202861877Sume	if (va < UPT_MIN_ADDRESS) {
2029103357Sume		mpte = pmap_allocpte(pmap, va);
2030140896Sume	}
203161877Sume#if 0 && defined(PMAP_DIAGNOSTIC)
2032140896Sume	else {
2033140896Sume		vm_offset_t *pdeaddr = (vm_offset_t *)pmap_pde(pmap, va);
2034140896Sume		if (((origpte = (vm_offset_t) *pdeaddr) & PG_V) == 0) {
203561877Sume			panic("pmap_enter: invalid kernel page table page(0), pdir=%p, pde=%p, va=%p\n",
2036140896Sume				pmap->pm_pdir[PTDPTDI], origpte, va);
2037140896Sume		}
2038140896Sume		if (smp_active) {
2039103357Sume			pdeaddr = (vm_offset_t *) IdlePTDS[cpuid];
2040103357Sume			if (((newpte = pdeaddr[va >> PDRSHIFT]) & PG_V) == 0) {
204161877Sume				if ((vm_offset_t) my_idlePTD != (vm_offset_t) vtophys(pdeaddr))
204261877Sume					printf("pde mismatch: %x, %x\n", my_idlePTD, pdeaddr);
204361877Sume				printf("cpuid: %d, pdeaddr: 0x%x\n", cpuid, pdeaddr);
204465532Snectar				panic("pmap_enter: invalid kernel page table page(1), pdir=%p, npde=%p, pde=%p, va=%p\n",
204561877Sume					pmap->pm_pdir[PTDPTDI], newpte, origpte, va);
204665532Snectar			}
204761877Sume		}
204865532Snectar	}
204961877Sume#endif
205065532Snectar
205165532Snectar	pte = pmap_pte(pmap, va);
205261877Sume
205361877Sume	/*
205465532Snectar	 * Page Directory table entry not valid, we need a new PT page
205565532Snectar	 */
205665532Snectar	if (pte == NULL) {
205765532Snectar		panic("pmap_enter: invalid page directory, pdir=%p, va=0x%x\n",
205865532Snectar			(void *)pmap->pm_pdir[PTDPTDI], va);
205965532Snectar	}
206065532Snectar
206165532Snectar	origpte = *(vm_offset_t *)pte;
206265532Snectar	pa &= PG_FRAME;
206365532Snectar	opa = origpte & PG_FRAME;
206465532Snectar
206565532Snectar	if (origpte & PG_PS)
206665532Snectar		panic("pmap_enter: attempted pmap_enter on 4MB page");
206765532Snectar
206865532Snectar	/*
206965532Snectar	 * Mapping has not changed, must be protection or wiring change.
207065532Snectar	 */
207165532Snectar	if (origpte && (opa == pa)) {
207261877Sume		/*
207365532Snectar		 * Wiring change, just update stats. We don't worry about
207461877Sume		 * wiring PT pages as they remain resident as long as there
207561877Sume		 * are valid mappings in them. Hence, if a user page is wired,
207661877Sume		 * the PT page will be also.
207761877Sume		 */
207861877Sume		if (wired && ((origpte & PG_W) == 0))
207961877Sume			pmap->pm_stats.wired_count++;
208061877Sume		else if (!wired && (origpte & PG_W))
208161877Sume			pmap->pm_stats.wired_count--;
208261877Sume
208361877Sume#if defined(PMAP_DIAGNOSTIC)
208465532Snectar		if (pmap_nw_modified((pt_entry_t) origpte)) {
208565532Snectar			printf(
2086105940Sume	"pmap_enter: modified page not writable: va: 0x%x, pte: 0x%x\n",
208761877Sume			    va, origpte);
208861877Sume		}
208961877Sume#endif
209061877Sume
2091139612Ssobomax		/*
2092139612Ssobomax		 * Remove extra pte reference
2093139612Ssobomax		 */
209461877Sume		if (mpte)
209561877Sume			mpte->hold_count--;
209661877Sume
209761877Sume		if ((prot & VM_PROT_WRITE) && (origpte & PG_V)) {
209861877Sume			if ((origpte & PG_RW) == 0) {
209961877Sume				*pte |= PG_RW;
210061877Sume#ifdef SMP
210161877Sume				cpu_invlpg((void *)va);
210261877Sume				if (pmap->pm_active & other_cpus)
210361877Sume					smp_invltlb();
210461877Sume#else
210561877Sume				invltlb_1pg(va);
210661877Sume#endif
210761877Sume			}
210861877Sume			return;
210961877Sume		}
211061877Sume
211161877Sume		/*
211261877Sume		 * We might be turning off write access to the page,
211361877Sume		 * so we go ahead and sense modify status.
211461877Sume		 */
211561877Sume		if (origpte & PG_MANAGED) {
2116105940Sume			if ((origpte & PG_M) && pmap_track_modified(va)) {
2117105940Sume				pv_table_t *ppv;
2118105940Sume				ppv = pa_to_pvh(opa);
2119105940Sume				vm_page_dirty(ppv->pv_vm_page);
2120105940Sume			}
212161877Sume			pa |= PG_MANAGED;
2122105940Sume		}
212361877Sume		goto validate;
212461877Sume	}
212561877Sume	/*
212661877Sume	 * Mapping has changed, invalidate old range and fall through to
212761877Sume	 * handle validating new mapping.
212861877Sume	 */
212961877Sume	if (opa) {
213061877Sume		int err;
213161877Sume		err = pmap_remove_pte(pmap, pte, va);
213261877Sume		if (err)
213361877Sume			panic("pmap_enter: pte vanished, va: 0x%x", va);
213461877Sume	}
213561877Sume
2136105940Sume	/*
2137105940Sume	 * Enter on the PV list if part of our managed memory Note that we
213861877Sume	 * raise IPL while manipulating pv_table since pmap_enter can be
213961877Sume	 * called at interrupt time.
214061877Sume	 */
214161877Sume	if (pmap_is_managed(pa)) {
214261877Sume		pmap_insert_entry(pmap, va, mpte, pa);
214361877Sume		pa |= PG_MANAGED;
214461877Sume	}
214561877Sume
214661877Sume	/*
214761877Sume	 * Increment counters
214861877Sume	 */
214961877Sume	pmap->pm_stats.resident_count++;
215061877Sume	if (wired)
215165532Snectar		pmap->pm_stats.wired_count++;
215265532Snectar
215365532Snectarvalidate:
215465532Snectar	/*
215565532Snectar	 * Now validate mapping with desired protection/wiring.
215665532Snectar	 */
215761877Sume	newpte = (vm_offset_t) (pa | pte_prot(pmap, prot) | PG_V);
215861877Sume
215961877Sume	if (wired)
216061877Sume		newpte |= PG_W;
216165532Snectar	if (va < UPT_MIN_ADDRESS)
216265532Snectar		newpte |= PG_U;
216365532Snectar	if (pmap == kernel_pmap)
216465532Snectar		newpte |= pgeflag;
216561877Sume
216661877Sume	/*
2167126243Sgreen	 * if the mapping or permission bits are different, we need
216865532Snectar	 * to update the pte.
216965532Snectar	 */
217061877Sume	if ((origpte & ~(PG_M|PG_A)) != newpte) {
217161877Sume		*pte = newpte | PG_A;
217261877Sume		/*if (origpte)*/ {
217361877Sume#ifdef SMP
217465532Snectar			cpu_invlpg((void *)va);
2175126243Sgreen			if (pmap->pm_active & other_cpus)
217661877Sume				smp_invltlb();
217765532Snectar#else
217865532Snectar			invltlb_1pg(va);
217965532Snectar#endif
218065532Snectar		}
218161877Sume	}
218261877Sume}
218361877Sume
218465532Snectar/*
218565532Snectar * this code makes some *MAJOR* assumptions:
218661877Sume * 1. Current pmap & pmap exists.
218765532Snectar * 2. Not wired.
218865532Snectar * 3. Read access.
218965532Snectar * 4. No page table pages.
219061877Sume * 5. Tlbflush is deferred to calling procedure.
219161877Sume * 6. Page IS managed.
219261877Sume * but is *MUCH* faster than pmap_enter...
219365532Snectar */
219461877Sume
219565532Snectarstatic vm_page_t
219665532Snectarpmap_enter_quick(pmap, va, pa, mpte)
219765532Snectar	register pmap_t pmap;
219865532Snectar	vm_offset_t va;
219961877Sume	register vm_offset_t pa;
220065532Snectar	vm_page_t mpte;
220165532Snectar{
220265532Snectar	register unsigned *pte;
220361877Sume
220461877Sume	/*
220565532Snectar	 * In the case that a page table page is not
220665532Snectar	 * resident, we are creating it here.
220765532Snectar	 */
220865532Snectar	if (va < UPT_MIN_ADDRESS) {
220965532Snectar		unsigned ptepindex;
221065532Snectar		vm_offset_t ptepa;
221165532Snectar
221265532Snectar		/*
221361877Sume		 * Calculate pagetable page index
221465532Snectar		 */
221565532Snectar		ptepindex = va >> PDRSHIFT;
221665532Snectar		if (mpte && (mpte->pindex == ptepindex)) {
221765532Snectar			mpte->hold_count++;
221865532Snectar		} else {
221965532Snectarretry:
222061877Sume			/*
222165532Snectar			 * Get the page directory entry
222261877Sume			 */
222365532Snectar			ptepa = (vm_offset_t) pmap->pm_pdir[ptepindex];
222461877Sume
222565532Snectar			/*
222665532Snectar			 * If the page table page is mapped, we just increment
222765532Snectar			 * the hold count, and activate it.
222861877Sume			 */
222965532Snectar			if (ptepa) {
223065532Snectar				if (ptepa & PG_PS)
223165532Snectar					panic("pmap_enter_quick: unexpected mapping into 4MB page");
223265532Snectar				if (pmap->pm_ptphint &&
223365532Snectar					(pmap->pm_ptphint->pindex == ptepindex)) {
223465532Snectar					mpte = pmap->pm_ptphint;
223561877Sume				} else {
2236121474Sume					mpte = pmap_page_lookup( pmap->pm_pteobj, ptepindex);
223765532Snectar					pmap->pm_ptphint = mpte;
2238121474Sume				}
223965532Snectar				if (mpte == NULL)
224065532Snectar					goto retry;
224165532Snectar				mpte->hold_count++;
224265532Snectar			} else {
224361877Sume				mpte = _pmap_allocpte(pmap, ptepindex);
224465532Snectar			}
224565532Snectar		}
224661877Sume	} else {
224765532Snectar		mpte = NULL;
224865532Snectar	}
224965532Snectar
225065532Snectar	/*
225161877Sume	 * This call to vtopte makes the assumption that we are
225261877Sume	 * entering the page into the current pmap.  In order to support
225361877Sume	 * quick entry into any pmap, one would likely use pmap_pte_quick.
225461877Sume	 * But that isn't as quick as vtopte.
225565532Snectar	 */
225665532Snectar	pte = (unsigned *)vtopte(va);
225765532Snectar	if (*pte) {
225865532Snectar		if (mpte)
225961877Sume			pmap_unwire_pte_hold(pmap, mpte);
226065532Snectar		return 0;
226165532Snectar	}
226261877Sume
226365532Snectar	/*
226465532Snectar	 * Enter on the PV list if part of our managed memory Note that we
226565532Snectar	 * raise IPL while manipulating pv_table since pmap_enter can be
226665532Snectar	 * called at interrupt time.
226765532Snectar	 */
226865532Snectar	pmap_insert_entry(pmap, va, mpte, pa);
226965532Snectar
227065532Snectar	/*
227165532Snectar	 * Increment counters
227265532Snectar	 */
227365532Snectar	pmap->pm_stats.resident_count++;
227465532Snectar
227565532Snectar	/*
227665532Snectar	 * Now validate mapping with RO protection
227765532Snectar	 */
227865532Snectar	*pte = pa | PG_V | PG_U | PG_MANAGED;
227965532Snectar
228065532Snectar	return mpte;
228165532Snectar}
228265532Snectar
228365532Snectar#define MAX_INIT_PT (96)
2284126243Sgreen/*
228565532Snectar * pmap_object_init_pt preloads the ptes for a given object
2286126243Sgreen * into the specified pmap.  This eliminates the blast of soft
2287126243Sgreen * faults on process startup and immediately after an mmap.
228865532Snectar */
2289126243Sgreenvoid
229065532Snectarpmap_object_init_pt(pmap, addr, object, pindex, size, limit)
229165532Snectar	pmap_t pmap;
229265532Snectar	vm_offset_t addr;
229365532Snectar	vm_object_t object;
229465532Snectar	vm_pindex_t pindex;
229565532Snectar	vm_size_t size;
229665532Snectar	int limit;
229765532Snectar{
229865532Snectar	vm_offset_t tmpidx;
229965532Snectar	int psize;
230065532Snectar	vm_page_t p, mpte;
230165532Snectar	int objpgs;
230265532Snectar
230365532Snectar	if (pmap == NULL || object == NULL)
230465532Snectar		return;
230565532Snectar
230665532Snectar	/*
230765532Snectar	 * This code maps large physical mmap regions into the
230865532Snectar	 * processor address space.  Note that some shortcuts
230965532Snectar	 * are taken, but the code works.
231065532Snectar	 */
231165532Snectar	if (pseflag &&
231265532Snectar		(object->type == OBJT_DEVICE) &&
231365532Snectar		((addr & (NBPDR - 1)) == 0) &&
231465532Snectar		((size & (NBPDR - 1)) == 0) ) {
231565532Snectar		int i;
231665532Snectar		vm_page_t m[1];
231765532Snectar		unsigned int ptepindex;
231865532Snectar		int npdes;
231965532Snectar		vm_offset_t ptepa;
232065532Snectar
232165532Snectar		if (pmap->pm_pdir[ptepindex = (addr >> PDRSHIFT)])
232265532Snectar			return;
232365532Snectar
2324126243Sgreenretry:
232565532Snectar		p = vm_page_lookup(object, pindex);
232665532Snectar		if (p && vm_page_sleep_busy(p, FALSE, "init4p"))
232765532Snectar			goto retry;
232865532Snectar
232965532Snectar		if (p == NULL) {
233065532Snectar			p = vm_page_alloc(object, pindex, VM_ALLOC_NORMAL);
233165532Snectar			if (p == NULL)
233265532Snectar				return;
233361877Sume			m[0] = p;
233461877Sume
233561877Sume			if (vm_pager_get_pages(object, m, 1, 0) != VM_PAGER_OK) {
233661877Sume				vm_page_free(p);
233792905Sobrien				return;
233861877Sume			}
233961877Sume
234061877Sume			p = vm_page_lookup(object, pindex);
234161877Sume			vm_page_wakeup(p);
234261877Sume		}
234361877Sume
234461877Sume		ptepa = (vm_offset_t) VM_PAGE_TO_PHYS(p);
234561877Sume		if (ptepa & (NBPDR - 1)) {
234661877Sume			return;
234761877Sume		}
234861877Sume
234961877Sume		p->valid = VM_PAGE_BITS_ALL;
235061877Sume
235161877Sume		pmap->pm_stats.resident_count += size >> PAGE_SHIFT;
235261877Sume		npdes = size >> PDRSHIFT;
235361877Sume		for(i=0;i<npdes;i++) {
2354103357Sume			pmap->pm_pdir[ptepindex] =
235561877Sume				(pd_entry_t) (ptepa | PG_U | PG_RW | PG_V | PG_PS);
235661877Sume			ptepa += NBPDR;
235761877Sume			ptepindex += 1;
235861877Sume		}
235961877Sume		vm_page_flag_set(p, PG_MAPPED);
236061877Sume		invltlb();
236161877Sume		return;
236261877Sume	}
236361877Sume
236461877Sume	psize = i386_btop(size);
236561877Sume
236661877Sume	if ((object->type != OBJT_VNODE) ||
236761877Sume		(limit && (psize > MAX_INIT_PT) &&
236861877Sume			(object->resident_page_count > MAX_INIT_PT))) {
2369103357Sume		return;
2370103357Sume	}
2371103357Sume
2372103357Sume	if (psize + pindex > object->size)
2373103357Sume		psize = object->size - pindex;
2374103357Sume
237561877Sume	mpte = NULL;
237661877Sume	/*
237761877Sume	 * if we are processing a major portion of the object, then scan the
237861877Sume	 * entire thing.
237961877Sume	 */
238061877Sume	if (psize > (object->resident_page_count >> 2)) {
238161877Sume		objpgs = psize;
238261877Sume
238361877Sume		for (p = TAILQ_FIRST(&object->memq);
238462614Sitojun		    ((objpgs > 0) && (p != NULL));
238562614Sitojun		    p = TAILQ_NEXT(p, listq)) {
238661877Sume
238761877Sume			tmpidx = p->pindex;
238861877Sume			if (tmpidx < pindex) {
238961877Sume				continue;
239061877Sume			}
239161877Sume			tmpidx -= pindex;
239261877Sume			if (tmpidx >= psize) {
239361877Sume				continue;
2394103357Sume			}
239578012Sume			if (((p->valid & VM_PAGE_BITS_ALL) == VM_PAGE_BITS_ALL) &&
2396103357Sume				(p->busy == 0) &&
239761877Sume			    (p->flags & (PG_BUSY | PG_FICTITIOUS)) == 0) {
239861877Sume				if ((p->queue - p->pc) == PQ_CACHE)
239961877Sume					vm_page_deactivate(p);
240061877Sume				vm_page_busy(p);
240161877Sume				mpte = pmap_enter_quick(pmap,
2402103357Sume					addr + i386_ptob(tmpidx),
240361877Sume					VM_PAGE_TO_PHYS(p), mpte);
240461877Sume				vm_page_flag_set(p, PG_MAPPED);
240561877Sume				vm_page_wakeup(p);
240661877Sume			}
240761877Sume			objpgs -= 1;
240861877Sume		}
240961877Sume	} else {
241061877Sume		/*
241161877Sume		 * else lookup the pages one-by-one.
241261877Sume		 */
2413103357Sume		for (tmpidx = 0; tmpidx < psize; tmpidx += 1) {
241461877Sume			p = vm_page_lookup(object, tmpidx + pindex);
241561877Sume			if (p &&
241661877Sume			    ((p->valid & VM_PAGE_BITS_ALL) == VM_PAGE_BITS_ALL) &&
241761877Sume				(p->busy == 0) &&
241861877Sume			    (p->flags & (PG_BUSY | PG_FICTITIOUS)) == 0) {
2419103350Snectar				if ((p->queue - p->pc) == PQ_CACHE)
2420103350Snectar					vm_page_deactivate(p);
2421103350Snectar				vm_page_busy(p);
242261877Sume				mpte = pmap_enter_quick(pmap,
242361877Sume					addr + i386_ptob(tmpidx),
242461877Sume					VM_PAGE_TO_PHYS(p), mpte);
2425105940Sume				vm_page_flag_set(p, PG_MAPPED);
242661877Sume				vm_page_wakeup(p);
242761877Sume			}
242861877Sume		}
242961877Sume	}
243061877Sume	return;
243161877Sume}
243261877Sume
243361877Sume/*
243461877Sume * pmap_prefault provides a quick way of clustering
243561877Sume * pagefaults into a processes address space.  It is a "cousin"
2436103357Sume * of pmap_object_init_pt, except it runs at page fault time instead
2437103357Sume * of mmap time.
243861877Sume */
243961877Sume#define PFBAK 4
244061877Sume#define PFFOR 4
244161877Sume#define PAGEORDER_SIZE (PFBAK+PFFOR)
244261877Sume
244361877Sumestatic int pmap_prefault_pageorder[] = {
244461877Sume	-PAGE_SIZE, PAGE_SIZE,
244561877Sume	-2 * PAGE_SIZE, 2 * PAGE_SIZE,
244661877Sume	-3 * PAGE_SIZE, 3 * PAGE_SIZE
244761877Sume	-4 * PAGE_SIZE, 4 * PAGE_SIZE
244861877Sume};
244961877Sume
245061877Sumevoid
245161877Sumepmap_prefault(pmap, addra, entry)
245261877Sume	pmap_t pmap;
245361877Sume	vm_offset_t addra;
245461877Sume	vm_map_entry_t entry;
245561877Sume{
245661877Sume	int i;
245761877Sume	vm_offset_t starta;
245861877Sume	vm_offset_t addr;
245961877Sume	vm_pindex_t pindex;
246061877Sume	vm_page_t m, mpte;
246161877Sume	vm_object_t object;
246261877Sume
246361877Sume	if (!curproc || (pmap != vmspace_pmap(curproc->p_vmspace)))
246461877Sume		return;
246561877Sume
246661877Sume	object = entry->object.vm_object;
246761877Sume
246861877Sume	starta = addra - PFBAK * PAGE_SIZE;
246961877Sume	if (starta < entry->start) {
247061877Sume		starta = entry->start;
247161877Sume	} else if (starta > addra) {
247261877Sume		starta = 0;
247361877Sume	}
247461877Sume
247561877Sume	mpte = NULL;
247661877Sume	for (i = 0; i < PAGEORDER_SIZE; i++) {
247761877Sume		vm_object_t lobject;
247861877Sume		unsigned *pte;
247961877Sume
248061877Sume		addr = addra + pmap_prefault_pageorder[i];
248161877Sume		if (addr > addra + (PFFOR * PAGE_SIZE))
248261877Sume			addr = 0;
248361877Sume
248461877Sume		if (addr < starta || addr >= entry->end)
248561877Sume			continue;
248661877Sume
248761877Sume		if ((*pmap_pde(pmap, addr)) == NULL)
248861877Sume			continue;
248961877Sume
249061877Sume		pte = (unsigned *) vtopte(addr);
249161877Sume		if (*pte)
249261877Sume			continue;
249361877Sume
249461877Sume		pindex = ((addr - entry->start) + entry->offset) >> PAGE_SHIFT;
249561877Sume		lobject = object;
249661877Sume		for (m = vm_page_lookup(lobject, pindex);
249761877Sume		    (!m && (lobject->type == OBJT_DEFAULT) && (lobject->backing_object));
249861877Sume		    lobject = lobject->backing_object) {
249961877Sume			if (lobject->backing_object_offset & PAGE_MASK)
250061877Sume				break;
250161877Sume			pindex += (lobject->backing_object_offset >> PAGE_SHIFT);
250261877Sume			m = vm_page_lookup(lobject->backing_object, pindex);
250361877Sume		}
250461877Sume
250561877Sume		/*
250661877Sume		 * give-up when a page is not in memory
250761877Sume		 */
250861877Sume		if (m == NULL)
250961877Sume			break;
251061877Sume
251161877Sume		if (((m->valid & VM_PAGE_BITS_ALL) == VM_PAGE_BITS_ALL) &&
251261877Sume			(m->busy == 0) &&
251361877Sume		    (m->flags & (PG_BUSY | PG_FICTITIOUS)) == 0) {
251461877Sume
251561877Sume			if ((m->queue - m->pc) == PQ_CACHE) {
251661877Sume				vm_page_deactivate(m);
251761877Sume			}
251861877Sume			vm_page_busy(m);
251961877Sume			mpte = pmap_enter_quick(pmap, addr,
252061877Sume				VM_PAGE_TO_PHYS(m), mpte);
252161877Sume			vm_page_flag_set(m, PG_MAPPED);
252261877Sume			vm_page_wakeup(m);
252361877Sume		}
252461877Sume	}
252561877Sume}
252661877Sume
252761877Sume/*
252861877Sume *	Routine:	pmap_change_wiring
252961877Sume *	Function:	Change the wiring attribute for a map/virtual-address
253061877Sume *			pair.
253161877Sume *	In/out conditions:
253261877Sume *			The mapping must already exist in the pmap.
253361877Sume */
253461877Sumevoid
253561877Sumepmap_change_wiring(pmap, va, wired)
253661877Sume	register pmap_t pmap;
253761877Sume	vm_offset_t va;
253861877Sume	boolean_t wired;
253961877Sume{
254061877Sume	register unsigned *pte;
254161877Sume
254261877Sume	if (pmap == NULL)
254361877Sume		return;
254461877Sume
254561877Sume	pte = pmap_pte(pmap, va);
254661877Sume
254761877Sume	if (wired && !pmap_pte_w(pte))
254861877Sume		pmap->pm_stats.wired_count++;
254961877Sume	else if (!wired && pmap_pte_w(pte))
255061877Sume		pmap->pm_stats.wired_count--;
255161877Sume
255261877Sume	/*
255361877Sume	 * Wiring is not a hardware characteristic so there is no need to
255461877Sume	 * invalidate TLB.
255561877Sume	 */
255661877Sume	pmap_pte_set_w(pte, wired);
255761877Sume}
255861877Sume
255961877Sume
256061877Sume
256161877Sume/*
256261877Sume *	Copy the range specified by src_addr/len
256361877Sume *	from the source map to the range dst_addr/len
256461877Sume *	in the destination map.
256561877Sume *
256661877Sume *	This routine is only advisory and need not do anything.
256761877Sume */
256861877Sume
256961877Sumevoid
257061877Sumepmap_copy(dst_pmap, src_pmap, dst_addr, len, src_addr)
257161877Sume	pmap_t dst_pmap, src_pmap;
257261877Sume	vm_offset_t dst_addr;
257361877Sume	vm_size_t len;
257461877Sume	vm_offset_t src_addr;
257561877Sume{
257661877Sume	vm_offset_t addr;
257761877Sume	vm_offset_t end_addr = src_addr + len;
257861877Sume	vm_offset_t pdnxt;
257961877Sume	unsigned src_frame, dst_frame;
258061877Sume
258161877Sume	if (dst_addr != src_addr)
258261877Sume		return;
258361877Sume
258461877Sume	src_frame = ((unsigned) src_pmap->pm_pdir[PTDPTDI]) & PG_FRAME;
258561877Sume	if (src_frame != (((unsigned) PTDpde) & PG_FRAME)) {
258661877Sume		return;
258761877Sume	}
258861877Sume
258961877Sume	dst_frame = ((unsigned) dst_pmap->pm_pdir[PTDPTDI]) & PG_FRAME;
259061877Sume	if (dst_frame != (((unsigned) APTDpde) & PG_FRAME)) {
259161877Sume		APTDpde = (pd_entry_t) (dst_frame | PG_RW | PG_V);
259261877Sume#if defined(SMP)
259361877Sume		/* The page directory is not shared between CPUs */
259461877Sume		cpu_invltlb();
259561877Sume#else
259661877Sume		invltlb();
259761877Sume#endif
259861877Sume	}
259961877Sume
260061877Sume	for(addr = src_addr; addr < end_addr; addr = pdnxt) {
260161877Sume		unsigned *src_pte, *dst_pte;
260261877Sume		vm_page_t dstmpte, srcmpte;
260361877Sume		vm_offset_t srcptepaddr;
260461877Sume		unsigned ptepindex;
260561877Sume
260661877Sume		if (addr >= UPT_MIN_ADDRESS)
260761877Sume			panic("pmap_copy: invalid to pmap_copy page tables\n");
260861877Sume
260961877Sume		/*
261061877Sume		 * Don't let optional prefaulting of pages make us go
261161877Sume		 * way below the low water mark of free pages or way
261261877Sume		 * above high water mark of used pv entries.
261361877Sume		 */
261461877Sume		if (cnt.v_free_count < cnt.v_free_reserved ||
261561877Sume		    pv_entry_count > pv_entry_high_water)
261661877Sume			break;
261761877Sume
261861877Sume		pdnxt = ((addr + PAGE_SIZE*NPTEPG) & ~(PAGE_SIZE*NPTEPG - 1));
261961877Sume		ptepindex = addr >> PDRSHIFT;
262061877Sume
262161877Sume		srcptepaddr = (vm_offset_t) src_pmap->pm_pdir[ptepindex];
262261877Sume		if (srcptepaddr == 0)
262361877Sume			continue;
262461877Sume
262561877Sume		if (srcptepaddr & PG_PS) {
262661877Sume			if (dst_pmap->pm_pdir[ptepindex] == 0) {
262761877Sume				dst_pmap->pm_pdir[ptepindex] = (pd_entry_t) srcptepaddr;
262861877Sume				dst_pmap->pm_stats.resident_count += NBPDR / PAGE_SIZE;
262961877Sume			}
263061877Sume			continue;
263161877Sume		}
263261877Sume
263361877Sume		srcmpte = vm_page_lookup(src_pmap->pm_pteobj, ptepindex);
263461877Sume		if ((srcmpte == NULL) ||
263561877Sume			(srcmpte->hold_count == 0) || (srcmpte->flags & PG_BUSY))
263661877Sume			continue;
263761877Sume
263861877Sume		if (pdnxt > end_addr)
263961877Sume			pdnxt = end_addr;
264061877Sume
264161877Sume		src_pte = (unsigned *) vtopte(addr);
264261877Sume		dst_pte = (unsigned *) avtopte(addr);
264361877Sume		while (addr < pdnxt) {
264461877Sume			unsigned ptetemp;
264561877Sume			ptetemp = *src_pte;
2646105940Sume			/*
264761877Sume			 * we only virtual copy managed pages
264861877Sume			 */
264961877Sume			if ((ptetemp & PG_MANAGED) != 0) {
2650				/*
2651				 * We have to check after allocpte for the
2652				 * pte still being around...  allocpte can
2653				 * block.
2654				 */
2655				dstmpte = pmap_allocpte(dst_pmap, addr);
2656				if ((*dst_pte == 0) && (ptetemp = *src_pte)) {
2657					/*
2658					 * Clear the modified and
2659					 * accessed (referenced) bits
2660					 * during the copy.
2661					 */
2662					*dst_pte = ptetemp & ~(PG_M | PG_A);
2663					dst_pmap->pm_stats.resident_count++;
2664					pmap_insert_entry(dst_pmap, addr,
2665						dstmpte,
2666						(ptetemp & PG_FRAME));
2667	 			} else {
2668					pmap_unwire_pte_hold(dst_pmap, dstmpte);
2669				}
2670				if (dstmpte->hold_count >= srcmpte->hold_count)
2671					break;
2672			}
2673			addr += PAGE_SIZE;
2674			src_pte++;
2675			dst_pte++;
2676		}
2677	}
2678}
2679
2680/*
2681 *	Routine:	pmap_kernel
2682 *	Function:
2683 *		Returns the physical map handle for the kernel.
2684 */
2685pmap_t
2686pmap_kernel()
2687{
2688	return (kernel_pmap);
2689}
2690
2691/*
2692 *	pmap_zero_page zeros the specified hardware page by mapping
2693 *	the page into KVM and using bzero to clear its contents.
2694 */
2695void
2696pmap_zero_page(phys)
2697	vm_offset_t phys;
2698{
2699#ifdef SMP
2700	if (*(int *) prv_CMAP3)
2701		panic("pmap_zero_page: prv_CMAP3 busy");
2702
2703	*(int *) prv_CMAP3 = PG_V | PG_RW | (phys & PG_FRAME) | PG_A | PG_M;
2704	cpu_invlpg(prv_CADDR3);
2705
2706#if defined(I686_CPU)
2707	if (cpu_class == CPUCLASS_686)
2708		i686_pagezero(prv_CADDR3);
2709	else
2710#endif
2711		bzero(prv_CADDR3, PAGE_SIZE);
2712
2713	*(int *) prv_CMAP3 = 0;
2714#else
2715	if (*(int *) CMAP2)
2716		panic("pmap_zero_page: CMAP2 busy");
2717
2718	*(int *) CMAP2 = PG_V | PG_RW | (phys & PG_FRAME) | PG_A | PG_M;
2719	invltlb_1pg((vm_offset_t)CADDR2);
2720
2721#if defined(I686_CPU)
2722	if (cpu_class == CPUCLASS_686)
2723		i686_pagezero(CADDR2);
2724	else
2725#endif
2726		bzero(CADDR2, PAGE_SIZE);
2727	*(int *) CMAP2 = 0;
2728#endif
2729}
2730
2731/*
2732 *	pmap_zero_page_area zeros the specified hardware page by mapping
2733 *	the page into KVM and using bzero to clear its contents.
2734 *
2735 *	off and size may not cover an area beyond a single hardware page.
2736 */
2737void
2738pmap_zero_page_area(phys, off, size)
2739	vm_offset_t phys;
2740	int off;
2741	int size;
2742{
2743#ifdef SMP
2744	if (*(int *) prv_CMAP3)
2745		panic("pmap_zero_page: prv_CMAP3 busy");
2746
2747	*(int *) prv_CMAP3 = PG_V | PG_RW | (phys & PG_FRAME) | PG_A | PG_M;
2748	cpu_invlpg(prv_CADDR3);
2749
2750#if defined(I686_CPU)
2751	if (cpu_class == CPUCLASS_686 && off == 0 && size == PAGE_SIZE)
2752		i686_pagezero(prv_CADDR3);
2753	else
2754#endif
2755		bzero((char *)prv_CADDR3 + off, size);
2756
2757	*(int *) prv_CMAP3 = 0;
2758#else
2759	if (*(int *) CMAP2)
2760		panic("pmap_zero_page: CMAP2 busy");
2761
2762	*(int *) CMAP2 = PG_V | PG_RW | (phys & PG_FRAME) | PG_A | PG_M;
2763	invltlb_1pg((vm_offset_t)CADDR2);
2764
2765#if defined(I686_CPU)
2766	if (cpu_class == CPUCLASS_686 && off == 0 && size == PAGE_SIZE)
2767		i686_pagezero(CADDR2);
2768	else
2769#endif
2770		bzero((char *)CADDR2 + off, size);
2771	*(int *) CMAP2 = 0;
2772#endif
2773}
2774
2775/*
2776 *	pmap_copy_page copies the specified (machine independent)
2777 *	page by mapping the page into virtual memory and using
2778 *	bcopy to copy the page, one machine dependent page at a
2779 *	time.
2780 */
2781void
2782pmap_copy_page(src, dst)
2783	vm_offset_t src;
2784	vm_offset_t dst;
2785{
2786#ifdef SMP
2787	if (*(int *) prv_CMAP1)
2788		panic("pmap_copy_page: prv_CMAP1 busy");
2789	if (*(int *) prv_CMAP2)
2790		panic("pmap_copy_page: prv_CMAP2 busy");
2791
2792	*(int *) prv_CMAP1 = PG_V | (src & PG_FRAME) | PG_A;
2793	*(int *) prv_CMAP2 = PG_V | PG_RW | (dst & PG_FRAME) | PG_A | PG_M;
2794
2795	cpu_invlpg(prv_CADDR1);
2796	cpu_invlpg(prv_CADDR2);
2797
2798	bcopy(prv_CADDR1, prv_CADDR2, PAGE_SIZE);
2799
2800	*(int *) prv_CMAP1 = 0;
2801	*(int *) prv_CMAP2 = 0;
2802#else
2803	if (*(int *) CMAP1 || *(int *) CMAP2)
2804		panic("pmap_copy_page: CMAP busy");
2805
2806	*(int *) CMAP1 = PG_V | (src & PG_FRAME) | PG_A;
2807	*(int *) CMAP2 = PG_V | PG_RW | (dst & PG_FRAME) | PG_A | PG_M;
2808#if defined(I386_CPU)
2809	if (cpu_class == CPUCLASS_386) {
2810		invltlb();
2811	} else
2812#endif
2813	{
2814		invlpg((u_int)CADDR1);
2815		invlpg((u_int)CADDR2);
2816	}
2817
2818	bcopy(CADDR1, CADDR2, PAGE_SIZE);
2819
2820	*(int *) CMAP1 = 0;
2821	*(int *) CMAP2 = 0;
2822#endif
2823}
2824
2825
2826/*
2827 *	Routine:	pmap_pageable
2828 *	Function:
2829 *		Make the specified pages (by pmap, offset)
2830 *		pageable (or not) as requested.
2831 *
2832 *		A page which is not pageable may not take
2833 *		a fault; therefore, its page table entry
2834 *		must remain valid for the duration.
2835 *
2836 *		This routine is merely advisory; pmap_enter
2837 *		will specify that these pages are to be wired
2838 *		down (or not) as appropriate.
2839 */
2840void
2841pmap_pageable(pmap, sva, eva, pageable)
2842	pmap_t pmap;
2843	vm_offset_t sva, eva;
2844	boolean_t pageable;
2845{
2846}
2847
2848/*
2849 * this routine returns true if a physical page resides
2850 * in the given pmap.
2851 */
2852boolean_t
2853pmap_page_exists(pmap, pa)
2854	pmap_t pmap;
2855	vm_offset_t pa;
2856{
2857	register pv_entry_t pv;
2858	pv_table_t *ppv;
2859	int s;
2860
2861	if (!pmap_is_managed(pa))
2862		return FALSE;
2863
2864	s = splvm();
2865
2866	ppv = pa_to_pvh(pa);
2867	/*
2868	 * Not found, check current mappings returning immediately if found.
2869	 */
2870	for (pv = TAILQ_FIRST(&ppv->pv_list);
2871		pv;
2872		pv = TAILQ_NEXT(pv, pv_list)) {
2873		if (pv->pv_pmap == pmap) {
2874			splx(s);
2875			return TRUE;
2876		}
2877	}
2878	splx(s);
2879	return (FALSE);
2880}
2881
2882#define PMAP_REMOVE_PAGES_CURPROC_ONLY
2883/*
2884 * Remove all pages from specified address space
2885 * this aids process exit speeds.  Also, this code
2886 * is special cased for current process only, but
2887 * can have the more generic (and slightly slower)
2888 * mode enabled.  This is much faster than pmap_remove
2889 * in the case of running down an entire address space.
2890 */
2891void
2892pmap_remove_pages(pmap, sva, eva)
2893	pmap_t pmap;
2894	vm_offset_t sva, eva;
2895{
2896	unsigned *pte, tpte;
2897	pv_table_t *ppv;
2898	pv_entry_t pv, npv;
2899	int s;
2900
2901#ifdef PMAP_REMOVE_PAGES_CURPROC_ONLY
2902	if (!curproc || (pmap != vmspace_pmap(curproc->p_vmspace))) {
2903		printf("warning: pmap_remove_pages called with non-current pmap\n");
2904		return;
2905	}
2906#endif
2907
2908	s = splvm();
2909	for(pv = TAILQ_FIRST(&pmap->pm_pvlist);
2910		pv;
2911		pv = npv) {
2912
2913		if (pv->pv_va >= eva || pv->pv_va < sva) {
2914			npv = TAILQ_NEXT(pv, pv_plist);
2915			continue;
2916		}
2917
2918#ifdef PMAP_REMOVE_PAGES_CURPROC_ONLY
2919		pte = (unsigned *)vtopte(pv->pv_va);
2920#else
2921		pte = pmap_pte_quick(pv->pv_pmap, pv->pv_va);
2922#endif
2923		tpte = *pte;
2924
2925/*
2926 * We cannot remove wired pages from a process' mapping at this time
2927 */
2928		if (tpte & PG_W) {
2929			npv = TAILQ_NEXT(pv, pv_plist);
2930			continue;
2931		}
2932		*pte = 0;
2933
2934		ppv = pa_to_pvh(tpte);
2935
2936		KASSERT(ppv < &pv_table[pv_npg],
2937			("pmap_remove_pages: bad tpte %x", tpte));
2938
2939		pv->pv_pmap->pm_stats.resident_count--;
2940
2941		/*
2942		 * Update the vm_page_t clean and reference bits.
2943		 */
2944		if (tpte & PG_M) {
2945			vm_page_dirty(ppv->pv_vm_page);
2946		}
2947
2948
2949		npv = TAILQ_NEXT(pv, pv_plist);
2950		TAILQ_REMOVE(&pv->pv_pmap->pm_pvlist, pv, pv_plist);
2951
2952		ppv->pv_list_count--;
2953		TAILQ_REMOVE(&ppv->pv_list, pv, pv_list);
2954		if (TAILQ_FIRST(&ppv->pv_list) == NULL) {
2955			vm_page_flag_clear(ppv->pv_vm_page, PG_MAPPED | PG_WRITEABLE);
2956		}
2957
2958		pmap_unuse_pt(pv->pv_pmap, pv->pv_va, pv->pv_ptem);
2959		free_pv_entry(pv);
2960	}
2961	splx(s);
2962	pmap_TLB_invalidate_all(pmap);
2963}
2964
2965/*
2966 * pmap_testbit tests bits in pte's
2967 * note that the testbit/changebit routines are inline,
2968 * and a lot of things compile-time evaluate.
2969 */
2970static boolean_t
2971pmap_testbit(pa, bit)
2972	register vm_offset_t pa;
2973	int bit;
2974{
2975	register pv_entry_t pv;
2976	pv_table_t *ppv;
2977	unsigned *pte;
2978	int s;
2979
2980	if (!pmap_is_managed(pa))
2981		return FALSE;
2982
2983	ppv = pa_to_pvh(pa);
2984	if (TAILQ_FIRST(&ppv->pv_list) == NULL)
2985		return FALSE;
2986
2987	s = splvm();
2988
2989	for (pv = TAILQ_FIRST(&ppv->pv_list);
2990		pv;
2991		pv = TAILQ_NEXT(pv, pv_list)) {
2992
2993		/*
2994		 * if the bit being tested is the modified bit, then
2995		 * mark clean_map and ptes as never
2996		 * modified.
2997		 */
2998		if (bit & (PG_A|PG_M)) {
2999			if (!pmap_track_modified(pv->pv_va))
3000				continue;
3001		}
3002
3003#if defined(PMAP_DIAGNOSTIC)
3004		if (!pv->pv_pmap) {
3005			printf("Null pmap (tb) at va: 0x%x\n", pv->pv_va);
3006			continue;
3007		}
3008#endif
3009		pte = pmap_pte_quick(pv->pv_pmap, pv->pv_va);
3010		if (*pte & bit) {
3011			splx(s);
3012			return TRUE;
3013		}
3014	}
3015	splx(s);
3016	return (FALSE);
3017}
3018
3019/*
3020 * this routine is used to modify bits in ptes
3021 */
3022static __inline void
3023pmap_changebit(pa, bit, setem)
3024	vm_offset_t pa;
3025	int bit;
3026	boolean_t setem;
3027{
3028	register pv_entry_t pv;
3029	pv_table_t *ppv;
3030	register unsigned *pte;
3031	int s;
3032
3033	if (!pmap_is_managed(pa))
3034		return;
3035
3036	s = splvm();
3037	ppv = pa_to_pvh(pa);
3038
3039	/*
3040	 * Loop over all current mappings setting/clearing as appropos If
3041	 * setting RO do we need to clear the VAC?
3042	 */
3043	for (pv = TAILQ_FIRST(&ppv->pv_list);
3044		pv;
3045		pv = TAILQ_NEXT(pv, pv_list)) {
3046
3047		/*
3048		 * don't write protect pager mappings
3049		 */
3050		if (!setem && (bit == PG_RW)) {
3051			if (!pmap_track_modified(pv->pv_va))
3052				continue;
3053		}
3054
3055#if defined(PMAP_DIAGNOSTIC)
3056		if (!pv->pv_pmap) {
3057			printf("Null pmap (cb) at va: 0x%x\n", pv->pv_va);
3058			continue;
3059		}
3060#endif
3061
3062		pte = pmap_pte_quick(pv->pv_pmap, pv->pv_va);
3063
3064		if (setem) {
3065			*(int *)pte |= bit;
3066			pmap_TLB_invalidate(pv->pv_pmap, pv->pv_va);
3067		} else {
3068			vm_offset_t pbits = *(vm_offset_t *)pte;
3069			if (pbits & bit) {
3070				if (bit == PG_RW) {
3071					if (pbits & PG_M) {
3072						vm_page_dirty(ppv->pv_vm_page);
3073					}
3074					*(int *)pte = pbits & ~(PG_M|PG_RW);
3075				} else {
3076					*(int *)pte = pbits & ~bit;
3077				}
3078				pmap_TLB_invalidate(pv->pv_pmap, pv->pv_va);
3079			}
3080		}
3081	}
3082	splx(s);
3083}
3084
3085/*
3086 *	pmap_clearbit:
3087 *
3088 *	Clear a bit/bits in every pte mapping a given physical page.  Making
3089 *	this inline allows the pmap_changebit inline to be well optimized.
3090 */
3091static __inline void
3092pmap_clearbit(
3093	vm_offset_t pa,
3094	int	bit)
3095{
3096	pmap_changebit(pa, bit, FALSE);
3097}
3098
3099/*
3100 *      pmap_page_protect:
3101 *
3102 *      Lower the permission for all mappings to a given page.
3103 */
3104void
3105pmap_page_protect(vm_offset_t phys, vm_prot_t prot)
3106{
3107	if ((prot & VM_PROT_WRITE) == 0) {
3108		if (prot & (VM_PROT_READ | VM_PROT_EXECUTE)) {
3109			pmap_clearbit(phys, PG_RW);
3110		} else {
3111			pmap_remove_all(phys);
3112		}
3113	}
3114}
3115
3116vm_offset_t
3117pmap_phys_address(ppn)
3118	int ppn;
3119{
3120	return (i386_ptob(ppn));
3121}
3122
3123/*
3124 *	pmap_ts_referenced:
3125 *
3126 *	Return the count of reference bits for a page, clearing all of them.
3127 */
3128int
3129pmap_ts_referenced(vm_offset_t pa)
3130{
3131	register pv_entry_t pv, pvf, pvn;
3132	pv_table_t *ppv;
3133	unsigned *pte;
3134	int s;
3135	int rtval = 0;
3136
3137	if (!pmap_is_managed(pa))
3138		return (rtval);
3139
3140	s = splvm();
3141
3142	ppv = pa_to_pvh(pa);
3143
3144	if ((pv = TAILQ_FIRST(&ppv->pv_list)) != NULL) {
3145
3146		pvf = pv;
3147
3148		do {
3149			pvn = TAILQ_NEXT(pv, pv_list);
3150
3151			TAILQ_REMOVE(&ppv->pv_list, pv, pv_list);
3152
3153			TAILQ_INSERT_TAIL(&ppv->pv_list, pv, pv_list);
3154
3155			if (!pmap_track_modified(pv->pv_va))
3156				continue;
3157
3158			pte = pmap_pte_quick(pv->pv_pmap, pv->pv_va);
3159
3160			if (pte && (*pte & PG_A)) {
3161				*pte &= ~PG_A;
3162
3163				pmap_TLB_invalidate(pv->pv_pmap, pv->pv_va);
3164
3165				rtval++;
3166				if (rtval > 4) {
3167					break;
3168				}
3169			}
3170		} while ((pv = pvn) != NULL && pv != pvf);
3171	}
3172	splx(s);
3173
3174	return (rtval);
3175}
3176
3177/*
3178 *	pmap_is_modified:
3179 *
3180 *	Return whether or not the specified physical page was modified
3181 *	in any physical maps.
3182 */
3183boolean_t
3184pmap_is_modified(vm_offset_t pa)
3185{
3186	return pmap_testbit((pa), PG_M);
3187}
3188
3189/*
3190 *	Clear the modify bits on the specified physical page.
3191 */
3192void
3193pmap_clear_modify(vm_offset_t pa)
3194{
3195	pmap_clearbit(pa, PG_M);
3196}
3197
3198/*
3199 *	pmap_clear_reference:
3200 *
3201 *	Clear the reference bit on the specified physical page.
3202 */
3203void
3204pmap_clear_reference(vm_offset_t pa)
3205{
3206	pmap_clearbit(pa, PG_A);
3207}
3208
3209/*
3210 * Miscellaneous support routines follow
3211 */
3212
3213static void
3214i386_protection_init()
3215{
3216	register int *kp, prot;
3217
3218	kp = protection_codes;
3219	for (prot = 0; prot < 8; prot++) {
3220		switch (prot) {
3221		case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_NONE:
3222			/*
3223			 * Read access is also 0. There isn't any execute bit,
3224			 * so just make it readable.
3225			 */
3226		case VM_PROT_READ | VM_PROT_NONE | VM_PROT_NONE:
3227		case VM_PROT_READ | VM_PROT_NONE | VM_PROT_EXECUTE:
3228		case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_EXECUTE:
3229			*kp++ = 0;
3230			break;
3231		case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_NONE:
3232		case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_EXECUTE:
3233		case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_NONE:
3234		case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE:
3235			*kp++ = PG_RW;
3236			break;
3237		}
3238	}
3239}
3240
3241/*
3242 * Map a set of physical memory pages into the kernel virtual
3243 * address space. Return a pointer to where it is mapped. This
3244 * routine is intended to be used for mapping device memory,
3245 * NOT real memory.
3246 */
3247void *
3248pmap_mapdev(pa, size)
3249	vm_offset_t pa;
3250	vm_size_t size;
3251{
3252	vm_offset_t va, tmpva, offset;
3253	unsigned *pte;
3254
3255	offset = pa & PAGE_MASK;
3256	size = roundup(offset + size, PAGE_SIZE);
3257
3258	va = kmem_alloc_pageable(kernel_map, size);
3259	if (!va)
3260		panic("pmap_mapdev: Couldn't alloc kernel virtual memory");
3261
3262	pa = pa & PG_FRAME;
3263	for (tmpva = va; size > 0;) {
3264		pte = (unsigned *)vtopte(tmpva);
3265		*pte = pa | PG_RW | PG_V | pgeflag;
3266		size -= PAGE_SIZE;
3267		tmpva += PAGE_SIZE;
3268		pa += PAGE_SIZE;
3269	}
3270	invltlb();
3271
3272	return ((void *)(va + offset));
3273}
3274
3275void
3276pmap_unmapdev(va, size)
3277	vm_offset_t va;
3278	vm_size_t size;
3279{
3280	vm_offset_t base, offset;
3281
3282	base = va & PG_FRAME;
3283	offset = va & PAGE_MASK;
3284	size = roundup(offset + size, PAGE_SIZE);
3285	kmem_free(kernel_map, base, size);
3286}
3287
3288/*
3289 * perform the pmap work for mincore
3290 */
3291int
3292pmap_mincore(pmap, addr)
3293	pmap_t pmap;
3294	vm_offset_t addr;
3295{
3296
3297	unsigned *ptep, pte;
3298	vm_page_t m;
3299	int val = 0;
3300
3301	ptep = pmap_pte(pmap, addr);
3302	if (ptep == 0) {
3303		return 0;
3304	}
3305
3306	if ((pte = *ptep) != 0) {
3307		pv_table_t *ppv;
3308		vm_offset_t pa;
3309
3310		val = MINCORE_INCORE;
3311		if ((pte & PG_MANAGED) == 0)
3312			return val;
3313
3314		pa = pte & PG_FRAME;
3315
3316		ppv = pa_to_pvh((pa & PG_FRAME));
3317		m = ppv->pv_vm_page;
3318
3319		/*
3320		 * Modified by us
3321		 */
3322		if (pte & PG_M)
3323			val |= MINCORE_MODIFIED|MINCORE_MODIFIED_OTHER;
3324		/*
3325		 * Modified by someone
3326		 */
3327		else if (m->dirty || pmap_is_modified(pa))
3328			val |= MINCORE_MODIFIED_OTHER;
3329		/*
3330		 * Referenced by us
3331		 */
3332		if (pte & PG_A)
3333			val |= MINCORE_REFERENCED|MINCORE_REFERENCED_OTHER;
3334
3335		/*
3336		 * Referenced by someone
3337		 */
3338		else if ((m->flags & PG_REFERENCED) || pmap_ts_referenced(pa)) {
3339			val |= MINCORE_REFERENCED_OTHER;
3340			vm_page_flag_set(m, PG_REFERENCED);
3341		}
3342	}
3343	return val;
3344}
3345
3346void
3347pmap_activate(struct proc *p)
3348{
3349	pmap_t	pmap;
3350
3351	pmap = vmspace_pmap(p->p_vmspace);
3352#if defined(SMP)
3353	pmap->pm_active |= 1 << cpuid;
3354#else
3355	pmap->pm_active |= 1;
3356#endif
3357#if defined(SWTCH_OPTIM_STATS)
3358	tlb_flush_count++;
3359#endif
3360	load_cr3(p->p_addr->u_pcb.pcb_cr3 = vtophys(pmap->pm_pdir));
3361}
3362
3363vm_offset_t
3364pmap_addr_hint(vm_object_t obj, vm_offset_t addr, vm_size_t size) {
3365
3366	if ((obj == NULL) || (size < NBPDR) || (obj->type != OBJT_DEVICE)) {
3367		return addr;
3368	}
3369
3370	addr = (addr + (NBPDR - 1)) & ~(NBPDR - 1);
3371	return addr;
3372}
3373
3374
3375#if defined(PMAP_DEBUG)
3376pmap_pid_dump(int pid) {
3377	pmap_t pmap;
3378	struct proc *p;
3379	int npte = 0;
3380	int index;
3381	LIST_FOREACH(p, &allproc, p_list) {
3382		if (p->p_pid != pid)
3383			continue;
3384
3385		if (p->p_vmspace) {
3386			int i,j;
3387			index = 0;
3388			pmap = vmspace_pmap(p->p_vmspace);
3389			for(i=0;i<1024;i++) {
3390				pd_entry_t *pde;
3391				unsigned *pte;
3392				unsigned base = i << PDRSHIFT;
3393
3394				pde = &pmap->pm_pdir[i];
3395				if (pde && pmap_pde_v(pde)) {
3396					for(j=0;j<1024;j++) {
3397						unsigned va = base + (j << PAGE_SHIFT);
3398						if (va >= (vm_offset_t) VM_MIN_KERNEL_ADDRESS) {
3399							if (index) {
3400								index = 0;
3401								printf("\n");
3402							}
3403							return npte;
3404						}
3405						pte = pmap_pte_quick( pmap, va);
3406						if (pte && pmap_pte_v(pte)) {
3407							vm_offset_t pa;
3408							vm_page_t m;
3409							pa = *(int *)pte;
3410							m = PHYS_TO_VM_PAGE((pa & PG_FRAME));
3411							printf("va: 0x%x, pt: 0x%x, h: %d, w: %d, f: 0x%x",
3412								va, pa, m->hold_count, m->wire_count, m->flags);
3413							npte++;
3414							index++;
3415							if (index >= 2) {
3416								index = 0;
3417								printf("\n");
3418							} else {
3419								printf(" ");
3420							}
3421						}
3422					}
3423				}
3424			}
3425		}
3426	}
3427	return npte;
3428}
3429#endif
3430
3431#if defined(DEBUG)
3432
3433static void	pads __P((pmap_t pm));
3434void		pmap_pvdump __P((vm_offset_t pa));
3435
3436/* print address space of pmap*/
3437static void
3438pads(pm)
3439	pmap_t pm;
3440{
3441	unsigned va, i, j;
3442	unsigned *ptep;
3443
3444	if (pm == kernel_pmap)
3445		return;
3446	for (i = 0; i < 1024; i++)
3447		if (pm->pm_pdir[i])
3448			for (j = 0; j < 1024; j++) {
3449				va = (i << PDRSHIFT) + (j << PAGE_SHIFT);
3450				if (pm == kernel_pmap && va < KERNBASE)
3451					continue;
3452				if (pm != kernel_pmap && va > UPT_MAX_ADDRESS)
3453					continue;
3454				ptep = pmap_pte_quick(pm, va);
3455				if (pmap_pte_v(ptep))
3456					printf("%x:%x ", va, *(int *) ptep);
3457			};
3458
3459}
3460
3461void
3462pmap_pvdump(pa)
3463	vm_offset_t pa;
3464{
3465	pv_table_t *ppv;
3466	register pv_entry_t pv;
3467
3468	printf("pa %x", pa);
3469	ppv = pa_to_pvh(pa);
3470	for (pv = TAILQ_FIRST(&ppv->pv_list);
3471		pv;
3472		pv = TAILQ_NEXT(pv, pv_list)) {
3473#ifdef used_to_be
3474		printf(" -> pmap %p, va %x, flags %x",
3475		    (void *)pv->pv_pmap, pv->pv_va, pv->pv_flags);
3476#endif
3477		printf(" -> pmap %p, va %x", (void *)pv->pv_pmap, pv->pv_va);
3478		pads(pv->pv_pmap);
3479	}
3480	printf(" ");
3481}
3482#endif
3483