KERNEL SPEEDUP #1
[unix-history] / usr / src / sys.386bsd / i386 / i386 / pmap.c
CommitLineData
1b68e56d
WJ
1/*
2 * Copyright (c) 1991 Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * the Systems Programming Group of the University of Utah Computer
7 * Science Department and William Jolitz of UUNET Technologies Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 * @(#)pmap.c 7.7 (Berkeley) 5/12/91
58c5bdc7
PHK
38 *
39 * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
40 * -------------------- ----- ----------------------
41 * CURRENT PATCH LEVEL: 1 00063
42 * -------------------- ----- ----------------------
43 *
44 * 28 Nov 1991 Poul-Henning Kamp Speedup processing.
1b68e56d
WJ
45 */
46static 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 $";
47
48/*
49 * Derived from hp300 version by Mike Hibler, this version by William
50 * Jolitz uses a recursive map [a pde points to the page directory] to
51 * map the page tables using the pagetables themselves. This is done to
52 * reduce the impact on kernel virtual memory for lots of sparse address
53 * space, and to reduce the cost of memory to each process.
54 *
55 * Derived from: hp300/@(#)pmap.c 7.1 (Berkeley) 12/5/90
56 */
57
58/*
59 * Reno i386 version, from Mike Hibler's hp300 version.
60 */
61
62/*
63 * Manages physical address maps.
64 *
65 * In addition to hardware address maps, this
66 * module is called upon to provide software-use-only
67 * maps which may or may not be stored in the same
68 * form as hardware maps. These pseudo-maps are
69 * used to store intermediate results from copy
70 * operations to and from address spaces.
71 *
72 * Since the information managed by this module is
73 * also stored by the logical address mapping module,
74 * this module may throw away valid virtual-to-physical
75 * mappings at almost any time. However, invalidations
76 * of virtual-to-physical mappings must be done as
77 * requested.
78 *
79 * In order to cope with hardware architectures which
80 * make virtual-to-physical map invalidates expensive,
81 * this module may delay invalidate or reduced protection
82 * operations until such time as they are actually
83 * necessary. This module is given full information as
84 * to which processors are currently using which maps,
85 * and to when physical maps must be made correct.
86 */
87
88#include "param.h"
89#include "proc.h"
90#include "malloc.h"
91#include "user.h"
92
93#include "vm/vm.h"
94#include "vm/vm_kern.h"
95#include "vm/vm_page.h"
96/*#include "vm/vm_pageout.h"*/
97
98#include "i386/isa/isa.h"
99
100/*
101 * Allocate various and sundry SYSMAPs used in the days of old VM
102 * and not yet converted. XXX.
103 */
104#define BSDVM_COMPAT 1
105
106#ifdef DEBUG
107struct {
108 int kernel; /* entering kernel mapping */
109 int user; /* entering user mapping */
110 int ptpneeded; /* needed to allocate a PT page */
111 int pwchange; /* no mapping change, just wiring or protection */
112 int wchange; /* no mapping change, just wiring */
113 int mchange; /* was mapped but mapping to different page */
114 int managed; /* a managed page */
115 int firstpv; /* first mapping for this PA */
116 int secondpv; /* second mapping for this PA */
117 int ci; /* cache inhibited */
118 int unmanaged; /* not a managed page */
119 int flushes; /* cache flushes */
120} enter_stats;
121struct {
122 int calls;
123 int removes;
124 int pvfirst;
125 int pvsearch;
126 int ptinvalid;
127 int uflushes;
128 int sflushes;
129} remove_stats;
130
131int debugmap = 0;
132int pmapdebug = 0 /* 0xffff */;
133#define PDB_FOLLOW 0x0001
134#define PDB_INIT 0x0002
135#define PDB_ENTER 0x0004
136#define PDB_REMOVE 0x0008
137#define PDB_CREATE 0x0010
138#define PDB_PTPAGE 0x0020
139#define PDB_CACHE 0x0040
140#define PDB_BITS 0x0080
141#define PDB_COLLECT 0x0100
142#define PDB_PROTECT 0x0200
143#define PDB_PDRTAB 0x0400
144#define PDB_PARANOIA 0x2000
145#define PDB_WIRING 0x4000
146#define PDB_PVDUMP 0x8000
147
148int pmapvacflush = 0;
149#define PVF_ENTER 0x01
150#define PVF_REMOVE 0x02
151#define PVF_PROTECT 0x04
152#define PVF_TOTAL 0x80
153#endif
154
155/*
156 * Get PDEs and PTEs for user/kernel address space
157 */
158#define pmap_pde(m, v) (&((m)->pm_pdir[((vm_offset_t)(v) >> PD_SHIFT)&1023]))
159
160#define pmap_pte_pa(pte) (*(int *)(pte) & PG_FRAME)
161
162#define pmap_pde_v(pte) ((pte)->pd_v)
163#define pmap_pte_w(pte) ((pte)->pg_w)
164/* #define pmap_pte_ci(pte) ((pte)->pg_ci) */
165#define pmap_pte_m(pte) ((pte)->pg_m)
166#define pmap_pte_u(pte) ((pte)->pg_u)
167#define pmap_pte_v(pte) ((pte)->pg_v)
168#define pmap_pte_set_w(pte, v) ((pte)->pg_w = (v))
169#define pmap_pte_set_prot(pte, v) ((pte)->pg_prot = (v))
170
171/*
172 * Given a map and a machine independent protection code,
173 * convert to a vax protection code.
174 */
175#define pte_prot(m, p) (protection_codes[p])
176int protection_codes[8];
177
178struct pmap kernel_pmap_store;
179pmap_t kernel_pmap;
180
181vm_offset_t avail_start; /* PA of first available physical page */
182vm_offset_t avail_end; /* PA of last available physical page */
183vm_size_t mem_size; /* memory size in bytes */
184vm_offset_t virtual_avail; /* VA of first avail page (after kernel bss)*/
185vm_offset_t virtual_end; /* VA of last avail page (end of kernel AS) */
186vm_offset_t vm_first_phys; /* PA of first managed page */
187vm_offset_t vm_last_phys; /* PA just past last managed page */
188int i386pagesperpage; /* PAGE_SIZE / I386_PAGE_SIZE */
189boolean_t pmap_initialized = FALSE; /* Has pmap_init completed? */
190char *pmap_attributes; /* reference and modify bits */
191
192boolean_t pmap_testbit();
193void pmap_clear_modify();
194
195#if BSDVM_COMPAT
196#include "msgbuf.h"
197
198/*
199 * All those kernel PT submaps that BSD is so fond of
200 */
201struct pte *CMAP1, *CMAP2, *mmap;
202caddr_t CADDR1, CADDR2, vmmap;
203struct pte *msgbufmap;
204struct msgbuf *msgbufp;
205#endif
206
207/*
208 * Bootstrap the system enough to run with virtual memory.
209 * Map the kernel's code and data, and allocate the system page table.
210 *
211 * On the I386 this is called after mapping has already been enabled
212 * and just syncs the pmap module with what has already been done.
213 * [We can't call it easily with mapping off since the kernel is not
214 * mapped with PA == VA, hence we would have to relocate every address
215 * from the linked base (virtual) address 0xFE000000 to the actual
216 * (physical) address starting relative to 0]
217 */
218struct pte *pmap_pte();
219
220void
221pmap_bootstrap(firstaddr, loadaddr)
222 vm_offset_t firstaddr;
223 vm_offset_t loadaddr;
224{
225#if BSDVM_COMPAT
226 vm_offset_t va;
227 struct pte *pte;
228#endif
229 extern vm_offset_t maxmem, physmem;
230extern int IdlePTD;
231
232 avail_start = firstaddr;
233 avail_end = maxmem << PG_SHIFT;
234
235 /* XXX: allow for msgbuf */
236 avail_end -= i386_round_page(sizeof(struct msgbuf));
237
238 mem_size = physmem << PG_SHIFT;
239 virtual_avail = (vm_offset_t)atdevbase + 0x100000 - 0xa0000 + 10*NBPG;
240 virtual_end = VM_MAX_KERNEL_ADDRESS;
241 i386pagesperpage = PAGE_SIZE / I386_PAGE_SIZE;
242
243 /*
244 * Initialize protection array.
245 */
246 i386_protection_init();
247
248 /*
249 * The kernel's pmap is statically allocated so we don't
250 * have to use pmap_create, which is unlikely to work
251 * correctly at this part of the boot sequence.
252 */
253 kernel_pmap = &kernel_pmap_store;
254
255#ifdef notdef
256 /*
257 * Create Kernel page directory table and page maps.
258 * [ currently done in locore. i have wild and crazy ideas -wfj ]
259 */
260 bzero(firstaddr, 4*NBPG);
261 kernel_pmap->pm_pdir = firstaddr + VM_MIN_KERNEL_ADDRESS;
262 kernel_pmap->pm_ptab = firstaddr + VM_MIN_KERNEL_ADDRESS + NBPG;
263
264 firstaddr += NBPG;
265 for (x = i386_btod(VM_MIN_KERNEL_ADDRESS);
266 x < i386_btod(VM_MIN_KERNEL_ADDRESS)+3; x++) {
267 struct pde *pde;
268 pde = kernel_pmap->pm_pdir + x;
269 *(int *)pde = firstaddr + x*NBPG | PG_V | PG_KW;
270 }
271#else
272 kernel_pmap->pm_pdir = (pd_entry_t *)(0xfe000000 + IdlePTD);
273#endif
274
275
276 simple_lock_init(&kernel_pmap->pm_lock);
277 kernel_pmap->pm_count = 1;
278
279#if BSDVM_COMPAT
280 /*
281 * Allocate all the submaps we need
282 */
283#define SYSMAP(c, p, v, n) \
284 v = (c)va; va += ((n)*I386_PAGE_SIZE); p = pte; pte += (n);
285
286 va = virtual_avail;
287 pte = pmap_pte(kernel_pmap, va);
288
289 SYSMAP(caddr_t ,CMAP1 ,CADDR1 ,1 )
290 SYSMAP(caddr_t ,CMAP2 ,CADDR2 ,1 )
291 SYSMAP(caddr_t ,mmap ,vmmap ,1 )
292 SYSMAP(struct msgbuf * ,msgbufmap ,msgbufp ,1 )
293 virtual_avail = va;
294#endif
295 /*
296 * reserve special hunk of memory for use by bus dma as a bounce
297 * buffer (contiguous virtual *and* physical memory). for now,
298 * assume vm does not use memory beneath hole, and we know that
299 * the bootstrap uses top 32k of base memory. -wfj
300 */
301 {
302 extern vm_offset_t isaphysmem;
303 isaphysmem = va;
304
305 virtual_avail = pmap_map(va, 0xa0000 - 32*1024, 0xa0000, VM_PROT_ALL);
306 }
307
308 *(int *)PTD = 0;
309 load_cr3(rcr3());
310
311}
312
313/*
314 * Initialize the pmap module.
315 * Called by vm_init, to initialize any structures that the pmap
316 * system needs to map virtual memory.
317 */
318void
319pmap_init(phys_start, phys_end)
320 vm_offset_t phys_start, phys_end;
321{
322 vm_offset_t addr, addr2;
323 vm_size_t npg, s;
324 int rv;
325 extern int KPTphys;
326
327#ifdef DEBUG
328 if (pmapdebug & PDB_FOLLOW)
329 printf("pmap_init(%x, %x)\n", phys_start, phys_end);
330#endif
331 /*
332 * Now that kernel map has been allocated, we can mark as
333 * unavailable regions which we have mapped in locore.
334 */
335 addr = atdevbase;
336 (void) vm_map_find(kernel_map, NULL, (vm_offset_t) 0,
337 &addr, (0x100000-0xa0000), FALSE);
338
339 addr = (vm_offset_t) 0xfe000000+KPTphys/* *NBPG */;
340 vm_object_reference(kernel_object);
341 (void) vm_map_find(kernel_map, kernel_object, addr,
342 &addr, 2*NBPG, FALSE);
343
344 /*
345 * Allocate memory for random pmap data structures. Includes the
346 * pv_head_table and pmap_attributes.
347 */
348 npg = atop(phys_end - phys_start);
349 s = (vm_size_t) (sizeof(struct pv_entry) * npg + npg);
350 s = round_page(s);
351 addr = (vm_offset_t) kmem_alloc(kernel_map, s);
352 pv_table = (pv_entry_t) addr;
353 addr += sizeof(struct pv_entry) * npg;
354 pmap_attributes = (char *) addr;
355#ifdef DEBUG
356 if (pmapdebug & PDB_INIT)
357 printf("pmap_init: %x bytes (%x pgs): tbl %x attr %x\n",
358 s, npg, pv_table, pmap_attributes);
359#endif
360
361 /*
362 * Now it is safe to enable pv_table recording.
363 */
364 vm_first_phys = phys_start;
365 vm_last_phys = phys_end;
366 pmap_initialized = TRUE;
367}
368
369/*
370 * Used to map a range of physical addresses into kernel
371 * virtual address space.
372 *
373 * For now, VM is already on, we only need to map the
374 * specified memory.
375 */
376vm_offset_t
377pmap_map(virt, start, end, prot)
378 vm_offset_t virt;
379 vm_offset_t start;
380 vm_offset_t end;
381 int prot;
382{
383#ifdef DEBUG
384 if (pmapdebug & PDB_FOLLOW)
385 printf("pmap_map(%x, %x, %x, %x)\n", virt, start, end, prot);
386#endif
387 while (start < end) {
388 pmap_enter(kernel_pmap, virt, start, prot, FALSE);
389 virt += PAGE_SIZE;
390 start += PAGE_SIZE;
391 }
392 return(virt);
393}
394
395/*
396 * Create and return a physical map.
397 *
398 * If the size specified for the map
399 * is zero, the map is an actual physical
400 * map, and may be referenced by the
401 * hardware.
402 *
403 * If the size specified is non-zero,
404 * the map will be used in software only, and
405 * is bounded by that size.
406 *
407 * [ just allocate a ptd and mark it uninitialize -- should we track
408 * with a table which process has which ptd? -wfj ]
409 */
410
411pmap_t
412pmap_create(size)
413 vm_size_t size;
414{
415 register pmap_t pmap;
416
417#ifdef DEBUG
418 if (pmapdebug & (PDB_FOLLOW|PDB_CREATE))
419 printf("pmap_create(%x)\n", size);
420#endif
421 /*
422 * Software use map does not need a pmap
423 */
424 if (size)
425 return(NULL);
426
427 /* XXX: is it ok to wait here? */
428 pmap = (pmap_t) malloc(sizeof *pmap, M_VMPMAP, M_WAITOK);
429#ifdef notifwewait
430 if (pmap == NULL)
431 panic("pmap_create: cannot allocate a pmap");
432#endif
433 bzero(pmap, sizeof(*pmap));
434 pmap_pinit(pmap);
435 return (pmap);
436}
437
438/*
439 * Initialize a preallocated and zeroed pmap structure,
440 * such as one in a vmspace structure.
441 */
442void
443pmap_pinit(pmap)
444 register struct pmap *pmap;
445{
446
447#ifdef DEBUG
448 if (pmapdebug & (PDB_FOLLOW|PDB_CREATE))
449 pg("pmap_pinit(%x)\n", pmap);
450#endif
451
452 /*
453 * No need to allocate page table space yet but we do need a
454 * valid page directory table.
455 */
456 pmap->pm_pdir = (pd_entry_t *) kmem_alloc(kernel_map, NBPG);
457
458 /* wire in kernel global address entries */
459 bcopy(PTD+KPTDI_FIRST, pmap->pm_pdir+KPTDI_FIRST,
460 (KPTDI_LAST-KPTDI_FIRST+1)*4);
461
462 /* install self-referential address mapping entry */
463 *(int *)(pmap->pm_pdir+PTDPTDI) =
464 (int)pmap_extract(kernel_pmap, pmap->pm_pdir) | PG_V | PG_URKW;
465
466 pmap->pm_count = 1;
467 simple_lock_init(&pmap->pm_lock);
468}
469
470/*
471 * Retire the given physical map from service.
472 * Should only be called if the map contains
473 * no valid mappings.
474 */
475void
476pmap_destroy(pmap)
477 register pmap_t pmap;
478{
479 int count;
480
481#ifdef DEBUG
482 if (pmapdebug & PDB_FOLLOW)
483 printf("pmap_destroy(%x)\n", pmap);
484#endif
485 if (pmap == NULL)
486 return;
487
488 simple_lock(&pmap->pm_lock);
489 count = --pmap->pm_count;
490 simple_unlock(&pmap->pm_lock);
491 if (count == 0) {
492 pmap_release(pmap);
493 free((caddr_t)pmap, M_VMPMAP);
494 }
495}
496
497/*
498 * Release any resources held by the given physical map.
499 * Called when a pmap initialized by pmap_pinit is being released.
500 * Should only be called if the map contains no valid mappings.
501 */
502void
503pmap_release(pmap)
504 register struct pmap *pmap;
505{
506
507#ifdef DEBUG
508 if (pmapdebug & PDB_FOLLOW)
509 pg("pmap_release(%x)\n", pmap);
510#endif
511#ifdef notdef /* DIAGNOSTIC */
512 /* count would be 0 from pmap_destroy... */
513 simple_lock(&pmap->pm_lock);
514 if (pmap->pm_count != 1)
515 panic("pmap_release count");
516#endif
517 kmem_free(kernel_map, (vm_offset_t)pmap->pm_pdir, NBPG);
518}
519
520/*
521 * Add a reference to the specified pmap.
522 */
523void
524pmap_reference(pmap)
525 pmap_t pmap;
526{
527#ifdef DEBUG
528 if (pmapdebug & PDB_FOLLOW)
529 printf("pmap_reference(%x)", pmap);
530#endif
531 if (pmap != NULL) {
532 simple_lock(&pmap->pm_lock);
533 pmap->pm_count++;
534 simple_unlock(&pmap->pm_lock);
535 }
536}
537
538/*
539 * Remove the given range of addresses from the specified map.
540 *
541 * It is assumed that the start and end are properly
542 * rounded to the page size.
543 */
544void
545pmap_remove(pmap, sva, eva)
58c5bdc7
PHK
546 struct pmap *pmap;
547 register vm_offset_t sva;
548 register vm_offset_t eva;
1b68e56d 549{
58c5bdc7
PHK
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;
1b68e56d
WJ
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
58c5bdc7
PHK
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 }
1b68e56d
WJ
581#ifdef DEBUG
582 remove_stats.calls++;
583#endif
58c5bdc7
PHK
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++) {
1b68e56d
WJ
592 /*
593 * Weed out invalid mappings.
594 * Note: we assume that the page directory table is
595 * always allocated, and in kernel virtual.
596 */
58c5bdc7
PHK
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 ;
1b68e56d 612 continue;
58c5bdc7
PHK
613 }
614 }
615 if(!pmap_pte_pa(ptp+sva))
616 continue;
1b68e56d 617
58c5bdc7 618 pte = ptp + sva;
1b68e56d 619 pa = pmap_pte_pa(pte);
58c5bdc7 620 va = i386_ptob(sva);
1b68e56d
WJ
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;
58c5bdc7 789 register pt_entry_t *ptp;
1b68e56d
WJ
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
58c5bdc7
PHK
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 }
1b68e56d
WJ
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
58c5bdc7 833 pte = ptp + i386_btop(va);
1b68e56d
WJ
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