pmap.c revision 4
1311116Sdim/*
2311116Sdim * Copyright (c) 1991 Regents of the University of California.
3353358Sdim * All rights reserved.
4353358Sdim *
5353358Sdim * This code is derived from software contributed to Berkeley by
6311116Sdim * the Systems Programming Group of the University of Utah Computer
7311116Sdim * Science Department and William Jolitz of UUNET Technologies Inc.
8311116Sdim *
9321369Sdim * Redistribution and use in source and binary forms, with or without
10321369Sdim * modification, are permitted provided that the following conditions
11311116Sdim * are met:
12321369Sdim * 1. Redistributions of source code must retain the above copyright
13311116Sdim *    notice, this list of conditions and the following disclaimer.
14311116Sdim * 2. Redistributions in binary form must reproduce the above copyright
15311116Sdim *    notice, this list of conditions and the following disclaimer in the
16321369Sdim *    documentation and/or other materials provided with the distribution.
17311116Sdim * 3. All advertising materials mentioning features or use of this software
18311116Sdim *    must display the following acknowledgement:
19311116Sdim *	This product includes software developed by the University of
20360784Sdim *	California, Berkeley and its contributors.
21341825Sdim * 4. Neither the name of the University nor the names of its contributors
22311116Sdim *    may be used to endorse or promote products derived from this software
23311116Sdim *    without specific prior written permission.
24321369Sdim *
25321369Sdim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26321369Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27341825Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28360784Sdim * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29311116Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30321369Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31311116Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32311116Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33311116Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34311116Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35311116Sdim * SUCH DAMAGE.
36311116Sdim *
37321369Sdim *	@(#)pmap.c	7.7 (Berkeley)	5/12/91
38321369Sdim *
39321369Sdim * PATCHES MAGIC                LEVEL   PATCH THAT GOT US HERE
40321369Sdim * --------------------         -----   ----------------------
41311116Sdim * CURRENT PATCH LEVEL:         1       00063
42321369Sdim * --------------------         -----   ----------------------
43311116Sdim *
44321369Sdim * 28 Nov 1991	Poul-Henning Kamp	Speedup processing.
45327952Sdim */
46327952Sdimstatic char rcsid[] = "$Header: /usr/src/sys.386bsd/i386/i386/RCS/pmap.c,v 1.3 92/01/21 14:26:44 william Exp Locker: root $";
47327952Sdim
48327952Sdim/*
49327952Sdim * Derived from hp300 version by Mike Hibler, this version by William
50327952Sdim * Jolitz uses a recursive map [a pde points to the page directory] to
51327952Sdim * map the page tables using the pagetables themselves. This is done to
52327952Sdim * reduce the impact on kernel virtual memory for lots of sparse address
53327952Sdim * space, and to reduce the cost of memory to each process.
54327952Sdim *
55327952Sdim *	Derived from: hp300/@(#)pmap.c	7.1 (Berkeley) 12/5/90
56311116Sdim */
57321369Sdim
58311116Sdim/*
59321369Sdim *	Reno i386 version, from Mike Hibler's hp300 version.
60321369Sdim */
61321369Sdim
62321369Sdim/*
63311116Sdim *	Manages physical address maps.
64311116Sdim *
65311116Sdim *	In addition to hardware address maps, this
66311116Sdim *	module is called upon to provide software-use-only
67321369Sdim *	maps which may or may not be stored in the same
68321369Sdim *	form as hardware maps.  These pseudo-maps are
69321369Sdim *	used to store intermediate results from copy
70321369Sdim *	operations to and from address spaces.
71321369Sdim *
72311116Sdim *	Since the information managed by this module is
73321369Sdim *	also stored by the logical address mapping module,
74321369Sdim *	this module may throw away valid virtual-to-physical
75321369Sdim *	mappings at almost any time.  However, invalidations
76321369Sdim *	of virtual-to-physical mappings must be done as
77321369Sdim *	requested.
78321369Sdim *
79321369Sdim *	In order to cope with hardware architectures which
80311116Sdim *	make virtual-to-physical map invalidates expensive,
81311116Sdim *	this module may delay invalidate or reduced protection
82311116Sdim *	operations until such time as they are actually
83311116Sdim *	necessary.  This module is given full information as
84311116Sdim *	to which processors are currently using which maps,
85311116Sdim *	and to when physical maps must be made correct.
86311116Sdim */
87311116Sdim
88311116Sdim#include "param.h"
89311116Sdim#include "proc.h"
90311116Sdim#include "malloc.h"
91311116Sdim#include "user.h"
92311116Sdim
93311116Sdim#include "vm/vm.h"
94311116Sdim#include "vm/vm_kern.h"
95311116Sdim#include "vm/vm_page.h"
96327952Sdim/*#include "vm/vm_pageout.h"*/
97311116Sdim
98311116Sdim#include "i386/isa/isa.h"
99311116Sdim
100311116Sdim/*
101311116Sdim * Allocate various and sundry SYSMAPs used in the days of old VM
102311116Sdim * and not yet converted.  XXX.
103311116Sdim */
104311116Sdim#define BSDVM_COMPAT	1
105311116Sdim
106311116Sdim#ifdef DEBUG
107311116Sdimstruct {
108311116Sdim	int kernel;	/* entering kernel mapping */
109311116Sdim	int user;	/* entering user mapping */
110311116Sdim	int ptpneeded;	/* needed to allocate a PT page */
111311116Sdim	int pwchange;	/* no mapping change, just wiring or protection */
112311116Sdim	int wchange;	/* no mapping change, just wiring */
113311116Sdim	int mchange;	/* was mapped but mapping to different page */
114311116Sdim	int managed;	/* a managed page */
115311116Sdim	int firstpv;	/* first mapping for this PA */
116311116Sdim	int secondpv;	/* second mapping for this PA */
117311116Sdim	int ci;		/* cache inhibited */
118311116Sdim	int unmanaged;	/* not a managed page */
119311116Sdim	int flushes;	/* cache flushes */
120311116Sdim} enter_stats;
121311116Sdimstruct {
122311116Sdim	int calls;
123311116Sdim	int removes;
124311116Sdim	int pvfirst;
125311116Sdim	int pvsearch;
126311116Sdim	int ptinvalid;
127311116Sdim	int uflushes;
128311116Sdim	int sflushes;
129311116Sdim} remove_stats;
130311116Sdim
131311116Sdimint debugmap = 0;
132311116Sdimint pmapdebug = 0 /* 0xffff */;
133311116Sdim#define PDB_FOLLOW	0x0001
134341825Sdim#define PDB_INIT	0x0002
135311116Sdim#define PDB_ENTER	0x0004
136311116Sdim#define PDB_REMOVE	0x0008
137311116Sdim#define PDB_CREATE	0x0010
138311116Sdim#define PDB_PTPAGE	0x0020
139311116Sdim#define PDB_CACHE	0x0040
140311116Sdim#define PDB_BITS	0x0080
141311116Sdim#define PDB_COLLECT	0x0100
142311116Sdim#define PDB_PROTECT	0x0200
143311116Sdim#define PDB_PDRTAB	0x0400
144311116Sdim#define PDB_PARANOIA	0x2000
145311116Sdim#define PDB_WIRING	0x4000
146311116Sdim#define PDB_PVDUMP	0x8000
147311116Sdim
148311116Sdimint pmapvacflush = 0;
149311116Sdim#define	PVF_ENTER	0x01
150311116Sdim#define	PVF_REMOVE	0x02
151311116Sdim#define	PVF_PROTECT	0x04
152327952Sdim#define	PVF_TOTAL	0x80
153327952Sdim#endif
154327952Sdim
155311116Sdim/*
156311116Sdim * Get PDEs and PTEs for user/kernel address space
157311116Sdim */
158344779Sdim#define	pmap_pde(m, v)	(&((m)->pm_pdir[((vm_offset_t)(v) >> PD_SHIFT)&1023]))
159344779Sdim
160311116Sdim#define pmap_pte_pa(pte)	(*(int *)(pte) & PG_FRAME)
161311116Sdim
162311116Sdim#define pmap_pde_v(pte)		((pte)->pd_v)
163311116Sdim#define pmap_pte_w(pte)		((pte)->pg_w)
164311116Sdim/* #define pmap_pte_ci(pte)	((pte)->pg_ci) */
165311116Sdim#define pmap_pte_m(pte)		((pte)->pg_m)
166311116Sdim#define pmap_pte_u(pte)		((pte)->pg_u)
167311116Sdim#define pmap_pte_v(pte)		((pte)->pg_v)
168311116Sdim#define pmap_pte_set_w(pte, v)		((pte)->pg_w = (v))
169311116Sdim#define pmap_pte_set_prot(pte, v)	((pte)->pg_prot = (v))
170311116Sdim
171311116Sdim/*
172311116Sdim * Given a map and a machine independent protection code,
173311116Sdim * convert to a vax protection code.
174311116Sdim */
175341825Sdim#define pte_prot(m, p)	(protection_codes[p])
176341825Sdimint	protection_codes[8];
177341825Sdim
178341825Sdimstruct pmap	kernel_pmap_store;
179341825Sdimpmap_t		kernel_pmap;
180341825Sdim
181341825Sdimvm_offset_t    	avail_start;	/* PA of first available physical page */
182311116Sdimvm_offset_t	avail_end;	/* PA of last available physical page */
183341825Sdimvm_size_t	mem_size;	/* memory size in bytes */
184341825Sdimvm_offset_t	virtual_avail;  /* VA of first avail page (after kernel bss)*/
185341825Sdimvm_offset_t	virtual_end;	/* VA of last avail page (end of kernel AS) */
186311116Sdimvm_offset_t	vm_first_phys;	/* PA of first managed page */
187311116Sdimvm_offset_t	vm_last_phys;	/* PA just past last managed page */
188321369Sdimint		i386pagesperpage;	/* PAGE_SIZE / I386_PAGE_SIZE */
189321369Sdimboolean_t	pmap_initialized = FALSE;	/* Has pmap_init completed? */
190321369Sdimchar		*pmap_attributes;	/* reference and modify bits */
191321369Sdim
192321369Sdimboolean_t	pmap_testbit();
193321369Sdimvoid		pmap_clear_modify();
194321369Sdim
195321369Sdim#if BSDVM_COMPAT
196321369Sdim#include "msgbuf.h"
197311116Sdim
198311116Sdim/*
199311116Sdim * All those kernel PT submaps that BSD is so fond of
200321369Sdim */
201321369Sdimstruct pte	*CMAP1, *CMAP2, *mmap;
202321369Sdimcaddr_t		CADDR1, CADDR2, vmmap;
203321369Sdimstruct pte	*msgbufmap;
204311116Sdimstruct msgbuf	*msgbufp;
205341825Sdim#endif
206341825Sdim
207341825Sdim/*
208341825Sdim *	Bootstrap the system enough to run with virtual memory.
209341825Sdim *	Map the kernel's code and data, and allocate the system page table.
210341825Sdim *
211341825Sdim *	On the I386 this is called after mapping has already been enabled
212321369Sdim *	and just syncs the pmap module with what has already been done.
213321369Sdim *	[We can't call it easily with mapping off since the kernel is not
214321369Sdim *	mapped with PA == VA, hence we would have to relocate every address
215341825Sdim *	from the linked base (virtual) address 0xFE000000 to the actual
216341825Sdim *	(physical) address starting relative to 0]
217341825Sdim */
218311116Sdimstruct pte *pmap_pte();
219311116Sdim
220311116Sdimvoid
221311116Sdimpmap_bootstrap(firstaddr, loadaddr)
222311116Sdim	vm_offset_t firstaddr;
223360784Sdim	vm_offset_t loadaddr;
224360784Sdim{
225360784Sdim#if BSDVM_COMPAT
226360784Sdim	vm_offset_t va;
227360784Sdim	struct pte *pte;
228360784Sdim#endif
229341825Sdim	extern vm_offset_t maxmem, physmem;
230360784Sdimextern int IdlePTD;
231360784Sdim
232360784Sdim	avail_start = firstaddr;
233360784Sdim	avail_end = maxmem << PG_SHIFT;
234360784Sdim
235341825Sdim	/* XXX: allow for msgbuf */
236311116Sdim	avail_end -= i386_round_page(sizeof(struct msgbuf));
237311116Sdim
238321369Sdim	mem_size = physmem << PG_SHIFT;
239321369Sdim	virtual_avail = (vm_offset_t)atdevbase + 0x100000 - 0xa0000 + 10*NBPG;
240321369Sdim	virtual_end = VM_MAX_KERNEL_ADDRESS;
241321369Sdim	i386pagesperpage = PAGE_SIZE / I386_PAGE_SIZE;
242321369Sdim
243321369Sdim	/*
244321369Sdim	 * Initialize protection array.
245321369Sdim	 */
246321369Sdim	i386_protection_init();
247321369Sdim
248321369Sdim	/*
249321369Sdim	 * The kernel's pmap is statically allocated so we don't
250344779Sdim	 * have to use pmap_create, which is unlikely to work
251321369Sdim	 * correctly at this part of the boot sequence.
252321369Sdim	 */
253321369Sdim	kernel_pmap = &kernel_pmap_store;
254321369Sdim
255321369Sdim#ifdef notdef
256321369Sdim	/*
257321369Sdim	 * Create Kernel page directory table and page maps.
258321369Sdim	 * [ currently done in locore. i have wild and crazy ideas -wfj ]
259321369Sdim	 */
260321369Sdim	bzero(firstaddr, 4*NBPG);
261321369Sdim	kernel_pmap->pm_pdir = firstaddr + VM_MIN_KERNEL_ADDRESS;
262321369Sdim	kernel_pmap->pm_ptab = firstaddr + VM_MIN_KERNEL_ADDRESS + NBPG;
263321369Sdim
264321369Sdim	firstaddr += NBPG;
265321369Sdim	for (x = i386_btod(VM_MIN_KERNEL_ADDRESS);
266321369Sdim		x < i386_btod(VM_MIN_KERNEL_ADDRESS)+3; x++) {
267321369Sdim			struct pde *pde;
268321369Sdim		pde = kernel_pmap->pm_pdir + x;
269321369Sdim		*(int *)pde = firstaddr + x*NBPG | PG_V | PG_KW;
270321369Sdim	}
271321369Sdim#else
272321369Sdim	kernel_pmap->pm_pdir = (pd_entry_t *)(0xfe000000 + IdlePTD);
273321369Sdim#endif
274311116Sdim
275321369Sdim
276341825Sdim	simple_lock_init(&kernel_pmap->pm_lock);
277321369Sdim	kernel_pmap->pm_count = 1;
278321369Sdim
279321369Sdim#if BSDVM_COMPAT
280321369Sdim	/*
281321369Sdim	 * Allocate all the submaps we need
282321369Sdim	 */
283321369Sdim#define	SYSMAP(c, p, v, n)	\
284321369Sdim	v = (c)va; va += ((n)*I386_PAGE_SIZE); p = pte; pte += (n);
285321369Sdim
286321369Sdim	va = virtual_avail;
287341825Sdim	pte = pmap_pte(kernel_pmap, va);
288311116Sdim
289321369Sdim	SYSMAP(caddr_t		,CMAP1		,CADDR1	   ,1		)
290321369Sdim	SYSMAP(caddr_t		,CMAP2		,CADDR2	   ,1		)
291321369Sdim	SYSMAP(caddr_t		,mmap		,vmmap	   ,1		)
292321369Sdim	SYSMAP(struct msgbuf *	,msgbufmap	,msgbufp   ,1		)
293321369Sdim	virtual_avail = va;
294321369Sdim#endif
295321369Sdim	/*
296321369Sdim	 * reserve special hunk of memory for use by bus dma as a bounce
297311116Sdim	 * buffer (contiguous virtual *and* physical memory). for now,
298321369Sdim	 * assume vm does not use memory beneath hole, and we know that
299321369Sdim	 * the bootstrap uses top 32k of base memory. -wfj
300321369Sdim	 */
301321369Sdim	{
302311116Sdim		extern vm_offset_t isaphysmem;
303321369Sdim	isaphysmem = va;
304321369Sdim
305321369Sdim	virtual_avail = pmap_map(va, 0xa0000 - 32*1024, 0xa0000, VM_PROT_ALL);
306321369Sdim	}
307321369Sdim
308321369Sdim	*(int *)PTD = 0;
309321369Sdim	load_cr3(rcr3());
310321369Sdim
311321369Sdim}
312321369Sdim
313321369Sdim/*
314321369Sdim *	Initialize the pmap module.
315321369Sdim *	Called by vm_init, to initialize any structures that the pmap
316321369Sdim *	system needs to map virtual memory.
317321369Sdim */
318341825Sdimvoid
319321369Sdimpmap_init(phys_start, phys_end)
320321369Sdim	vm_offset_t	phys_start, phys_end;
321321369Sdim{
322321369Sdim	vm_offset_t	addr, addr2;
323321369Sdim	vm_size_t	npg, s;
324321369Sdim	int		rv;
325321369Sdim	extern int KPTphys;
326321369Sdim
327321369Sdim#ifdef DEBUG
328360784Sdim	if (pmapdebug & PDB_FOLLOW)
329321369Sdim		printf("pmap_init(%x, %x)\n", phys_start, phys_end);
330360784Sdim#endif
331321369Sdim	/*
332321369Sdim	 * Now that kernel map has been allocated, we can mark as
333321369Sdim	 * unavailable regions which we have mapped in locore.
334321369Sdim	 */
335321369Sdim	addr = atdevbase;
336321369Sdim	(void) vm_map_find(kernel_map, NULL, (vm_offset_t) 0,
337321369Sdim			   &addr, (0x100000-0xa0000), FALSE);
338321369Sdim
339321369Sdim	addr = (vm_offset_t) 0xfe000000+KPTphys/* *NBPG */;
340321369Sdim	vm_object_reference(kernel_object);
341321369Sdim	(void) vm_map_find(kernel_map, kernel_object, addr,
342321369Sdim			   &addr, 2*NBPG, FALSE);
343321369Sdim
344321369Sdim	/*
345321369Sdim	 * Allocate memory for random pmap data structures.  Includes the
346321369Sdim	 * pv_head_table and pmap_attributes.
347341825Sdim	 */
348341825Sdim	npg = atop(phys_end - phys_start);
349341825Sdim	s = (vm_size_t) (sizeof(struct pv_entry) * npg + npg);
350341825Sdim	s = round_page(s);
351341825Sdim	addr = (vm_offset_t) kmem_alloc(kernel_map, s);
352341825Sdim	pv_table = (pv_entry_t) addr;
353341825Sdim	addr += sizeof(struct pv_entry) * npg;
354341825Sdim	pmap_attributes = (char *) addr;
355341825Sdim#ifdef DEBUG
356341825Sdim	if (pmapdebug & PDB_INIT)
357341825Sdim		printf("pmap_init: %x bytes (%x pgs): tbl %x attr %x\n",
358341825Sdim		       s, npg, pv_table, pmap_attributes);
359341825Sdim#endif
360341825Sdim
361341825Sdim	/*
362341825Sdim	 * Now it is safe to enable pv_table recording.
363341825Sdim	 */
364341825Sdim	vm_first_phys = phys_start;
365341825Sdim	vm_last_phys = phys_end;
366341825Sdim	pmap_initialized = TRUE;
367341825Sdim}
368341825Sdim
369341825Sdim/*
370341825Sdim *	Used to map a range of physical addresses into kernel
371341825Sdim *	virtual address space.
372341825Sdim *
373341825Sdim *	For now, VM is already on, we only need to map the
374341825Sdim *	specified memory.
375341825Sdim */
376341825Sdimvm_offset_t
377341825Sdimpmap_map(virt, start, end, prot)
378341825Sdim	vm_offset_t	virt;
379341825Sdim	vm_offset_t	start;
380341825Sdim	vm_offset_t	end;
381341825Sdim	int		prot;
382341825Sdim{
383341825Sdim#ifdef DEBUG
384341825Sdim	if (pmapdebug & PDB_FOLLOW)
385341825Sdim		printf("pmap_map(%x, %x, %x, %x)\n", virt, start, end, prot);
386341825Sdim#endif
387341825Sdim	while (start < end) {
388311116Sdim		pmap_enter(kernel_pmap, virt, start, prot, FALSE);
389311116Sdim		virt += PAGE_SIZE;
390321369Sdim		start += PAGE_SIZE;
391321369Sdim	}
392321369Sdim	return(virt);
393321369Sdim}
394321369Sdim
395321369Sdim/*
396321369Sdim *	Create and return a physical map.
397321369Sdim *
398321369Sdim *	If the size specified for the map
399321369Sdim *	is zero, the map is an actual physical
400311116Sdim *	map, and may be referenced by the
401321369Sdim *	hardware.
402311116Sdim *
403321369Sdim *	If the size specified is non-zero,
404321369Sdim *	the map will be used in software only, and
405321369Sdim *	is bounded by that size.
406321369Sdim *
407341825Sdim * [ just allocate a ptd and mark it uninitialize -- should we track
408321369Sdim *   with a table which process has which ptd? -wfj ]
409341825Sdim */
410321369Sdim
411321369Sdimpmap_t
412321369Sdimpmap_create(size)
413311116Sdim	vm_size_t	size;
414327952Sdim{
415327952Sdim	register pmap_t pmap;
416327952Sdim
417321369Sdim#ifdef DEBUG
418321369Sdim	if (pmapdebug & (PDB_FOLLOW|PDB_CREATE))
419321369Sdim		printf("pmap_create(%x)\n", size);
420321369Sdim#endif
421341825Sdim	/*
422341825Sdim	 * Software use map does not need a pmap
423321369Sdim	 */
424321369Sdim	if (size)
425321369Sdim		return(NULL);
426321369Sdim
427321369Sdim	/* XXX: is it ok to wait here? */
428311116Sdim	pmap = (pmap_t) malloc(sizeof *pmap, M_VMPMAP, M_WAITOK);
429311116Sdim#ifdef notifwewait
430353358Sdim	if (pmap == NULL)
431353358Sdim		panic("pmap_create: cannot allocate a pmap");
432344779Sdim#endif
433344779Sdim	bzero(pmap, sizeof(*pmap));
434344779Sdim	pmap_pinit(pmap);
435344779Sdim	return (pmap);
436353358Sdim}
437353358Sdim
438344779Sdim/*
439353358Sdim * Initialize a preallocated and zeroed pmap structure,
440353358Sdim * such as one in a vmspace structure.
441311116Sdim */
442341825Sdimvoid
443311116Sdimpmap_pinit(pmap)
444311116Sdim	register struct pmap *pmap;
445311116Sdim{
446311116Sdim
447311116Sdim#ifdef DEBUG
448321369Sdim	if (pmapdebug & (PDB_FOLLOW|PDB_CREATE))
449321369Sdim		pg("pmap_pinit(%x)\n", pmap);
450321369Sdim#endif
451353358Sdim
452353358Sdim	/*
453353358Sdim	 * No need to allocate page table space yet but we do need a
454353358Sdim	 * valid page directory table.
455353358Sdim	 */
456353358Sdim	pmap->pm_pdir = (pd_entry_t *) kmem_alloc(kernel_map, NBPG);
457353358Sdim
458353358Sdim	/* wire in kernel global address entries */
459353358Sdim	bcopy(PTD+KPTDI_FIRST, pmap->pm_pdir+KPTDI_FIRST,
460353358Sdim		(KPTDI_LAST-KPTDI_FIRST+1)*4);
461353358Sdim
462353358Sdim	/* install self-referential address mapping entry */
463353358Sdim	*(int *)(pmap->pm_pdir+PTDPTDI) =
464353358Sdim		(int)pmap_extract(kernel_pmap, pmap->pm_pdir) | PG_V | PG_URKW;
465353358Sdim
466353358Sdim	pmap->pm_count = 1;
467353358Sdim	simple_lock_init(&pmap->pm_lock);
468353358Sdim}
469353358Sdim
470360784Sdim/*
471353358Sdim *	Retire the given physical map from service.
472353358Sdim *	Should only be called if the map contains
473353358Sdim *	no valid mappings.
474353358Sdim */
475311116Sdimvoid
476353358Sdimpmap_destroy(pmap)
477321369Sdim	register pmap_t pmap;
478321369Sdim{
479321369Sdim	int count;
480321369Sdim
481321369Sdim#ifdef DEBUG
482341825Sdim	if (pmapdebug & PDB_FOLLOW)
483321369Sdim		printf("pmap_destroy(%x)\n", pmap);
484327952Sdim#endif
485327952Sdim	if (pmap == NULL)
486327952Sdim		return;
487327952Sdim
488341825Sdim	simple_lock(&pmap->pm_lock);
489311116Sdim	count = --pmap->pm_count;
490311116Sdim	simple_unlock(&pmap->pm_lock);
491311116Sdim	if (count == 0) {
492311116Sdim		pmap_release(pmap);
493321369Sdim		free((caddr_t)pmap, M_VMPMAP);
494321369Sdim	}
495321369Sdim}
496311116Sdim
497311116Sdim/*
498311116Sdim * Release any resources held by the given physical map.
499321369Sdim * Called when a pmap initialized by pmap_pinit is being released.
500311116Sdim * Should only be called if the map contains no valid mappings.
501311116Sdim */
502311116Sdimvoid
503321369Sdimpmap_release(pmap)
504321369Sdim	register struct pmap *pmap;
505311116Sdim{
506311116Sdim
507311116Sdim#ifdef DEBUG
508311116Sdim	if (pmapdebug & PDB_FOLLOW)
509311116Sdim		pg("pmap_release(%x)\n", pmap);
510311116Sdim#endif
511311116Sdim#ifdef notdef /* DIAGNOSTIC */
512311116Sdim	/* count would be 0 from pmap_destroy... */
513321369Sdim	simple_lock(&pmap->pm_lock);
514311116Sdim	if (pmap->pm_count != 1)
515311116Sdim		panic("pmap_release count");
516311116Sdim#endif
517311116Sdim	kmem_free(kernel_map, (vm_offset_t)pmap->pm_pdir, NBPG);
518321369Sdim}
519311116Sdim
520321369Sdim/*
521311116Sdim *	Add a reference to the specified pmap.
522311116Sdim */
523311116Sdimvoid
524311116Sdimpmap_reference(pmap)
525311116Sdim	pmap_t	pmap;
526311116Sdim{
527311116Sdim#ifdef DEBUG
528321369Sdim	if (pmapdebug & PDB_FOLLOW)
529311116Sdim		printf("pmap_reference(%x)", pmap);
530321369Sdim#endif
531311116Sdim	if (pmap != NULL) {
532311116Sdim		simple_lock(&pmap->pm_lock);
533311116Sdim		pmap->pm_count++;
534321369Sdim		simple_unlock(&pmap->pm_lock);
535321369Sdim	}
536321369Sdim}
537311116Sdim
538321369Sdim/*
539321369Sdim *	Remove the given range of addresses from the specified map.
540321369Sdim *
541321369Sdim *	It is assumed that the start and end are properly
542321369Sdim *	rounded to the page size.
543321369Sdim */
544321369Sdimvoid
545321369Sdimpmap_remove(pmap, sva, eva)
546321369Sdim	struct pmap *pmap;
547321369Sdim	register vm_offset_t sva;
548321369Sdim	register vm_offset_t eva;
549321369Sdim{
550	register pt_entry_t *ptp,*ptq;
551	vm_offset_t va;
552	vm_offset_t pa;
553	pt_entry_t *pte;
554	pv_entry_t pv, npv;
555	int ix;
556	int s, bits;
557#ifdef DEBUG
558	pt_entry_t opte;
559
560	if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT))
561		pg("pmap_remove(%x, %x, %x)", pmap, sva, eva);
562#endif
563
564	if (pmap == NULL)
565		return;
566
567	/* are we current address space or kernel? */
568	if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum
569		|| pmap == kernel_pmap)
570		ptp=PTmap;
571
572	/* otherwise, we are alternate address space */
573	else {
574		if (pmap->pm_pdir[PTDPTDI].pd_pfnum
575			!= APTDpde.pd_pfnum) {
576			APTDpde = pmap->pm_pdir[PTDPTDI];
577			tlbflush();
578		}
579		ptp=APTmap;
580	     }
581#ifdef DEBUG
582	remove_stats.calls++;
583#endif
584
585	/* this is essential since we must check the PDE(sva) for precense */
586	while (sva <= eva && !pmap_pde_v(pmap_pde(pmap, sva)))
587		sva = (sva & PD_MASK) + (1<<PD_SHIFT);
588	sva = i386_btop(sva);
589	eva = i386_btop(eva);
590
591	for (; sva < eva; sva++) {
592		/*
593		 * Weed out invalid mappings.
594		 * Note: we assume that the page directory table is
595	 	 * always allocated, and in kernel virtual.
596		 */
597		ptq=ptp+sva;
598		while((sva & 0x3ff) && !pmap_pte_pa(ptq))
599		    {
600		    if(++sva >= eva)
601		        return;
602		    ptq++;
603		    }
604
605
606		if(!(sva & 0x3ff)) /* Only check once in a while */
607 		    {
608		    if (!pmap_pde_v(pmap_pde(pmap, i386_ptob(sva))))
609			{
610			/* We can race ahead here, straight to next pde.. */
611			sva = (sva & 0xffc00) + (1<<10) -1 ;
612			continue;
613			}
614		    }
615	        if(!pmap_pte_pa(ptp+sva))
616		    continue;
617
618		pte = ptp + sva;
619		pa = pmap_pte_pa(pte);
620		va = i386_ptob(sva);
621#ifdef DEBUG
622		opte = *pte;
623		remove_stats.removes++;
624#endif
625		/*
626		 * Update statistics
627		 */
628		if (pmap_pte_w(pte))
629			pmap->pm_stats.wired_count--;
630		pmap->pm_stats.resident_count--;
631
632		/*
633		 * Invalidate the PTEs.
634		 * XXX: should cluster them up and invalidate as many
635		 * as possible at once.
636		 */
637#ifdef DEBUG
638		if (pmapdebug & PDB_REMOVE)
639			printf("remove: inv %x ptes at %x(%x) ",
640			       i386pagesperpage, pte, *(int *)pte);
641#endif
642		bits = ix = 0;
643		do {
644			bits |= *(int *)pte & (PG_U|PG_M);
645			*(int *)pte++ = 0;
646			/*TBIS(va + ix * I386_PAGE_SIZE);*/
647		} while (++ix != i386pagesperpage);
648		if (curproc && pmap == &curproc->p_vmspace->vm_pmap)
649			pmap_activate(pmap, (struct pcb *)curproc->p_addr);
650		/* are we current address space or kernel? */
651		/*if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum
652			|| pmap == kernel_pmap)
653		load_cr3(curpcb->pcb_ptd);*/
654		tlbflush();
655
656#ifdef needednotdone
657reduce wiring count on page table pages as references drop
658#endif
659
660		/*
661		 * Remove from the PV table (raise IPL since we
662		 * may be called at interrupt time).
663		 */
664		if (pa < vm_first_phys || pa >= vm_last_phys)
665			continue;
666		pv = pa_to_pvh(pa);
667		s = splimp();
668		/*
669		 * If it is the first entry on the list, it is actually
670		 * in the header and we must copy the following entry up
671		 * to the header.  Otherwise we must search the list for
672		 * the entry.  In either case we free the now unused entry.
673		 */
674		if (pmap == pv->pv_pmap && va == pv->pv_va) {
675			npv = pv->pv_next;
676			if (npv) {
677				*pv = *npv;
678				free((caddr_t)npv, M_VMPVENT);
679			} else
680				pv->pv_pmap = NULL;
681#ifdef DEBUG
682			remove_stats.pvfirst++;
683#endif
684		} else {
685			for (npv = pv->pv_next; npv; npv = npv->pv_next) {
686#ifdef DEBUG
687				remove_stats.pvsearch++;
688#endif
689				if (pmap == npv->pv_pmap && va == npv->pv_va)
690					break;
691				pv = npv;
692			}
693#ifdef DEBUG
694			if (npv == NULL)
695				panic("pmap_remove: PA not in pv_tab");
696#endif
697			pv->pv_next = npv->pv_next;
698			free((caddr_t)npv, M_VMPVENT);
699			pv = pa_to_pvh(pa);
700		}
701
702#ifdef notdef
703[tally number of pagetable pages, if sharing of ptpages adjust here]
704#endif
705		/*
706		 * Update saved attributes for managed page
707		 */
708		pmap_attributes[pa_index(pa)] |= bits;
709		splx(s);
710	}
711#ifdef notdef
712[cache and tlb flushing, if needed]
713#endif
714}
715
716/*
717 *	Routine:	pmap_remove_all
718 *	Function:
719 *		Removes this physical page from
720 *		all physical maps in which it resides.
721 *		Reflects back modify bits to the pager.
722 */
723void
724pmap_remove_all(pa)
725	vm_offset_t pa;
726{
727	register pv_entry_t pv;
728	int s;
729
730#ifdef DEBUG
731	if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT))
732		printf("pmap_remove_all(%x)", pa);
733	/*pmap_pvdump(pa);*/
734#endif
735	/*
736	 * Not one of ours
737	 */
738	if (pa < vm_first_phys || pa >= vm_last_phys)
739		return;
740
741	pv = pa_to_pvh(pa);
742	s = splimp();
743	/*
744	 * Do it the easy way for now
745	 */
746	while (pv->pv_pmap != NULL) {
747#ifdef DEBUG
748		if (!pmap_pde_v(pmap_pde(pv->pv_pmap, pv->pv_va)) ||
749		    pmap_pte_pa(pmap_pte(pv->pv_pmap, pv->pv_va)) != pa)
750			panic("pmap_remove_all: bad mapping");
751#endif
752		pmap_remove(pv->pv_pmap, pv->pv_va, pv->pv_va + PAGE_SIZE);
753	}
754	splx(s);
755}
756
757/*
758 *	Routine:	pmap_copy_on_write
759 *	Function:
760 *		Remove write privileges from all
761 *		physical maps for this physical page.
762 */
763void
764pmap_copy_on_write(pa)
765	vm_offset_t pa;
766{
767#ifdef DEBUG
768	if (pmapdebug & (PDB_FOLLOW|PDB_PROTECT))
769		printf("pmap_copy_on_write(%x)", pa);
770#endif
771	pmap_changebit(pa, PG_RO, TRUE);
772}
773
774/*
775 *	Set the physical protection on the
776 *	specified range of this map as requested.
777 */
778void
779pmap_protect(pmap, sva, eva, prot)
780	register pmap_t	pmap;
781	vm_offset_t	sva, eva;
782	vm_prot_t	prot;
783{
784	register pt_entry_t *pte;
785	register vm_offset_t va;
786	register int ix;
787	int i386prot;
788	boolean_t firstpage = TRUE;
789	register pt_entry_t *ptp;
790
791#ifdef DEBUG
792	if (pmapdebug & (PDB_FOLLOW|PDB_PROTECT))
793		printf("pmap_protect(%x, %x, %x, %x)", pmap, sva, eva, prot);
794#endif
795	if (pmap == NULL)
796		return;
797
798	if ((prot & VM_PROT_READ) == VM_PROT_NONE) {
799		pmap_remove(pmap, sva, eva);
800		return;
801	}
802	if (prot & VM_PROT_WRITE)
803		return;
804
805	/* are we current address space or kernel? */
806	if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum
807		|| pmap == kernel_pmap)
808		ptp=PTmap;
809
810	/* otherwise, we are alternate address space */
811	else {
812		if (pmap->pm_pdir[PTDPTDI].pd_pfnum
813			!= APTDpde.pd_pfnum) {
814			APTDpde = pmap->pm_pdir[PTDPTDI];
815			tlbflush();
816		}
817		ptp=APTmap;
818	     }
819	for (va = sva; va < eva; va += PAGE_SIZE) {
820		/*
821		 * Page table page is not allocated.
822		 * Skip it, we don't want to force allocation
823		 * of unnecessary PTE pages just to set the protection.
824		 */
825		if (!pmap_pde_v(pmap_pde(pmap, va))) {
826			/* XXX: avoid address wrap around */
827			if (va >= i386_trunc_pdr((vm_offset_t)-1))
828				break;
829			va = i386_round_pdr(va + PAGE_SIZE) - PAGE_SIZE;
830			continue;
831		}
832
833		pte = ptp + i386_btop(va);
834
835		/*
836		 * Page not valid.  Again, skip it.
837		 * Should we do this?  Or set protection anyway?
838		 */
839		if (!pmap_pte_v(pte))
840			continue;
841
842		ix = 0;
843		i386prot = pte_prot(pmap, prot);
844		if(va < UPT_MAX_ADDRESS)
845			i386prot |= 2 /*PG_u*/;
846		do {
847			/* clear VAC here if PG_RO? */
848			pmap_pte_set_prot(pte++, i386prot);
849			/*TBIS(va + ix * I386_PAGE_SIZE);*/
850		} while (++ix != i386pagesperpage);
851	}
852	if (curproc && pmap == &curproc->p_vmspace->vm_pmap)
853		pmap_activate(pmap, (struct pcb *)curproc->p_addr);
854}
855
856/*
857 *	Insert the given physical page (p) at
858 *	the specified virtual address (v) in the
859 *	target physical map with the protection requested.
860 *
861 *	If specified, the page will be wired down, meaning
862 *	that the related pte can not be reclaimed.
863 *
864 *	NB:  This is the only routine which MAY NOT lazy-evaluate
865 *	or lose information.  That is, this routine must actually
866 *	insert this page into the given map NOW.
867 */
868void
869pmap_enter(pmap, va, pa, prot, wired)
870	register pmap_t pmap;
871	vm_offset_t va;
872	register vm_offset_t pa;
873	vm_prot_t prot;
874	boolean_t wired;
875{
876	register pt_entry_t *pte;
877	register int npte, ix;
878	vm_offset_t opa;
879	boolean_t cacheable = TRUE;
880	boolean_t checkpv = TRUE;
881
882#ifdef DEBUG
883	if (pmapdebug & (PDB_FOLLOW|PDB_ENTER))
884		printf("pmap_enter(%x, %x, %x, %x, %x)",
885		       pmap, va, pa, prot, wired);
886#endif
887	if (pmap == NULL)
888		return;
889
890	if(va > VM_MAX_KERNEL_ADDRESS)panic("pmap_enter: toobig");
891	/* also, should not muck with PTD va! */
892
893#ifdef DEBUG
894	if (pmap == kernel_pmap)
895		enter_stats.kernel++;
896	else
897		enter_stats.user++;
898#endif
899
900	/*
901	 * Page Directory table entry not valid, we need a new PT page
902	 */
903	if (!pmap_pde_v(pmap_pde(pmap, va))) {
904		pg("ptdi %x", pmap->pm_pdir[PTDPTDI]);
905	}
906
907	pte = pmap_pte(pmap, va);
908	opa = pmap_pte_pa(pte);
909#ifdef DEBUG
910	if (pmapdebug & PDB_ENTER)
911		printf("enter: pte %x, *pte %x ", pte, *(int *)pte);
912#endif
913
914	/*
915	 * Mapping has not changed, must be protection or wiring change.
916	 */
917	if (opa == pa) {
918#ifdef DEBUG
919		enter_stats.pwchange++;
920#endif
921		/*
922		 * Wiring change, just update stats.
923		 * We don't worry about wiring PT pages as they remain
924		 * resident as long as there are valid mappings in them.
925		 * Hence, if a user page is wired, the PT page will be also.
926		 */
927		if (wired && !pmap_pte_w(pte) || !wired && pmap_pte_w(pte)) {
928#ifdef DEBUG
929			if (pmapdebug & PDB_ENTER)
930				pg("enter: wiring change -> %x ", wired);
931#endif
932			if (wired)
933				pmap->pm_stats.wired_count++;
934			else
935				pmap->pm_stats.wired_count--;
936#ifdef DEBUG
937			enter_stats.wchange++;
938#endif
939		}
940		goto validate;
941	}
942
943	/*
944	 * Mapping has changed, invalidate old range and fall through to
945	 * handle validating new mapping.
946	 */
947	if (opa) {
948#ifdef DEBUG
949		if (pmapdebug & PDB_ENTER)
950			printf("enter: removing old mapping %x pa %x ", va, opa);
951#endif
952		pmap_remove(pmap, va, va + PAGE_SIZE);
953#ifdef DEBUG
954		enter_stats.mchange++;
955#endif
956	}
957
958	/*
959	 * Enter on the PV list if part of our managed memory
960	 * Note that we raise IPL while manipulating pv_table
961	 * since pmap_enter can be called at interrupt time.
962	 */
963	if (pa >= vm_first_phys && pa < vm_last_phys) {
964		register pv_entry_t pv, npv;
965		int s;
966
967#ifdef DEBUG
968		enter_stats.managed++;
969#endif
970		pv = pa_to_pvh(pa);
971		s = splimp();
972#ifdef DEBUG
973		if (pmapdebug & PDB_ENTER)
974			printf("enter: pv at %x: %x/%x/%x ",
975			       pv, pv->pv_va, pv->pv_pmap, pv->pv_next);
976#endif
977		/*
978		 * No entries yet, use header as the first entry
979		 */
980		if (pv->pv_pmap == NULL) {
981#ifdef DEBUG
982			enter_stats.firstpv++;
983#endif
984			pv->pv_va = va;
985			pv->pv_pmap = pmap;
986			pv->pv_next = NULL;
987			pv->pv_flags = 0;
988		}
989		/*
990		 * There is at least one other VA mapping this page.
991		 * Place this entry after the header.
992		 */
993		else {
994			/*printf("second time: ");*/
995#ifdef DEBUG
996			for (npv = pv; npv; npv = npv->pv_next)
997				if (pmap == npv->pv_pmap && va == npv->pv_va)
998					panic("pmap_enter: already in pv_tab");
999#endif
1000			npv = (pv_entry_t)
1001				malloc(sizeof *npv, M_VMPVENT, M_NOWAIT);
1002			npv->pv_va = va;
1003			npv->pv_pmap = pmap;
1004			npv->pv_next = pv->pv_next;
1005			pv->pv_next = npv;
1006#ifdef DEBUG
1007			if (!npv->pv_next)
1008				enter_stats.secondpv++;
1009#endif
1010		}
1011		splx(s);
1012	}
1013	/*
1014	 * Assumption: if it is not part of our managed memory
1015	 * then it must be device memory which may be volitile.
1016	 */
1017	if (pmap_initialized) {
1018		checkpv = cacheable = FALSE;
1019#ifdef DEBUG
1020		enter_stats.unmanaged++;
1021#endif
1022	}
1023
1024	/*
1025	 * Increment counters
1026	 */
1027	pmap->pm_stats.resident_count++;
1028	if (wired)
1029		pmap->pm_stats.wired_count++;
1030
1031validate:
1032	/*
1033	 * Now validate mapping with desired protection/wiring.
1034	 * Assume uniform modified and referenced status for all
1035	 * I386 pages in a MACH page.
1036	 */
1037	npte = (pa & PG_FRAME) | pte_prot(pmap, prot) | PG_V;
1038	npte |= (*(int *)pte & (PG_M|PG_U));
1039	if (wired)
1040		npte |= PG_W;
1041	if(va < UPT_MIN_ADDRESS)
1042		npte |= PG_u;
1043	else if(va < UPT_MAX_ADDRESS)
1044		npte |= PG_u | PG_RW;
1045#ifdef DEBUG
1046	if (pmapdebug & PDB_ENTER)
1047		printf("enter: new pte value %x ", npte);
1048#endif
1049	ix = 0;
1050	do {
1051		*(int *)pte++ = npte;
1052		/*TBIS(va);*/
1053		npte += I386_PAGE_SIZE;
1054		va += I386_PAGE_SIZE;
1055	} while (++ix != i386pagesperpage);
1056	pte--;
1057#ifdef DEBUGx
1058cache, tlb flushes
1059#endif
1060/*pads(pmap);*/
1061	/*load_cr3(((struct pcb *)curproc->p_addr)->pcb_ptd);*/
1062	tlbflush();
1063}
1064
1065/*
1066 *      pmap_page_protect:
1067 *
1068 *      Lower the permission for all mappings to a given page.
1069 */
1070void
1071pmap_page_protect(phys, prot)
1072        vm_offset_t     phys;
1073        vm_prot_t       prot;
1074{
1075        switch (prot) {
1076        case VM_PROT_READ:
1077        case VM_PROT_READ|VM_PROT_EXECUTE:
1078                pmap_copy_on_write(phys);
1079                break;
1080        case VM_PROT_ALL:
1081                break;
1082        default:
1083                pmap_remove_all(phys);
1084                break;
1085        }
1086}
1087
1088/*
1089 *	Routine:	pmap_change_wiring
1090 *	Function:	Change the wiring attribute for a map/virtual-address
1091 *			pair.
1092 *	In/out conditions:
1093 *			The mapping must already exist in the pmap.
1094 */
1095void
1096pmap_change_wiring(pmap, va, wired)
1097	register pmap_t	pmap;
1098	vm_offset_t	va;
1099	boolean_t	wired;
1100{
1101	register pt_entry_t *pte;
1102	register int ix;
1103
1104#ifdef DEBUG
1105	if (pmapdebug & PDB_FOLLOW)
1106		printf("pmap_change_wiring(%x, %x, %x)", pmap, va, wired);
1107#endif
1108	if (pmap == NULL)
1109		return;
1110
1111	pte = pmap_pte(pmap, va);
1112#ifdef DEBUG
1113	/*
1114	 * Page table page is not allocated.
1115	 * Should this ever happen?  Ignore it for now,
1116	 * we don't want to force allocation of unnecessary PTE pages.
1117	 */
1118	if (!pmap_pde_v(pmap_pde(pmap, va))) {
1119		if (pmapdebug & PDB_PARANOIA)
1120			pg("pmap_change_wiring: invalid PDE for %x ", va);
1121		return;
1122	}
1123	/*
1124	 * Page not valid.  Should this ever happen?
1125	 * Just continue and change wiring anyway.
1126	 */
1127	if (!pmap_pte_v(pte)) {
1128		if (pmapdebug & PDB_PARANOIA)
1129			pg("pmap_change_wiring: invalid PTE for %x ", va);
1130	}
1131#endif
1132	if (wired && !pmap_pte_w(pte) || !wired && pmap_pte_w(pte)) {
1133		if (wired)
1134			pmap->pm_stats.wired_count++;
1135		else
1136			pmap->pm_stats.wired_count--;
1137	}
1138	/*
1139	 * Wiring is not a hardware characteristic so there is no need
1140	 * to invalidate TLB.
1141	 */
1142	ix = 0;
1143	do {
1144		pmap_pte_set_w(pte++, wired);
1145	} while (++ix != i386pagesperpage);
1146}
1147
1148/*
1149 *	Routine:	pmap_pte
1150 *	Function:
1151 *		Extract the page table entry associated
1152 *		with the given map/virtual_address pair.
1153 * [ what about induced faults -wfj]
1154 */
1155
1156struct pte *pmap_pte(pmap, va)
1157	register pmap_t	pmap;
1158	vm_offset_t va;
1159{
1160
1161#ifdef DEBUGx
1162	if (pmapdebug & PDB_FOLLOW)
1163		printf("pmap_pte(%x, %x) ->\n", pmap, va);
1164#endif
1165	if (pmap && pmap_pde_v(pmap_pde(pmap, va))) {
1166
1167		/* are we current address space or kernel? */
1168		if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum
1169			|| pmap == kernel_pmap)
1170			return ((struct pte *) vtopte(va));
1171
1172		/* otherwise, we are alternate address space */
1173		else {
1174			if (pmap->pm_pdir[PTDPTDI].pd_pfnum
1175				!= APTDpde.pd_pfnum) {
1176				APTDpde = pmap->pm_pdir[PTDPTDI];
1177				tlbflush();
1178			}
1179			return((struct pte *) avtopte(va));
1180		}
1181	}
1182	return(0);
1183}
1184
1185/*
1186 *	Routine:	pmap_extract
1187 *	Function:
1188 *		Extract the physical page address associated
1189 *		with the given map/virtual_address pair.
1190 */
1191
1192vm_offset_t
1193pmap_extract(pmap, va)
1194	register pmap_t	pmap;
1195	vm_offset_t va;
1196{
1197	register vm_offset_t pa;
1198
1199#ifdef DEBUGx
1200	if (pmapdebug & PDB_FOLLOW)
1201		pg("pmap_extract(%x, %x) -> ", pmap, va);
1202#endif
1203	pa = 0;
1204	if (pmap && pmap_pde_v(pmap_pde(pmap, va))) {
1205		pa = *(int *) pmap_pte(pmap, va);
1206	}
1207	if (pa)
1208		pa = (pa & PG_FRAME) | (va & ~PG_FRAME);
1209#ifdef DEBUGx
1210	if (pmapdebug & PDB_FOLLOW)
1211		printf("%x\n", pa);
1212#endif
1213	return(pa);
1214}
1215
1216/*
1217 *	Copy the range specified by src_addr/len
1218 *	from the source map to the range dst_addr/len
1219 *	in the destination map.
1220 *
1221 *	This routine is only advisory and need not do anything.
1222 */
1223void pmap_copy(dst_pmap, src_pmap, dst_addr, len, src_addr)
1224	pmap_t		dst_pmap;
1225	pmap_t		src_pmap;
1226	vm_offset_t	dst_addr;
1227	vm_size_t	len;
1228	vm_offset_t	src_addr;
1229{
1230#ifdef DEBUG
1231	if (pmapdebug & PDB_FOLLOW)
1232		printf("pmap_copy(%x, %x, %x, %x, %x)",
1233		       dst_pmap, src_pmap, dst_addr, len, src_addr);
1234#endif
1235}
1236
1237/*
1238 *	Require that all active physical maps contain no
1239 *	incorrect entries NOW.  [This update includes
1240 *	forcing updates of any address map caching.]
1241 *
1242 *	Generally used to insure that a thread about
1243 *	to run will see a semantically correct world.
1244 */
1245void pmap_update()
1246{
1247#ifdef DEBUG
1248	if (pmapdebug & PDB_FOLLOW)
1249		printf("pmap_update()");
1250#endif
1251	tlbflush();
1252}
1253
1254/*
1255 *	Routine:	pmap_collect
1256 *	Function:
1257 *		Garbage collects the physical map system for
1258 *		pages which are no longer used.
1259 *		Success need not be guaranteed -- that is, there
1260 *		may well be pages which are not referenced, but
1261 *		others may be collected.
1262 *	Usage:
1263 *		Called by the pageout daemon when pages are scarce.
1264 * [ needs to be written -wfj ]
1265 */
1266void
1267pmap_collect(pmap)
1268	pmap_t		pmap;
1269{
1270	register vm_offset_t pa;
1271	register pv_entry_t pv;
1272	register int *pte;
1273	vm_offset_t kpa;
1274	int s;
1275
1276#ifdef DEBUG
1277	int *pde;
1278	int opmapdebug;
1279	printf("pmap_collect(%x) ", pmap);
1280#endif
1281	if (pmap != kernel_pmap)
1282		return;
1283
1284}
1285
1286/* [ macro again?, should I force kstack into user map here? -wfj ] */
1287void
1288pmap_activate(pmap, pcbp)
1289	register pmap_t pmap;
1290	struct pcb *pcbp;
1291{
1292int x;
1293#ifdef DEBUG
1294	if (pmapdebug & (PDB_FOLLOW|PDB_PDRTAB))
1295		pg("pmap_activate(%x, %x) ", pmap, pcbp);
1296#endif
1297	PMAP_ACTIVATE(pmap, pcbp);
1298/*printf("pde ");
1299for(x=0x3f6; x < 0x3fA; x++)
1300	printf("%x ", pmap->pm_pdir[x]);*/
1301/*pads(pmap);*/
1302/*pg(" pcb_cr3 %x", pcbp->pcb_cr3);*/
1303}
1304
1305/*
1306 *	Routine:	pmap_kernel
1307 *	Function:
1308 *		Returns the physical map handle for the kernel.
1309 */
1310pmap_t
1311pmap_kernel()
1312{
1313    	return (kernel_pmap);
1314}
1315
1316/*
1317 *	pmap_zero_page zeros the specified (machine independent)
1318 *	page by mapping the page into virtual memory and using
1319 *	bzero to clear its contents, one machine dependent page
1320 *	at a time.
1321 */
1322pmap_zero_page(phys)
1323	register vm_offset_t	phys;
1324{
1325	register int ix;
1326
1327#ifdef DEBUG
1328	if (pmapdebug & PDB_FOLLOW)
1329		printf("pmap_zero_page(%x)", phys);
1330#endif
1331	phys >>= PG_SHIFT;
1332	ix = 0;
1333	do {
1334		clearseg(phys++);
1335	} while (++ix != i386pagesperpage);
1336}
1337
1338/*
1339 *	pmap_copy_page copies the specified (machine independent)
1340 *	page by mapping the page into virtual memory and using
1341 *	bcopy to copy the page, one machine dependent page at a
1342 *	time.
1343 */
1344pmap_copy_page(src, dst)
1345	register vm_offset_t	src, dst;
1346{
1347	register int ix;
1348
1349#ifdef DEBUG
1350	if (pmapdebug & PDB_FOLLOW)
1351		printf("pmap_copy_page(%x, %x)", src, dst);
1352#endif
1353	src >>= PG_SHIFT;
1354	dst >>= PG_SHIFT;
1355	ix = 0;
1356	do {
1357		physcopyseg(src++, dst++);
1358	} while (++ix != i386pagesperpage);
1359}
1360
1361
1362/*
1363 *	Routine:	pmap_pageable
1364 *	Function:
1365 *		Make the specified pages (by pmap, offset)
1366 *		pageable (or not) as requested.
1367 *
1368 *		A page which is not pageable may not take
1369 *		a fault; therefore, its page table entry
1370 *		must remain valid for the duration.
1371 *
1372 *		This routine is merely advisory; pmap_enter
1373 *		will specify that these pages are to be wired
1374 *		down (or not) as appropriate.
1375 */
1376pmap_pageable(pmap, sva, eva, pageable)
1377	pmap_t		pmap;
1378	vm_offset_t	sva, eva;
1379	boolean_t	pageable;
1380{
1381#ifdef DEBUG
1382	if (pmapdebug & PDB_FOLLOW)
1383		printf("pmap_pageable(%x, %x, %x, %x)",
1384		       pmap, sva, eva, pageable);
1385#endif
1386	/*
1387	 * If we are making a PT page pageable then all valid
1388	 * mappings must be gone from that page.  Hence it should
1389	 * be all zeros and there is no need to clean it.
1390	 * Assumptions:
1391	 *	- we are called with only one page at a time
1392	 *	- PT pages have only one pv_table entry
1393	 */
1394	if (pmap == kernel_pmap && pageable && sva + PAGE_SIZE == eva) {
1395		register pv_entry_t pv;
1396		register vm_offset_t pa;
1397
1398#ifdef DEBUG
1399		if ((pmapdebug & (PDB_FOLLOW|PDB_PTPAGE)) == PDB_PTPAGE)
1400			printf("pmap_pageable(%x, %x, %x, %x)",
1401			       pmap, sva, eva, pageable);
1402#endif
1403		/*if (!pmap_pde_v(pmap_pde(pmap, sva)))
1404			return;*/
1405		if(pmap_pte(pmap, sva) == 0)
1406			return;
1407		pa = pmap_pte_pa(pmap_pte(pmap, sva));
1408		if (pa < vm_first_phys || pa >= vm_last_phys)
1409			return;
1410		pv = pa_to_pvh(pa);
1411		/*if (!ispt(pv->pv_va))
1412			return;*/
1413#ifdef DEBUG
1414		if (pv->pv_va != sva || pv->pv_next) {
1415			pg("pmap_pageable: bad PT page va %x next %x\n",
1416			       pv->pv_va, pv->pv_next);
1417			return;
1418		}
1419#endif
1420		/*
1421		 * Mark it unmodified to avoid pageout
1422		 */
1423		pmap_clear_modify(pa);
1424#ifdef needsomethinglikethis
1425		if (pmapdebug & PDB_PTPAGE)
1426			pg("pmap_pageable: PT page %x(%x) unmodified\n",
1427			       sva, *(int *)pmap_pte(pmap, sva));
1428		if (pmapdebug & PDB_WIRING)
1429			pmap_check_wiring("pageable", sva);
1430#endif
1431	}
1432}
1433
1434/*
1435 *	Clear the modify bits on the specified physical page.
1436 */
1437
1438void
1439pmap_clear_modify(pa)
1440	vm_offset_t	pa;
1441{
1442#ifdef DEBUG
1443	if (pmapdebug & PDB_FOLLOW)
1444		printf("pmap_clear_modify(%x)", pa);
1445#endif
1446	pmap_changebit(pa, PG_M, FALSE);
1447}
1448
1449/*
1450 *	pmap_clear_reference:
1451 *
1452 *	Clear the reference bit on the specified physical page.
1453 */
1454
1455void pmap_clear_reference(pa)
1456	vm_offset_t	pa;
1457{
1458#ifdef DEBUG
1459	if (pmapdebug & PDB_FOLLOW)
1460		printf("pmap_clear_reference(%x)", pa);
1461#endif
1462	pmap_changebit(pa, PG_U, FALSE);
1463}
1464
1465/*
1466 *	pmap_is_referenced:
1467 *
1468 *	Return whether or not the specified physical page is referenced
1469 *	by any physical maps.
1470 */
1471
1472boolean_t
1473pmap_is_referenced(pa)
1474	vm_offset_t	pa;
1475{
1476#ifdef DEBUG
1477	if (pmapdebug & PDB_FOLLOW) {
1478		boolean_t rv = pmap_testbit(pa, PG_U);
1479		printf("pmap_is_referenced(%x) -> %c", pa, "FT"[rv]);
1480		return(rv);
1481	}
1482#endif
1483	return(pmap_testbit(pa, PG_U));
1484}
1485
1486/*
1487 *	pmap_is_modified:
1488 *
1489 *	Return whether or not the specified physical page is modified
1490 *	by any physical maps.
1491 */
1492
1493boolean_t
1494pmap_is_modified(pa)
1495	vm_offset_t	pa;
1496{
1497#ifdef DEBUG
1498	if (pmapdebug & PDB_FOLLOW) {
1499		boolean_t rv = pmap_testbit(pa, PG_M);
1500		printf("pmap_is_modified(%x) -> %c", pa, "FT"[rv]);
1501		return(rv);
1502	}
1503#endif
1504	return(pmap_testbit(pa, PG_M));
1505}
1506
1507vm_offset_t
1508pmap_phys_address(ppn)
1509	int ppn;
1510{
1511	return(i386_ptob(ppn));
1512}
1513
1514/*
1515 * Miscellaneous support routines follow
1516 */
1517
1518i386_protection_init()
1519{
1520	register int *kp, prot;
1521
1522	kp = protection_codes;
1523	for (prot = 0; prot < 8; prot++) {
1524		switch (prot) {
1525		case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_NONE:
1526			*kp++ = 0;
1527			break;
1528		case VM_PROT_READ | VM_PROT_NONE | VM_PROT_NONE:
1529		case VM_PROT_READ | VM_PROT_NONE | VM_PROT_EXECUTE:
1530		case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_EXECUTE:
1531			*kp++ = PG_RO;
1532			break;
1533		case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_NONE:
1534		case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_EXECUTE:
1535		case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_NONE:
1536		case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE:
1537			*kp++ = PG_RW;
1538			break;
1539		}
1540	}
1541}
1542
1543boolean_t
1544pmap_testbit(pa, bit)
1545	register vm_offset_t pa;
1546	int bit;
1547{
1548	register pv_entry_t pv;
1549	register int *pte, ix;
1550	int s;
1551
1552	if (pa < vm_first_phys || pa >= vm_last_phys)
1553		return(FALSE);
1554
1555	pv = pa_to_pvh(pa);
1556	s = splimp();
1557	/*
1558	 * Check saved info first
1559	 */
1560	if (pmap_attributes[pa_index(pa)] & bit) {
1561		splx(s);
1562		return(TRUE);
1563	}
1564	/*
1565	 * Not found, check current mappings returning
1566	 * immediately if found.
1567	 */
1568	if (pv->pv_pmap != NULL) {
1569		for (; pv; pv = pv->pv_next) {
1570			pte = (int *) pmap_pte(pv->pv_pmap, pv->pv_va);
1571			ix = 0;
1572			do {
1573				if (*pte++ & bit) {
1574					splx(s);
1575					return(TRUE);
1576				}
1577			} while (++ix != i386pagesperpage);
1578		}
1579	}
1580	splx(s);
1581	return(FALSE);
1582}
1583
1584pmap_changebit(pa, bit, setem)
1585	register vm_offset_t pa;
1586	int bit;
1587	boolean_t setem;
1588{
1589	register pv_entry_t pv;
1590	register int *pte, npte, ix;
1591	vm_offset_t va;
1592	int s;
1593	boolean_t firstpage = TRUE;
1594
1595#ifdef DEBUG
1596	if (pmapdebug & PDB_BITS)
1597		printf("pmap_changebit(%x, %x, %s)",
1598		       pa, bit, setem ? "set" : "clear");
1599#endif
1600	if (pa < vm_first_phys || pa >= vm_last_phys)
1601		return;
1602
1603	pv = pa_to_pvh(pa);
1604	s = splimp();
1605	/*
1606	 * Clear saved attributes (modify, reference)
1607	 */
1608	if (!setem)
1609		pmap_attributes[pa_index(pa)] &= ~bit;
1610	/*
1611	 * Loop over all current mappings setting/clearing as appropos
1612	 * If setting RO do we need to clear the VAC?
1613	 */
1614	if (pv->pv_pmap != NULL) {
1615#ifdef DEBUG
1616		int toflush = 0;
1617#endif
1618		for (; pv; pv = pv->pv_next) {
1619#ifdef DEBUG
1620			toflush |= (pv->pv_pmap == kernel_pmap) ? 2 : 1;
1621#endif
1622			va = pv->pv_va;
1623
1624                        /*
1625                         * XXX don't write protect pager mappings
1626                         */
1627                        if (bit == PG_RO) {
1628                                extern vm_offset_t pager_sva, pager_eva;
1629
1630                                if (va >= pager_sva && va < pager_eva)
1631                                        continue;
1632                        }
1633
1634			pte = (int *) pmap_pte(pv->pv_pmap, va);
1635			ix = 0;
1636			do {
1637				if (setem)
1638					npte = *pte | bit;
1639				else
1640					npte = *pte & ~bit;
1641				if (*pte != npte) {
1642					*pte = npte;
1643					/*TBIS(va);*/
1644				}
1645				va += I386_PAGE_SIZE;
1646				pte++;
1647			} while (++ix != i386pagesperpage);
1648
1649			if (curproc && pv->pv_pmap == &curproc->p_vmspace->vm_pmap)
1650				pmap_activate(pv->pv_pmap, (struct pcb *)curproc->p_addr);
1651		}
1652#ifdef somethinglikethis
1653		if (setem && bit == PG_RO && (pmapvacflush & PVF_PROTECT)) {
1654			if ((pmapvacflush & PVF_TOTAL) || toflush == 3)
1655				DCIA();
1656			else if (toflush == 2)
1657				DCIS();
1658			else
1659				DCIU();
1660		}
1661#endif
1662	}
1663	splx(s);
1664}
1665
1666#ifdef DEBUG
1667pmap_pvdump(pa)
1668	vm_offset_t pa;
1669{
1670	register pv_entry_t pv;
1671
1672	printf("pa %x", pa);
1673	for (pv = pa_to_pvh(pa); pv; pv = pv->pv_next) {
1674		printf(" -> pmap %x, va %x, flags %x",
1675		       pv->pv_pmap, pv->pv_va, pv->pv_flags);
1676		pads(pv->pv_pmap);
1677	}
1678	printf(" ");
1679}
1680
1681#ifdef notyet
1682pmap_check_wiring(str, va)
1683	char *str;
1684	vm_offset_t va;
1685{
1686	vm_map_entry_t entry;
1687	register int count, *pte;
1688
1689	va = trunc_page(va);
1690	if (!pmap_pde_v(pmap_pde(kernel_pmap, va)) ||
1691	    !pmap_pte_v(pmap_pte(kernel_pmap, va)))
1692		return;
1693
1694	if (!vm_map_lookup_entry(pt_map, va, &entry)) {
1695		pg("wired_check: entry for %x not found\n", va);
1696		return;
1697	}
1698	count = 0;
1699	for (pte = (int *)va; pte < (int *)(va+PAGE_SIZE); pte++)
1700		if (*pte)
1701			count++;
1702	if (entry->wired_count != count)
1703		pg("*%s*: %x: w%d/a%d\n",
1704		       str, va, entry->wired_count, count);
1705}
1706#endif
1707
1708/* print address space of pmap*/
1709pads(pm) pmap_t pm; {
1710	unsigned va, i, j;
1711	struct pte *ptep;
1712
1713	if(pm == kernel_pmap) return;
1714	for (i = 0; i < 1024; i++)
1715		if(pm->pm_pdir[i].pd_v)
1716			for (j = 0; j < 1024 ; j++) {
1717				va = (i<<22)+(j<<12);
1718				if (pm == kernel_pmap && va < 0xfe000000)
1719						continue;
1720				if (pm != kernel_pmap && va > UPT_MAX_ADDRESS)
1721						continue;
1722				ptep = pmap_pte(pm, va);
1723				if(pmap_pte_v(ptep))
1724					printf("%x:%x ", va, *(int *)ptep);
1725			} ;
1726
1727}
1728#endif
1729