diff options
author | 2000-11-09 13:57:34 +0000 | |
---|---|---|
committer | 2000-11-09 13:57:34 +0000 | |
commit | bd6e9ca986f28d736414aa2f0528b1cda7f6e888 (patch) | |
tree | 7389c30f505618edc790b32d0aa78c8d09fee365 | |
parent | zap dead files. (diff) | |
download | wireguard-openbsd-bd6e9ca986f28d736414aa2f0528b1cda7f6e888.tar.xz wireguard-openbsd-bd6e9ca986f28d736414aa2f0528b1cda7f6e888.zip |
zap old file.
-rw-r--r-- | sys/arch/alpha/alpha/pmap.old.c | 2286 |
1 files changed, 0 insertions, 2286 deletions
diff --git a/sys/arch/alpha/alpha/pmap.old.c b/sys/arch/alpha/alpha/pmap.old.c deleted file mode 100644 index 4e8ade0cd7e..00000000000 --- a/sys/arch/alpha/alpha/pmap.old.c +++ /dev/null @@ -1,2286 +0,0 @@ -/* $OpenBSD: pmap.old.c,v 1.7 2000/06/08 11:57:21 art Exp $ */ -/* $NetBSD: pmap.old.c,v 1.14 1996/11/13 21:13:10 cgd Exp $ */ - -/* - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * the Systems Programming Group of the University of Utah Computer - * Science Department. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)pmap.c 8.6 (Berkeley) 5/27/94 - */ - -#ifdef XXX -/* - * HP9000/300 series physical map management code. - * - * Supports: - * 68020 with HP MMU models 320, 350 - * 68020 with 68551 MMU models 318, 319, 330 (all untested) - * 68030 with on-chip MMU models 340, 360, 370, 345, 375, 400 - * 68040 with on-chip MMU models 380, 425, 433 - * - * Notes: - * Don't even pay lip service to multiprocessor support. - * - * We assume TLB entries don't have process tags (except for the - * supervisor/user distinction) so we only invalidate TLB entries - * when changing mappings for the current (or kernel) pmap. This is - * technically not true for the 68551 but we flush the TLB on every - * context switch, so it effectively winds up that way. - * - * Bitwise and/or operations are significantly faster than bitfield - * references so we use them when accessing STE/PTEs in the pmap_pte_* - * macros. Note also that the two are not always equivalent; e.g.: - * (*(int *)pte & PG_PROT) [4] != pte->pg_prot [1] - * and a couple of routines that deal with protection and wiring take - * some shortcuts that assume the and/or definitions. - * - * This implementation will only work for PAGE_SIZE == NBPG - * (i.e. 4096 bytes). - */ -#endif - -/* - * Manages physical address maps. - * - * In addition to hardware address maps, this - * module is called upon to provide software-use-only - * maps which may or may not be stored in the same - * form as hardware maps. These pseudo-maps are - * used to store intermediate results from copy - * operations to and from address spaces. - * - * Since the information managed by this module is - * also stored by the logical address mapping module, - * this module may throw away valid virtual-to-physical - * mappings at almost any time. However, invalidations - * of virtual-to-physical mappings must be done as - * requested. - * - * In order to cope with hardware architectures which - * make virtual-to-physical map invalidates expensive, - * this module may delay invalidate or reduced protection - * operations until such time as they are actually - * necessary. This module is given full information as - * to which processors are currently using which maps, - * and to when physical maps must be made correct. - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/proc.h> -#include <sys/malloc.h> -#include <sys/user.h> -#include <sys/buf.h> -#ifdef SYSVSHM -#include <sys/shm.h> -#endif - -#include <vm/vm.h> -#include <vm/vm_kern.h> -#include <vm/vm_page.h> - -#include <machine/cpu.h> - -#ifdef PMAPSTATS -struct { - int collectscans; - int collectpages; - int kpttotal; - int kptinuse; - int kptmaxuse; -} kpt_stats; -struct { - int kernel; /* entering kernel mapping */ - int user; /* entering user mapping */ - int ptpneeded; /* needed to allocate a PT page */ - int nochange; /* no change at all */ - int pwchange; /* no mapping change, just wiring or protection */ - int wchange; /* no mapping change, just wiring */ - int pchange; /* no mapping change, just protection */ - int mchange; /* was mapped but mapping to different page */ - int managed; /* a managed page */ - int firstpv; /* first mapping for this PA */ - int secondpv; /* second mapping for this PA */ - int ci; /* cache inhibited */ - int unmanaged; /* not a managed page */ - int flushes; /* cache flushes */ -} enter_stats; -struct { - int calls; - int removes; - int pvfirst; - int pvsearch; - int ptinvalid; - int uflushes; - int sflushes; -} remove_stats; -struct { - int calls; - int changed; - int alreadyro; - int alreadyrw; -} protect_stats; -struct chgstats { - int setcalls; - int sethits; - int setmiss; - int clrcalls; - int clrhits; - int clrmiss; -} changebit_stats[16]; -#endif - -#ifdef DEBUG -#define PDB_FOLLOW 0x0001 -#define PDB_INIT 0x0002 -#define PDB_ENTER 0x0004 -#define PDB_REMOVE 0x0008 -#define PDB_CREATE 0x0010 -#define PDB_PTPAGE 0x0020 -#define PDB_CACHE 0x0040 -#define PDB_BITS 0x0080 -#define PDB_COLLECT 0x0100 -#define PDB_PROTECT 0x0200 -#define PDB_SEGTAB 0x0400 -#define PDB_MULTIMAP 0x0800 -#define PDB_BOOTSTRAP 0x1000 -#define PDB_PARANOIA 0x2000 -#define PDB_WIRING 0x4000 -#define PDB_PVDUMP 0x8000 - -int debugmap = 0; -int pmapdebug = PDB_PARANOIA; -extern vm_offset_t pager_sva, pager_eva; -#endif - -/* - * Get STEs and PTEs for user/kernel address space - */ -#define pmap_ste(m, v) (&((m)->pm_stab[vatoste((vm_offset_t)(v))])) -#define pmap_ste_v(m, v) (*pmap_ste(m, v) & PG_V) - -#define pmap_pte(m, v) \ - (&((m)->pm_ptab[NPTEPG * vatoste((vm_offset_t)(v)) + \ - vatopte((vm_offset_t)(v))])) -#define pmap_pte_pa(pte) (PG_PFNUM(*(pte)) << PGSHIFT) -#define pmap_pte_prot(pte) (*(pte) & PG_PROT) -#define pmap_pte_w(pte) (*(pte) & PG_WIRED) -#define pmap_pte_v(pte) (*(pte) & PG_V) - -#define pmap_pte_set_w(pte, v) \ - if (v) *(u_long *)(pte) |= PG_WIRED; else *(u_long *)(pte) &= ~PG_WIRED -#define pmap_pte_w_chg(pte, nw) ((nw) ^ pmap_pte_w(pte)) - -#define pmap_pte_set_prot(pte, np) { *(pte) &= ~PG_PROT ; *(pte) |= (np); } -#define pmap_pte_prot_chg(pte, np) ((np) ^ pmap_pte_prot(pte)) - - -/* - * Given a map and a machine independent protection code, - * convert to an hp300 protection code. - */ -#define pte_prot(m, p) (protection_codes[m == pmap_kernel() ? 0 : 1][p]) -int protection_codes[2][8]; - -/* - * Kernel page table page management. - */ -struct kpt_page { - struct kpt_page *kpt_next; /* link on either used or free list */ - vm_offset_t kpt_va; /* always valid kernel VA */ - vm_offset_t kpt_pa; /* PA of this page (for speed) */ -}; -struct kpt_page *kpt_free_list, *kpt_used_list; -struct kpt_page *kpt_pages; - -/* - * The Alpha's level-1 page table. - */ -pt_entry_t *Lev1map; - -/* - * Kernel segment/page table and page table map. - * The page table map gives us a level of indirection we need to dynamically - * expand the page table. It is essentially a copy of the segment table - * with PTEs instead of STEs. All are initialized in locore at boot time. - * Segtabzero is an empty segment table which all processes share til they - * reference something. - */ -pt_entry_t *Sysptmap; -pt_entry_t *Sysmap; -vm_size_t Sysptmapsize, Sysmapsize; -pt_entry_t *Segtabzero, Segtabzeropte; - -struct pmap kernel_pmap_store; -vm_map_t st_map, pt_map; - -vm_offset_t avail_start; /* PA of first available physical page */ -vm_offset_t avail_end; /* PA of last available physical page */ -vm_size_t mem_size; /* memory size in bytes */ -vm_offset_t virtual_avail; /* VA of first avail page (after kernel bss)*/ -vm_offset_t virtual_end; /* VA of last avail page (end of kernel AS) */ -vm_offset_t vm_first_phys; /* PA of first managed page */ -vm_offset_t vm_last_phys; /* PA just past last managed page */ -boolean_t pmap_initialized = FALSE; /* Has pmap_init completed? */ -char *pmap_attributes; /* reference and modify bits */ - -/* - * Internal routines - */ -void alpha_protection_init __P((void)); -void pmap_remove_mapping __P((pmap_t, vm_offset_t, pt_entry_t *, int)); -void pmap_changebit __P((vm_offset_t, u_long, boolean_t)); -void pmap_enter_ptpage __P((pmap_t, vm_offset_t)); -#ifdef DEBUG -void pmap_pvdump __P((vm_offset_t)); -void pmap_check_wiring __P((char *, vm_offset_t)); -#endif - -#define PAGE_IS_MANAGED(pa) ((pa) >= vm_first_phys && (pa) < vm_last_phys) - -/* pmap_remove_mapping flags */ -#define PRM_TFLUSH 1 -#define PRM_CFLUSH 2 - -/* - * pmap_bootstrap: - * Bootstrap the system to run with virtual memory. - * firstaddr is the first unused kseg0 address (not page aligned). - */ -void -pmap_bootstrap(firstaddr, ptaddr) - vm_offset_t firstaddr; - vm_offset_t ptaddr; -{ - register int i; - vm_offset_t start; - pt_entry_t pte; - extern int firstusablepage, lastusablepage; - -#ifdef DEBUG - if (pmapdebug & (PDB_FOLLOW|PDB_BOOTSTRAP)) - printf("pmap_bootstrap(0x%lx, 0x%lx)\n", firstaddr, ptaddr); -#endif - - /* must be page aligned */ - start = firstaddr = alpha_round_page(firstaddr); - -#define valloc(name, type, num) \ - (name) = (type *)firstaddr; \ - firstaddr = ALIGN((vm_offset_t)((name)+(num))) - - /* - * Allocate an empty prototype segment map for processes. - * This will be used until processes get their own. - */ - valloc(Segtabzero, pt_entry_t, NPTEPG); - Segtabzeropte = (ALPHA_K0SEG_TO_PHYS((vm_offset_t)Segtabzero) >> PGSHIFT) << PG_SHIFT; - Segtabzeropte |= PG_V | PG_KRE | PG_KWE | PG_WIRED; - - /* - * Figure out how many PTE's are necessary to map the kernel. - * The '512' comes from PAGER_MAP_SIZE in vm_pager_init(). - * This should be kept in sync. - * We also reserve space for kmem_alloc_pageable() for vm_fork(). - */ - Sysmapsize = (VM_KMEM_SIZE + VM_MBUF_SIZE + VM_PHYS_SIZE + - nbuf * MAXBSIZE + 16 * NCARGS) / NBPG + 512 + 256; - Sysmapsize += maxproc * (btoc(ALPHA_STSIZE) + btoc(ALPHA_MAX_PTSIZE)); - -#ifdef SYSVSHM - Sysmapsize += shminfo.shmall; -#endif - Sysmapsize = roundup(Sysmapsize, NPTEPG); - - /* - * Allocate a level 1 PTE table for the kernel. - * This is always one page long. - * IF THIS IS NOT A MULTIPLE OF NBPG, ALL WILL GO TO HELL. - */ - valloc(Lev1map, pt_entry_t, NPTEPG); - - /* - * Allocate a level 2 PTE table for the kernel. - * These must map all of the level3 PTEs. - * IF THIS IS NOT A MULTIPLE OF NBPG, ALL WILL GO TO HELL. - */ - Sysptmapsize = roundup(howmany(Sysmapsize, NPTEPG), NPTEPG); - valloc(Sysptmap, pt_entry_t, Sysptmapsize); - pmap_kernel()->pm_stab = Sysptmap; - - /* - * Allocate a level 3 PTE table for the kernel. - * Contains Sysmapsize PTEs. - */ - valloc(Sysmap, pt_entry_t, Sysmapsize); - pmap_kernel()->pm_ptab = Sysmap; - - /* - * Allocate memory for page attributes. - * allocates a few more entries than we need, but that's safe. - */ - valloc(pmap_attributes, char, 1 + lastusablepage - firstusablepage); - - /* - * Allocate memory for pv_table. - * This will allocate more entries than we really need. - * We could do this in pmap_init when we know the actual - * phys_start and phys_end but its better to use kseg0 addresses - * rather than kernel virtual addresses mapped through the TLB. - */ - i = 1 + lastusablepage - alpha_btop(ALPHA_K0SEG_TO_PHYS(firstaddr)); - valloc(pv_table, struct pv_entry, i); - - /* - * Clear allocated memory. - */ - firstaddr = alpha_round_page(firstaddr); - bzero((caddr_t)start, firstaddr - start); - - /* - * Set up level 1 page table - */ - - /* First, copy mappings for things below VM_MIN_KERNEL_ADDRESS */ - bcopy((caddr_t)ptaddr, Lev1map, - kvtol1pte(VM_MIN_KERNEL_ADDRESS) * sizeof Lev1map[0]); - - /* Second, map all of the level 2 pte pages */ - for (i = 0; i < howmany(Sysptmapsize, NPTEPG); i++) { - pte = (ALPHA_K0SEG_TO_PHYS(((vm_offset_t)Sysptmap) + (i*PAGE_SIZE)) >> PGSHIFT) - << PG_SHIFT; - pte |= PG_V | PG_ASM | PG_KRE | PG_KWE | PG_WIRED; - Lev1map[kvtol1pte(VM_MIN_KERNEL_ADDRESS + - (i*PAGE_SIZE*NPTEPG*NPTEPG))] = pte; - } - - /* Finally, map the virtual page table */ - pte = (ALPHA_K0SEG_TO_PHYS((vm_offset_t)Lev1map) >> PGSHIFT) << PG_SHIFT; - pte |= PG_V | PG_KRE | PG_KWE; /* NOTE NO ASM */ - Lev1map[kvtol1pte(VPTBASE)] = pte; - - /* - * Set up level 2 page table. - */ - /* Map all of the level 3 pte pages */ - for (i = 0; i < howmany(Sysmapsize, NPTEPG); i++) { - pte = (ALPHA_K0SEG_TO_PHYS(((vm_offset_t)Sysmap)+(i*PAGE_SIZE)) >> PGSHIFT) - << PG_SHIFT; - pte |= PG_V | PG_ASM | PG_KRE | PG_KWE | PG_WIRED; - Sysptmap[vatoste(VM_MIN_KERNEL_ADDRESS+ - (i*PAGE_SIZE*NPTEPG))] = pte; - } - - /* - * Set up level three page table (Sysmap) - */ - /* Nothing to do; it's already zero'd */ - - avail_start = ALPHA_K0SEG_TO_PHYS(firstaddr); -#if 1 - avail_end = alpha_ptob(lastusablepage + 1); - mem_size = avail_end - avail_start; -#else - /* XXX why not lastusablepage + 1, & not include NBPG in mem_size? */ - avail_end = alpha_ptob(lastusablepage); - mem_size = NBPG + avail_end - avail_start; -#endif -#if 0 - printf("avail_start = 0x%lx\n", avail_start); - printf("avail_end = 0x%lx\n", avail_end); - printf("mem_size = 0x%lx\n", mem_size); -#endif - - virtual_avail = VM_MIN_KERNEL_ADDRESS; - virtual_end = VM_MIN_KERNEL_ADDRESS + Sysmapsize * NBPG; - - simple_lock_init(&pmap_kernel()->pm_lock); - pmap_kernel()->pm_count = 1; - - /* - * Set up curproc's (i.e. proc 0's) PCB such that the ptbr - * points to the right place. - */ - curproc->p_addr->u_pcb.pcb_hw.apcb_ptbr = ALPHA_K0SEG_TO_PHYS((vm_offset_t)Lev1map) >> PGSHIFT; -} - -/* - * Unmap the PROM mappings. PROM mappings are kept around - * by pmap_bootstrap, so we can still use the prom's printf. - * Basically, blow away all mappings in the level one PTE - * table below VM_MIN_KERNEL_ADDRESS. The Virtual Page Table - * Is at the end of virtual space, so it's safe. - */ -void -pmap_unmap_prom() -{ - extern int prom_mapped; - extern pt_entry_t *rom_ptep, rom_pte; - -#ifdef DEBUG - if (pmapdebug & (PDB_FOLLOW|PDB_BOOTSTRAP)) - printf("pmap_unmap_prom\n"); -#endif - - /* XXX save old pte so that we can remap prom if necessary */ - rom_ptep = &Lev1map[0]; /* XXX */ - rom_pte = *rom_ptep & ~PG_ASM; /* XXX */ - - /* Mark all mappings before VM_MIN_KERNEL_ADDRESS as invalid. */ - bzero(Lev1map, kvtol1pte(VM_MIN_KERNEL_ADDRESS) * sizeof Lev1map[0]); - prom_mapped = 0; - ALPHA_TBIA(); -} - -/* - * Bootstrap memory allocator. This function allows for early dynamic - * memory allocation until the virtual memory system has been bootstrapped. - * After that point, either kmem_alloc or malloc should be used. This - * function works by stealing pages from the (to be) managed page pool, - * stealing virtual address space, then implicitly mapping the pages - * (by using their k0seg addresses) and zeroing them. - * - * It should be used from pmap_bootstrap till vm_page_startup, afterwards - * it cannot be used, and will generate a panic if tried. Note that this - * memory will never be freed, and in essence it is wired down. - */ -void * -pmap_bootstrap_alloc(size) - int size; -{ - vm_offset_t val; - extern boolean_t vm_page_startup_initialized; - -#ifdef DEBUG - if (pmapdebug & (PDB_FOLLOW|PDB_BOOTSTRAP)) - printf("pmap_bootstrap_alloc(%x)\n", size); -#endif - if (vm_page_startup_initialized) - panic("pmap_bootstrap_alloc: called after startup initialized"); - - val = ALPHA_PHYS_TO_K0SEG(avail_start); - size = round_page(size); - avail_start += size; - - bzero((caddr_t)val, size); - return ((void *)val); -} - -/* - * Initialize the pmap module. - * Called by vm_init, to initialize any structures that the pmap - * system needs to map virtual memory. - */ -void -pmap_init(phys_start, phys_end) - vm_offset_t phys_start, phys_end; -{ - vm_offset_t addr, addr2; - vm_size_t s; - -#ifdef DEBUG - if (pmapdebug & PDB_FOLLOW) - printf("pmap_init(%lx, %lx)\n", phys_start, phys_end); -#endif - - /* initialize protection array */ - alpha_protection_init(); - - /* - * Allocate the segment table map - */ - s = maxproc * ALPHA_STSIZE; - st_map = kmem_suballoc(kernel_map, &addr, &addr2, s, TRUE); - - /* - * Allocate the page table map - */ - s = maxproc * ALPHA_MAX_PTSIZE; /* XXX limit it */ - pt_map = kmem_suballoc(kernel_map, &addr, &addr2, s, TRUE); - - /* - * Now it is safe to enable pv_table recording. - */ - vm_first_phys = phys_start; - vm_last_phys = phys_end; -#if 0 - printf("vm_first_phys = 0x%lx\n", vm_first_phys); - printf("vm_last_phys = 0x%lx\n", vm_last_phys); -#endif - pmap_initialized = TRUE; -} - -#if 0 -/* - * Used to map a range of physical addresses into kernel - * virtual address space. - * - * For now, VM is already on, we only need to map the - * specified memory. - */ -vm_offset_t -pmap_map(virt, start, end, prot) - vm_offset_t virt; - vm_offset_t start; - vm_offset_t end; - int prot; -{ -#ifdef DEBUG - if (pmapdebug & PDB_FOLLOW) - printf("pmap_map(%lx, %lx, %lx, %x)\n", virt, start, end, prot); -#endif - while (start < end) { - pmap_enter(pmap_kernel(), virt, start, prot, FALSE, 0); - virt += PAGE_SIZE; - start += PAGE_SIZE; - } - return(virt); -} -#endif - -/* - * Create and return a physical map. - * - * If the size specified for the map - * is zero, the map is an actual physical - * map, and may be referenced by the - * hardware. - * - * If the size specified is non-zero, - * the map will be used in software only, and - * is bounded by that size. - */ -pmap_t -pmap_create(size) - vm_size_t size; -{ - register pmap_t pmap; - -#ifdef DEBUG - if (pmapdebug & (PDB_FOLLOW|PDB_CREATE)) - printf("pmap_create(%lx)\n", size); -#endif - /* - * Software use map does not need a pmap - */ - if (size) - return(NULL); - - /* XXX: is it ok to wait here? */ - pmap = (pmap_t) malloc(sizeof *pmap, M_VMPMAP, M_WAITOK); -#ifdef notifwewait - if (pmap == NULL) - panic("pmap_create: cannot allocate a pmap"); -#endif - bzero(pmap, sizeof(*pmap)); - pmap_pinit(pmap); - return (pmap); -} - -/* - * Initialize a preallocated and zeroed pmap structure, - * such as one in a vmspace structure. - */ -void -pmap_pinit(pmap) - register struct pmap *pmap; -{ - -#ifdef DEBUG - if (pmapdebug & (PDB_FOLLOW|PDB_CREATE)) - printf("pmap_pinit(%p)\n", pmap); -#endif - /* - * No need to allocate page table space yet but we do need a - * valid segment table. Initially, we point everyone at the - * "null" segment table. On the first pmap_enter, a real - * segment table will be allocated. - */ - pmap->pm_stab = Segtabzero; - pmap->pm_stpte = Segtabzeropte; - pmap->pm_stchanged = TRUE; - pmap->pm_count = 1; - simple_lock_init(&pmap->pm_lock); -} - -/* - * Retire the given physical map from service. - * Should only be called if the map contains - * no valid mappings. - */ -void -pmap_destroy(pmap) - register pmap_t pmap; -{ - int count; - -#ifdef DEBUG - if (pmapdebug & PDB_FOLLOW) - printf("pmap_destroy(%p)\n", pmap); -#endif - if (pmap == NULL) - return; - - simple_lock(&pmap->pm_lock); - count = --pmap->pm_count; - simple_unlock(&pmap->pm_lock); - if (count == 0) { - pmap_release(pmap); - free((caddr_t)pmap, M_VMPMAP); - } -} - -/* - * Release any resources held by the given physical map. - * Called when a pmap initialized by pmap_pinit is being released. - * Should only be called if the map contains no valid mappings. - */ -void -pmap_release(pmap) - register struct pmap *pmap; -{ - -#ifdef DEBUG - if (pmapdebug & PDB_FOLLOW) - printf("pmap_release(%p)\n", pmap); -#endif -#ifdef notdef /* DIAGNOSTIC */ - /* count would be 0 from pmap_destroy... */ - simple_lock(&pmap->pm_lock); - if (pmap->pm_count != 1) - panic("pmap_release count"); -#endif - if (pmap->pm_ptab) - kmem_free_wakeup(pt_map, (vm_offset_t)pmap->pm_ptab, - ALPHA_MAX_PTSIZE); - if (pmap->pm_stab != Segtabzero) - kmem_free_wakeup(st_map, (vm_offset_t)pmap->pm_stab, - ALPHA_STSIZE); -} - -/* - * Add a reference to the specified pmap. - */ -void -pmap_reference(pmap) - pmap_t pmap; -{ -#ifdef DEBUG - if (pmapdebug & PDB_FOLLOW) - printf("pmap_reference(%p)\n", pmap); -#endif - if (pmap != NULL) { - simple_lock(&pmap->pm_lock); - pmap->pm_count++; - simple_unlock(&pmap->pm_lock); - } -} - -/* - * Remove the given range of addresses from the specified map. - * - * It is assumed that the start and end are properly - * rounded to the page size. - */ -void -pmap_remove(pmap, sva, eva) - register pmap_t pmap; - register vm_offset_t sva, eva; -{ - register vm_offset_t nssva; - register pt_entry_t *pte; - boolean_t firstpage, needcflush; - int flags; - -#ifdef DEBUG - if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT)) - printf("pmap_remove(%p, %lx, %lx)\n", pmap, sva, eva); -#endif - - if (pmap == NULL) - return; - -#ifdef PMAPSTATS - remove_stats.calls++; -#endif - firstpage = TRUE; - needcflush = FALSE; - flags = active_pmap(pmap) ? PRM_TFLUSH : 0; - while (sva < eva) { - nssva = alpha_trunc_seg(sva) + ALPHA_SEG_SIZE; - if (nssva == 0 || nssva > eva) - nssva = eva; - /* - * If VA belongs to an unallocated segment, - * skip to the next segment boundary. - */ - if (!pmap_ste_v(pmap, sva)) { - sva = nssva; - continue; - } - /* - * Invalidate every valid mapping within this segment. - */ - pte = pmap_pte(pmap, sva); - while (sva < nssva) { - if (pmap_pte_v(pte)) { - pmap_remove_mapping(pmap, sva, pte, flags); - firstpage = FALSE; - } - pte++; - sva += PAGE_SIZE; - } - } - /* - * Didn't do anything, no need for cache flushes - */ - if (firstpage) - return; -} - -/* - * pmap_page_protect: - * - * Lower the permission for all mappings to a given page. - */ -void -pmap_page_protect(pa, prot) - vm_offset_t pa; - vm_prot_t prot; -{ - register pv_entry_t pv; - int s; - -#ifdef DEBUG - if ((pmapdebug & (PDB_FOLLOW|PDB_PROTECT)) || - (prot == VM_PROT_NONE && (pmapdebug & PDB_REMOVE))) - printf("pmap_page_protect(%lx, %x)\n", pa, prot); -#endif - if (!PAGE_IS_MANAGED(pa)) - return; - - switch (prot) { - case VM_PROT_READ|VM_PROT_WRITE: - case VM_PROT_ALL: - return; - /* copy_on_write */ - case VM_PROT_READ: - case VM_PROT_READ|VM_PROT_EXECUTE: -/* XXX */ pmap_changebit(pa, PG_KWE | PG_UWE, FALSE); - return; - /* remove_all */ - default: - break; - } - pv = pa_to_pvh(pa); - s = splimp(); - while (pv->pv_pmap != NULL) { - register pt_entry_t *pte; - - pte = pmap_pte(pv->pv_pmap, pv->pv_va); -#ifdef DEBUG - if (!pmap_ste_v(pv->pv_pmap, pv->pv_va) || - pmap_pte_pa(pte) != pa) - panic("pmap_page_protect: bad mapping"); -#endif - if (!pmap_pte_w(pte)) - pmap_remove_mapping(pv->pv_pmap, pv->pv_va, - pte, PRM_TFLUSH|PRM_CFLUSH); - else { - pv = pv->pv_next; -#ifdef DEBUG - if (pmapdebug & PDB_PARANOIA) - printf("%s wired mapping for %lx not removed\n", - "pmap_page_protect:", pa); -#endif - } - } - splx(s); -} - -/* - * Set the physical protection on the - * specified range of this map as requested. - */ -void -pmap_protect(pmap, sva, eva, prot) - register pmap_t pmap; - register vm_offset_t sva, eva; - vm_prot_t prot; -{ - register vm_offset_t nssva; - register pt_entry_t *pte, bits; - boolean_t firstpage, needtflush; - -#ifdef DEBUG - if (pmapdebug & (PDB_FOLLOW|PDB_PROTECT)) - printf("pmap_protect(%p, %lx, %lx, %x)\n", pmap, sva, eva, prot); -#endif - - if (pmap == NULL) - return; - -#ifdef PMAPSTATS - protect_stats.calls++; -#endif - if ((prot & VM_PROT_READ) == VM_PROT_NONE) { - pmap_remove(pmap, sva, eva); - return; - } - if (prot & VM_PROT_WRITE) - return; - - bits = pte_prot(pmap, prot); - needtflush = active_pmap(pmap); - firstpage = TRUE; - while (sva < eva) { - nssva = alpha_trunc_seg(sva) + ALPHA_SEG_SIZE; - if (nssva == 0 || nssva > eva) - nssva = eva; - /* - * If VA belongs to an unallocated segment, - * skip to the next segment boundary. - */ - if (!pmap_ste_v(pmap, sva)) { - sva = nssva; - continue; - } - /* - * Change protection on mapping if it is valid and doesn't - * already have the correct protection. - */ - pte = pmap_pte(pmap, sva); - while (sva < nssva) { - if (pmap_pte_v(pte) && pmap_pte_prot_chg(pte, bits)) { - pmap_pte_set_prot(pte, bits); - if (needtflush) - ALPHA_TBIS(sva); -#ifdef PMAPSTATS - protect_stats.changed++; -#endif - firstpage = FALSE; - } -#ifdef PMAPSTATS - else if (pmap_pte_v(pte)) { - if (isro) - protect_stats.alreadyro++; - else - protect_stats.alreadyrw++; - } -#endif - pte++; - sva += PAGE_SIZE; - } - } -} - -/* - * Insert the given physical page (p) at - * the specified virtual address (v) in the - * target physical map with the protection requested. - * - * If specified, the page will be wired down, meaning - * that the related pte can not be reclaimed. - * - * NB: This is the only routine which MAY NOT lazy-evaluate - * or lose information. That is, this routine must actually - * insert this page into the given map NOW. - */ -void -pmap_enter(pmap, va, pa, prot, wired, access_type) - register pmap_t pmap; - vm_offset_t va; - register vm_offset_t pa; - vm_prot_t prot; - boolean_t wired; - vm_prot_t access_type; -{ - register pt_entry_t *pte; - register pt_entry_t npte; - vm_offset_t opa; - boolean_t checkpv = TRUE; - -#ifdef DEBUG - if (pmapdebug & (PDB_FOLLOW|PDB_ENTER)) - printf("pmap_enter(%p, %lx, %lx, %x, %x)\n", - pmap, va, pa, prot, wired); -#endif - if (pmap == NULL) - return; - -#ifdef PMAPSTATS - if (pmap == pmap_kernel()) - enter_stats.kernel++; - else - enter_stats.user++; -#endif - /* - * For user mapping, allocate kernel VM resources if necessary. - */ - if (pmap->pm_ptab == NULL) - pmap->pm_ptab = (pt_entry_t *) - kmem_alloc_wait(pt_map, ALPHA_MAX_PTSIZE); - /* - * Segment table entry not valid, we need a new PT page - */ - if (!pmap_ste_v(pmap, va)) - pmap_enter_ptpage(pmap, va); - - pa = alpha_trunc_page(pa); - pte = pmap_pte(pmap, va); - opa = pmap_pte_pa(pte); -#ifdef DEBUG - if (pmapdebug & PDB_ENTER) - printf("enter: pte %p, *pte %lx\n", pte, *pte); -#endif - - /* - * Mapping has not changed, must be protection or wiring change. - */ - if (opa == pa) { -#ifdef PMAPSTATS - enter_stats.pwchange++; -#endif - /* - * Wiring change, just update stats. - * We don't worry about wiring PT pages as they remain - * resident as long as there are valid mappings in them. - * Hence, if a user page is wired, the PT page will be also. - */ - if (pmap_pte_w_chg(pte, wired ? PG_WIRED : 0)) { -#ifdef DEBUG - if (pmapdebug & PDB_ENTER) - printf("enter: wiring change -> %x\n", wired); -#endif - if (wired) - pmap->pm_stats.wired_count++; - else - pmap->pm_stats.wired_count--; -#ifdef PMAPSTATS - if (pmap_pte_prot(pte) == pte_prot(pmap, prot)) - enter_stats.wchange++; -#endif - } -#ifdef PMAPSTATS - else if (pmap_pte_prot(pte) != pte_prot(pmap, prot)) - enter_stats.pchange++; - else - enter_stats.nochange++; -#endif - /* - * Retain cache inhibition status - */ - checkpv = FALSE; - goto validate; - } - - /* - * Mapping has changed, invalidate old range and fall through to - * handle validating new mapping. - */ - if (opa) { -#ifdef DEBUG - if (pmapdebug & PDB_ENTER) - printf("enter: removing old mapping %lx\n", va); -#endif - pmap_remove_mapping(pmap, va, pte, PRM_TFLUSH|PRM_CFLUSH); -#ifdef PMAPSTATS - enter_stats.mchange++; -#endif - } - - /* - * If this is a new user mapping, increment the wiring count - * on this PT page. PT pages are wired down as long as there - * is a valid mapping in the page. - */ - if (pmap != pmap_kernel()) - (void) vm_map_pageable(pt_map, trunc_page(pte), - round_page(pte+1), FALSE); - - /* - * Enter on the PV list if part of our managed memory - * Note that we raise IPL while manipulating pv_table - * since pmap_enter can be called at interrupt time. - */ - if (PAGE_IS_MANAGED(pa)) { - register pv_entry_t pv, npv; - int s; - -#ifdef PMAPSTATS - enter_stats.managed++; -#endif - pv = pa_to_pvh(pa); - s = splimp(); -#ifdef DEBUG - if (pmapdebug & PDB_ENTER) - printf("enter: pv at %p: %lx/%p/%p\n", - pv, pv->pv_va, pv->pv_pmap, pv->pv_next); -#endif - /* - * No entries yet, use header as the first entry - */ - if (pv->pv_pmap == NULL) { -#ifdef PMAPSTATS - enter_stats.firstpv++; -#endif - pv->pv_va = va; - pv->pv_pmap = pmap; - pv->pv_next = NULL; - pv->pv_ptpte = NULL; - pv->pv_ptpmap = NULL; - pv->pv_flags = 0; - } - /* - * There is at least one other VA mapping this page. - * Place this entry after the header. - */ - else { -#ifdef DEBUG - for (npv = pv; npv; npv = npv->pv_next) - if (pmap == npv->pv_pmap && va == npv->pv_va) - panic("pmap_enter: already in pv_tab"); -#endif - npv = (pv_entry_t) - malloc(sizeof *npv, M_VMPVENT, M_NOWAIT); - npv->pv_va = va; - npv->pv_pmap = pmap; - npv->pv_next = pv->pv_next; - npv->pv_ptpte = NULL; - npv->pv_ptpmap = NULL; - npv->pv_flags = 0; - pv->pv_next = npv; -#ifdef PMAPSTATS - if (!npv->pv_next) - enter_stats.secondpv++; -#endif - } - splx(s); - } - /* - * Assumption: if it is not part of our managed memory - * then it must be device memory which may be volitile. - */ - else if (pmap_initialized) { - checkpv = FALSE; -#ifdef PMAPSTATS - enter_stats.unmanaged++; -#endif - } - - /* - * Increment counters - */ - pmap->pm_stats.resident_count++; - if (wired) - pmap->pm_stats.wired_count++; - -validate: - /* - * Build the new PTE. - */ - npte = ((pa >> PGSHIFT) << PG_SHIFT) | pte_prot(pmap, prot) | PG_V; - if (PAGE_IS_MANAGED(pa)) { - if ((pmap_attributes[pa_index(pa)] & PMAP_ATTR_REF) == 0) - npte |= PG_FOR | PG_FOW | PG_FOE; - else if ((pmap_attributes[pa_index(pa)] & PMAP_ATTR_MOD) == 0) - npte |= PG_FOW; - } - if (wired) - npte |= PG_WIRED; -#ifdef DEBUG - if (pmapdebug & PDB_ENTER) - printf("enter: new pte value %lx\n", npte); -#endif - /* - * Remember if this was a wiring-only change. - * If so, we need not flush the TLB and caches. - */ - wired = ((*pte ^ npte) == PG_WIRED); - *pte = npte; - if (!wired && active_pmap(pmap)) - ALPHA_TBIS(va); -#ifdef DEBUG - if ((pmapdebug & PDB_WIRING) && pmap != pmap_kernel()) - pmap_check_wiring("enter", trunc_page(pmap_pte(pmap, va))); -#endif -} - -/* - * Routine: pmap_change_wiring - * Function: Change the wiring attribute for a map/virtual-address - * pair. - * In/out conditions: - * The mapping must already exist in the pmap. - */ -void -pmap_change_wiring(pmap, va, wired) - register pmap_t pmap; - vm_offset_t va; - boolean_t wired; -{ - register pt_entry_t *pte; - -#ifdef DEBUG - if (pmapdebug & PDB_FOLLOW) - printf("pmap_change_wiring(%p, %lx, %x)\n", pmap, va, wired); -#endif - if (pmap == NULL) - return; - - pte = pmap_pte(pmap, va); -#ifdef DEBUG - /* - * Page table page is not allocated. - * Should this ever happen? Ignore it for now, - * we don't want to force allocation of unnecessary PTE pages. - */ - if (!pmap_ste_v(pmap, va)) { - if (pmapdebug & PDB_PARANOIA) - printf("pmap_change_wiring: invalid STE for %lx\n", va); - return; - } - /* - * Page not valid. Should this ever happen? - * Just continue and change wiring anyway. - */ - if (!pmap_pte_v(pte)) { - if (pmapdebug & PDB_PARANOIA) - printf("pmap_change_wiring: invalid PTE for %lx\n", va); - } -#endif - /* - * If wiring actually changed (always?) set the wire bit and - * update the wire count. Note that wiring is not a hardware - * characteristic so there is no need to invalidate the TLB. - */ - if (pmap_pte_w_chg(pte, wired ? PG_WIRED : 0)) { - pmap_pte_set_w(pte, wired); - if (wired) - pmap->pm_stats.wired_count++; - else - pmap->pm_stats.wired_count--; - } -} - -/* - * Routine: pmap_extract - * Function: - * Extract the physical page address associated - * with the given map/virtual_address pair. - */ - -vm_offset_t -pmap_extract(pmap, va) - register pmap_t pmap; - vm_offset_t va; -{ - pt_entry_t pte; - register vm_offset_t pa; - -#ifdef DEBUG - if (pmapdebug & PDB_FOLLOW) - printf("pmap_extract(%p, %lx) -> ", pmap, va); -#endif - pa = 0; - if (pmap && pmap_ste_v(pmap, va)) { - pte = *pmap_pte(pmap, va); - if (pte & PG_V) - pa = ctob(PG_PFNUM(pte)) | (va & PGOFSET); - } - -#ifdef DEBUG - if (pmapdebug & PDB_FOLLOW) - printf("%lx\n", pa); -#endif - return(pa); -} - -/* - * Copy the range specified by src_addr/len - * from the source map to the range dst_addr/len - * in the destination map. - * - * This routine is only advisory and need not do anything. - */ -void pmap_copy(dst_pmap, src_pmap, dst_addr, len, src_addr) - pmap_t dst_pmap; - pmap_t src_pmap; - vm_offset_t dst_addr; - vm_size_t len; - vm_offset_t src_addr; -{ -#ifdef DEBUG - if (pmapdebug & PDB_FOLLOW) - printf("pmap_copy(%p, %p, %lx, %lx, %lx)\n", - dst_pmap, src_pmap, dst_addr, len, src_addr); -#endif -} - -/* - * Require that all active physical maps contain no - * incorrect entries NOW. [This update includes - * forcing updates of any address map caching.] - * - * Generally used to insure that a thread about - * to run will see a semantically correct world. - */ -void pmap_update() -{ -#ifdef DEBUG - if (pmapdebug & PDB_FOLLOW) - printf("pmap_update()\n"); -#endif - ALPHA_TBIA(); -} - -/* - * Routine: pmap_collect - * Function: - * Garbage collects the physical map system for - * pages which are no longer used. - * Success need not be guaranteed -- that is, there - * may well be pages which are not referenced, but - * others may be collected. - * Usage: - * Called by the pageout daemon when pages are scarce. - */ -void -pmap_collect(pmap) - pmap_t pmap; -{ - register vm_offset_t pa; - register pv_entry_t pv; - register pt_entry_t *pte; - vm_offset_t kpa; - int s; - -#ifdef DEBUG - pt_entry_t *ste; - int opmapdebug = 0; -#endif - if (pmap != pmap_kernel()) - return; - -#ifdef DEBUG - if (pmapdebug & PDB_FOLLOW) - printf("pmap_collect(%p)\n", pmap); -#endif -#ifdef PMAPSTATS - kpt_stats.collectscans++; -#endif - s = splimp(); - for (pa = vm_first_phys; pa < vm_last_phys; pa += PAGE_SIZE) { - register struct kpt_page *kpt, **pkpt; - - /* - * Locate physical pages which are being used as kernel - * page table pages. - */ - pv = pa_to_pvh(pa); - if (pv->pv_pmap != pmap_kernel() || !(pv->pv_flags & PV_PTPAGE)) - continue; - do { - if (pv->pv_ptpte && pv->pv_ptpmap == pmap_kernel()) - break; - } while ((pv = pv->pv_next) != NULL); - if (pv == NULL) - continue; -#ifdef DEBUG - if (pv->pv_va < (vm_offset_t)Sysmap || - pv->pv_va >= (vm_offset_t)Sysmap + ALPHA_MAX_PTSIZE) - printf("collect: kernel PT VA out of range\n"); - else - goto ok; - pmap_pvdump(pa); - continue; -ok: -#endif - pte = (pt_entry_t *)(pv->pv_va + ALPHA_PAGE_SIZE); - while (--pte >= (pt_entry_t *)pv->pv_va && *pte == PG_NV) - ; - if (pte >= (pt_entry_t *)pv->pv_va) - continue; - -#ifdef DEBUG - if (pmapdebug & (PDB_PTPAGE|PDB_COLLECT)) { - printf("collect: freeing KPT page at %lx (ste %lx@%p)\n", - pv->pv_va, *pv->pv_ptpte, pv->pv_ptpte); - opmapdebug = pmapdebug; - pmapdebug |= PDB_PTPAGE; - } - - ste = pv->pv_ptpte; -#endif - /* - * If all entries were invalid we can remove the page. - * We call pmap_remove_entry to take care of invalidating - * ST and Sysptmap entries. - */ - kpa = pmap_extract(pmap, pv->pv_va); - pmap_remove_mapping(pmap, pv->pv_va, PT_ENTRY_NULL, - PRM_TFLUSH|PRM_CFLUSH); - /* - * Use the physical address to locate the original - * (kmem_alloc assigned) address for the page and put - * that page back on the free list. - */ - for (pkpt = &kpt_used_list, kpt = *pkpt; - kpt != (struct kpt_page *)0; - pkpt = &kpt->kpt_next, kpt = *pkpt) - if (kpt->kpt_pa == kpa) - break; -#ifdef DEBUG - if (kpt == (struct kpt_page *)0) - panic("pmap_collect: lost a KPT page"); - if (pmapdebug & (PDB_PTPAGE|PDB_COLLECT)) - printf("collect: %lx (%lx) to free list\n", - kpt->kpt_va, kpa); -#endif - *pkpt = kpt->kpt_next; - kpt->kpt_next = kpt_free_list; - kpt_free_list = kpt; -#ifdef PMAPSTATS - kpt_stats.kptinuse--; - kpt_stats.collectpages++; -#endif -#ifdef DEBUG - if (pmapdebug & (PDB_PTPAGE|PDB_COLLECT)) - pmapdebug = opmapdebug; - - if (*ste) - printf("collect: kernel STE at %p still valid (%lx)\n", - ste, *ste); - ste = &Sysptmap[(pt_entry_t *)ste-pmap_ste(pmap_kernel(), 0)]; - if (*ste) - printf("collect: kernel PTmap at %p still valid (%lx)\n", - ste, *ste); -#endif - } - splx(s); -} - -void -pmap_activate(pmap) - register pmap_t pmap; -{ - int iscurproc; - -#ifdef DEBUG - if (pmapdebug & (PDB_FOLLOW|PDB_SEGTAB)) - printf("pmap_activate(%p)\n", pmap); -#endif - - iscurproc = curproc != NULL && pmap == curproc->p_vmspace->vm_map.pmap; - PMAP_ACTIVATE(pmap, iscurproc); -} - -/* - * pmap_zero_page zeros the specified (machine independent) - * page by mapping the page into virtual memory and using - * bzero to clear its contents, one machine dependent page - * at a time. - */ -void -pmap_zero_page(phys) - vm_offset_t phys; -{ - caddr_t p; - -#ifdef DEBUG - if (pmapdebug & PDB_FOLLOW) - printf("pmap_zero_page(%lx)\n", phys); -#endif - p = (caddr_t)ALPHA_PHYS_TO_K0SEG(phys); - bzero(p, PAGE_SIZE); -} - -/* - * pmap_copy_page copies the specified (machine independent) - * page by mapping the page into virtual memory and using - * bcopy to copy the page, one machine dependent page at a - * time. - */ -void -pmap_copy_page(src, dst) - vm_offset_t src, dst; -{ - caddr_t s, d; - -#ifdef DEBUG - if (pmapdebug & PDB_FOLLOW) - printf("pmap_copy_page(%lx, %lx)\n", src, dst); -#endif - s = (caddr_t)ALPHA_PHYS_TO_K0SEG(src); - d = (caddr_t)ALPHA_PHYS_TO_K0SEG(dst); - bcopy(s, d, PAGE_SIZE); -} - -/* - * Routine: pmap_pageable - * Function: - * Make the specified pages (by pmap, offset) - * pageable (or not) as requested. - * - * A page which is not pageable may not take - * a fault; therefore, its page table entry - * must remain valid for the duration. - * - * This routine is merely advisory; pmap_enter - * will specify that these pages are to be wired - * down (or not) as appropriate. - */ -void -pmap_pageable(pmap, sva, eva, pageable) - pmap_t pmap; - vm_offset_t sva, eva; - boolean_t pageable; -{ -#ifdef DEBUG - if (pmapdebug & PDB_FOLLOW) - printf("pmap_pageable(%p, %lx, %lx, %x)\n", - pmap, sva, eva, pageable); -#endif - /* - * If we are making a PT page pageable then all valid - * mappings must be gone from that page. Hence it should - * be all zeros and there is no need to clean it. - * Assumptions: - * - we are called with only one page at a time - * - PT pages have only one pv_table entry - */ - if (pmap == pmap_kernel() && pageable && sva + PAGE_SIZE == eva) { - register pv_entry_t pv; - register vm_offset_t pa; - -#ifdef DEBUG - if ((pmapdebug & (PDB_FOLLOW|PDB_PTPAGE)) == PDB_PTPAGE) - printf("pmap_pageable(%p, %lx, %lx, %x)\n", - pmap, sva, eva, pageable); -#endif - if (!pmap_ste_v(pmap, sva)) - return; - pa = pmap_pte_pa(pmap_pte(pmap, sva)); - if (!PAGE_IS_MANAGED(pa)) - return; - pv = pa_to_pvh(pa); - if (pv->pv_ptpte == NULL) - return; -#ifdef DEBUG - if (pv->pv_va != sva || pv->pv_next) { - printf("pmap_pageable: bad PT page va %lx next %p\n", - pv->pv_va, pv->pv_next); - return; - } -#endif - /* - * Mark it unmodified to avoid pageout - */ - pmap_clear_modify(pa); -#ifdef DEBUG - if ((PHYS_TO_VM_PAGE(pa)->flags & PG_CLEAN) == 0) { - printf("pa %lx: flags=%x: not clean\n", - pa, PHYS_TO_VM_PAGE(pa)->flags); - PHYS_TO_VM_PAGE(pa)->flags |= PG_CLEAN; - } - if (pmapdebug & PDB_PTPAGE) - printf("pmap_pageable: PT page %lx(%lx) unmodified\n", - sva, *pmap_pte(pmap, sva)); - if (pmapdebug & PDB_WIRING) - pmap_check_wiring("pageable", sva); -#endif - } -} - -/* - * Clear the modify bits on the specified physical page. - */ - -void -pmap_clear_modify(pa) - vm_offset_t pa; -{ -#ifdef DEBUG - if (pmapdebug & PDB_FOLLOW) - printf("pmap_clear_modify(%lx)\n", pa); -#endif - if (!PAGE_IS_MANAGED(pa)) /* XXX why not panic? */ - return; - if ((pmap_attributes[pa_index(pa)] & PMAP_ATTR_MOD) != 0) { - pmap_changebit(pa, PG_FOW, TRUE); - pmap_attributes[pa_index(pa)] &= ~PMAP_ATTR_MOD; - } -} - -/* - * pmap_clear_reference: - * - * Clear the reference bit on the specified physical page. - */ - -void pmap_clear_reference(pa) - vm_offset_t pa; -{ -#ifdef DEBUG - if (pmapdebug & PDB_FOLLOW) - printf("pmap_clear_reference(%lx)\n", pa); -#endif - if (!PAGE_IS_MANAGED(pa)) /* XXX why not panic? */ - return; - if ((pmap_attributes[pa_index(pa)] & PMAP_ATTR_REF) != 0) { - pmap_changebit(pa, PG_FOR | PG_FOW | PG_FOE, TRUE); - pmap_attributes[pa_index(pa)] &= ~PMAP_ATTR_REF; - } -} - -/* - * pmap_is_referenced: - * - * Return whether or not the specified physical page is referenced - * by any physical maps. - */ - -boolean_t -pmap_is_referenced(pa) - vm_offset_t pa; -{ - boolean_t rv; - - if (!PAGE_IS_MANAGED(pa)) /* XXX why not panic? */ - return 0; - rv = (pmap_attributes[pa_index(pa)] & PMAP_ATTR_REF) != 0; -#ifdef DEBUG - if (pmapdebug & PDB_FOLLOW) { - printf("pmap_is_referenced(%lx) -> %c\n", pa, "FT"[rv]); - } -#endif - return rv; -} - -/* - * pmap_is_modified: - * - * Return whether or not the specified physical page is modified - * by any physical maps. - */ - -boolean_t -pmap_is_modified(pa) - vm_offset_t pa; -{ - boolean_t rv; - - if (!PAGE_IS_MANAGED(pa)) /* XXX why not panic? */ - return 0; - rv = (pmap_attributes[pa_index(pa)] & PMAP_ATTR_MOD) != 0; -#ifdef DEBUG - if (pmapdebug & PDB_FOLLOW) { - printf("pmap_is_modified(%lx) -> %c\n", pa, "FT"[rv]); - } -#endif - return rv; -} - -vm_offset_t -pmap_phys_address(ppn) - int ppn; -{ - return(alpha_ptob(ppn)); -} - -/* - * Miscellaneous support routines follow - */ - -/* - * Initialize Alpha protection code array. - */ -/* static */ -void -alpha_protection_init() -{ - int prot, *kp, *up; - - kp = protection_codes[0]; - up = protection_codes[1]; - - for (prot = 0; prot < 8; prot++) { - switch (prot) { - case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_NONE: - *kp++ = PG_ASM; - *up++ = 0; - break; - case VM_PROT_READ | VM_PROT_NONE | VM_PROT_NONE: - case VM_PROT_READ | VM_PROT_NONE | VM_PROT_EXECUTE: - case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_EXECUTE: - *kp++ = PG_ASM | PG_KRE; - *up++ = PG_URE | PG_KRE; - break; - case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_NONE: - *kp++ = PG_ASM | PG_KWE; - *up++ = PG_UWE | PG_KWE; - break; - case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_EXECUTE: - case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_NONE: - case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE: - *kp++ = PG_ASM | PG_KWE | PG_KRE; - *up++ = PG_UWE | PG_URE | PG_KWE | PG_KRE; - break; - } - } -} - -/* - * Invalidate a single page denoted by pmap/va. - * If (pte != NULL), it is the already computed PTE for the page. - * If (flags & PRM_TFLUSH), we must invalidate any TLB information. - * If (flags & PRM_CFLUSH), we must flush/invalidate any cache information. - */ -/* static */ -void -pmap_remove_mapping(pmap, va, pte, flags) - register pmap_t pmap; - register vm_offset_t va; - register pt_entry_t *pte; - int flags; -{ - register vm_offset_t pa; - register pv_entry_t pv, npv; - pmap_t ptpmap; - pt_entry_t *ste; - int s; -#ifdef DEBUG - pt_entry_t opte; - - if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT)) - printf("pmap_remove_mapping(%p, %lx, %p, %x)\n", - pmap, va, pte, flags); -#endif - - /* - * PTE not provided, compute it from pmap and va. - */ - if (pte == PT_ENTRY_NULL) { - pte = pmap_pte(pmap, va); - if (*pte == PG_NV) - return; - } - pa = pmap_pte_pa(pte); -#ifdef DEBUG - opte = *pte; -#endif -#ifdef PMAPSTATS - remove_stats.removes++; -#endif - /* - * Update statistics - */ - if (pmap_pte_w(pte)) - pmap->pm_stats.wired_count--; - pmap->pm_stats.resident_count--; - - /* - * Invalidate the PTE after saving the reference modify info. - */ -#ifdef DEBUG - if (pmapdebug & PDB_REMOVE) - printf("remove: invalidating pte at %p\n", pte); -#endif - *pte = PG_NV; - if ((flags & PRM_TFLUSH) && active_pmap(pmap)) - ALPHA_TBIS(va); - /* - * For user mappings decrement the wiring count on - * the PT page. We do this after the PTE has been - * invalidated because vm_map_pageable winds up in - * pmap_pageable which clears the modify bit for the - * PT page. - */ - if (pmap != pmap_kernel()) { - (void) vm_map_pageable(pt_map, trunc_page(pte), - round_page(pte+1), TRUE); -#ifdef DEBUG - if (pmapdebug & PDB_WIRING) - pmap_check_wiring("remove", trunc_page(pte)); -#endif - } - /* - * If this isn't a managed page, we are all done. - */ - if (!PAGE_IS_MANAGED(pa)) - return; - /* - * Otherwise remove it from the PV table - * (raise IPL since we may be called at interrupt time). - */ - pv = pa_to_pvh(pa); - ste = NULL; - s = splimp(); - /* - * If it is the first entry on the list, it is actually - * in the header and we must copy the following entry up - * to the header. Otherwise we must search the list for - * the entry. In either case we free the now unused entry. - */ - if (pmap == pv->pv_pmap && va == pv->pv_va) { - ste = pv->pv_ptpte; - ptpmap = pv->pv_ptpmap; - npv = pv->pv_next; - if (npv) { - npv->pv_flags = pv->pv_flags; - *pv = *npv; - free((caddr_t)npv, M_VMPVENT); - } else - pv->pv_pmap = NULL; -#ifdef PMAPSTATS - remove_stats.pvfirst++; -#endif - } else { - for (npv = pv->pv_next; npv; npv = npv->pv_next) { -#ifdef PMAPSTATS - remove_stats.pvsearch++; -#endif - if (pmap == npv->pv_pmap && va == npv->pv_va) - break; - pv = npv; - } -#ifdef DEBUG - if (npv == NULL) - panic("pmap_remove: PA not in pv_tab"); -#endif - ste = npv->pv_ptpte; - ptpmap = npv->pv_ptpmap; - pv->pv_next = npv->pv_next; - free((caddr_t)npv, M_VMPVENT); - pv = pa_to_pvh(pa); - } - /* - * If this was a PT page we must also remove the - * mapping from the associated segment table. - */ - if (ste) { -#ifdef PMAPSTATS - remove_stats.ptinvalid++; -#endif -#ifdef DEBUG - if (pmapdebug & (PDB_REMOVE|PDB_PTPAGE)) - printf("remove: ste was %lx@%p pte was %lx@%p\n", - *ste, ste, opte, pmap_pte(pmap, va)); -#endif - *ste = PG_NV; - /* - * If it was a user PT page, we decrement the - * reference count on the segment table as well, - * freeing it if it is now empty. - */ - if (ptpmap != pmap_kernel()) { -#ifdef DEBUG - if (pmapdebug & (PDB_REMOVE|PDB_SEGTAB)) - printf("remove: stab %p, refcnt %d\n", - ptpmap->pm_stab, ptpmap->pm_sref - 1); - if ((pmapdebug & PDB_PARANOIA) && - ptpmap->pm_stab != (pt_entry_t *)trunc_page(ste)) - panic("remove: bogus ste"); -#endif - if (--(ptpmap->pm_sref) == 0) { -#ifdef DEBUG - if (pmapdebug&(PDB_REMOVE|PDB_SEGTAB)) - printf("remove: free stab %p\n", - ptpmap->pm_stab); -#endif - kmem_free_wakeup(st_map, - (vm_offset_t)ptpmap->pm_stab, - ALPHA_STSIZE); - ptpmap->pm_stab = Segtabzero; - ptpmap->pm_stpte = Segtabzeropte; - ptpmap->pm_stchanged = TRUE; - /* - * XXX may have changed segment table - * pointer for current process so - * update now to reload hardware. - * (curproc may be NULL if exiting.) - */ - if (curproc != NULL && - ptpmap == curproc->p_vmspace->vm_map.pmap) - PMAP_ACTIVATE(ptpmap, 1); - } -#ifdef DEBUG - else if (ptpmap->pm_sref < 0) - panic("remove: sref < 0"); -#endif - } -#if 0 - /* - * XXX this should be unnecessary as we have been - * flushing individual mappings as we go. - */ - if (ptpmap == pmap_kernel()) - ALPHA_TBIAS(); - else - ALPHA_TBIAU(); -#endif - pv->pv_flags &= ~PV_PTPAGE; - ptpmap->pm_ptpages--; - } - splx(s); -} - -/* static */ -void -pmap_changebit(pa, bit, setem) - register vm_offset_t pa; - u_long bit; - boolean_t setem; -{ - register pv_entry_t pv; - register pt_entry_t *pte, npte; - vm_offset_t va; - int s; -#ifdef PMAPSTATS - struct chgstats *chgp; -#endif - -#ifdef DEBUG - if (pmapdebug & PDB_BITS) - printf("pmap_changebit(%lx, %lx, %s)\n", - pa, bit, setem ? "set" : "clear"); -#endif - if (!PAGE_IS_MANAGED(pa)) - return; - -#ifdef PMAPSTATS - chgp = &changebit_stats[(bit>>2)-1]; - if (setem) - chgp->setcalls++; - else - chgp->clrcalls++; -#endif - pv = pa_to_pvh(pa); - s = splimp(); - /* - * Loop over all current mappings setting/clearing as appropos - * If setting RO do we need to clear the VAC? - */ - if (pv->pv_pmap != NULL) { -#ifdef DEBUG - int toflush = 0; -#endif - for (; pv; pv = pv->pv_next) { -#ifdef DEBUG - toflush |= (pv->pv_pmap == pmap_kernel()) ? 2 : 1; -#endif - va = pv->pv_va; - - /* - * XXX don't write protect pager mappings - */ -/* XXX */ if (bit == (PG_UWE | PG_KWE)) { - extern vm_offset_t pager_sva, pager_eva; - - if (va >= pager_sva && va < pager_eva) - continue; - } - - pte = pmap_pte(pv->pv_pmap, va); - if (setem) - npte = *pte | bit; - else - npte = *pte & ~bit; - if (*pte != npte) { - *pte = npte; - if (active_pmap(pv->pv_pmap)) - ALPHA_TBIS(va); -#ifdef PMAPSTATS - if (setem) - chgp->sethits++; - else - chgp->clrhits++; -#endif - } -#ifdef PMAPSTATS - else { - if (setem) - chgp->setmiss++; - else - chgp->clrmiss++; - } -#endif - } - } - splx(s); -} - -/* static */ -void -pmap_enter_ptpage(pmap, va) - register pmap_t pmap; - register vm_offset_t va; -{ - register vm_offset_t ptpa; - register pv_entry_t pv; - pt_entry_t *ste; - int s; - -#ifdef DEBUG - if (pmapdebug & (PDB_FOLLOW|PDB_ENTER|PDB_PTPAGE)) - printf("pmap_enter_ptpage: pmap %p, va %lx\n", pmap, va); -#endif -#ifdef PMAPSTATS - enter_stats.ptpneeded++; -#endif - /* - * Allocate a segment table if necessary. Note that it is allocated - * from a private map and not pt_map. This keeps user page tables - * aligned on segment boundaries in the kernel address space. - * The segment table is wired down. It will be freed whenever the - * reference count drops to zero. - */ - if (pmap->pm_stab == Segtabzero) { - pmap->pm_stab = (pt_entry_t *) - kmem_alloc(st_map, ALPHA_STSIZE); - pmap->pm_stpte = *kvtopte(pmap->pm_stab); - pmap->pm_stchanged = TRUE; - /* - * XXX may have changed segment table pointer for current - * process so update now to reload hardware. - */ - if (pmap == curproc->p_vmspace->vm_map.pmap) - PMAP_ACTIVATE(pmap, 1); -#ifdef DEBUG - if (pmapdebug & (PDB_ENTER|PDB_PTPAGE|PDB_SEGTAB)) - printf("enter: pmap %p stab %p(%lx)\n", - pmap, pmap->pm_stab, pmap->pm_stpte); -#endif - } - - ste = pmap_ste(pmap, va); - va = trunc_page((vm_offset_t)pmap_pte(pmap, va)); - - /* - * In the kernel we allocate a page from the kernel PT page - * free list and map it into the kernel page table map (via - * pmap_enter). - */ - if (pmap == pmap_kernel()) { - register struct kpt_page *kpt; - - s = splimp(); - if ((kpt = kpt_free_list) == (struct kpt_page *)0) { - /* - * No PT pages available. - * Try once to free up unused ones. - */ -#ifdef DEBUG - if (pmapdebug & PDB_COLLECT) - printf("enter: no KPT pages, collecting...\n"); -#endif - pmap_collect(pmap_kernel()); - if ((kpt = kpt_free_list) == (struct kpt_page *)0) - panic("pmap_enter_ptpage: can't get KPT page"); - } -#ifdef PMAPSTATS - if (++kpt_stats.kptinuse > kpt_stats.kptmaxuse) - kpt_stats.kptmaxuse = kpt_stats.kptinuse; -#endif - kpt_free_list = kpt->kpt_next; - kpt->kpt_next = kpt_used_list; - kpt_used_list = kpt; - ptpa = kpt->kpt_pa; - bzero((caddr_t)kpt->kpt_va, ALPHA_PAGE_SIZE); - pmap_enter(pmap, va, ptpa, VM_PROT_DEFAULT, TRUE, 0); -#ifdef DEBUG - if (pmapdebug & (PDB_ENTER|PDB_PTPAGE)) { - int ix = pmap_ste(pmap, va) - pmap_ste(pmap, 0); - - printf("enter: add &Sysptmap[%d]: %lx (KPT page %lx)\n", - ix, Sysptmap[ix], kpt->kpt_va); - } -#endif - splx(s); - } - /* - * For user processes we just simulate a fault on that location - * letting the VM system allocate a zero-filled page. - */ - else { - /* - * Count the segment table reference now so that we won't - * lose the segment table when low on memory. - */ - pmap->pm_sref++; -#ifdef DEBUG - if (pmapdebug & (PDB_ENTER|PDB_PTPAGE)) - printf("enter: about to fault UPT pg at %lx\n", va); -#endif - s = vm_fault(pt_map, va, VM_PROT_READ|VM_PROT_WRITE, FALSE); - if (s != KERN_SUCCESS) { - printf("vm_fault(pt_map, %lx, RW, 0) -> %d\n", va, s); - panic("pmap_enter: vm_fault failed"); - } - ptpa = pmap_extract(pmap_kernel(), va); - /* - * Mark the page clean now to avoid its pageout (and - * hence creation of a pager) between now and when it - * is wired; i.e. while it is on a paging queue. - */ - PHYS_TO_VM_PAGE(ptpa)->flags |= PG_CLEAN; -#ifdef DEBUG - PHYS_TO_VM_PAGE(ptpa)->flags |= PG_PTPAGE; -#endif - } - /* - * Locate the PV entry in the kernel for this PT page and - * record the STE address. This is so that we can invalidate - * the STE when we remove the mapping for the page. - */ - pv = pa_to_pvh(ptpa); - s = splimp(); - if (pv) { - pv->pv_flags |= PV_PTPAGE; - do { - if (pv->pv_pmap == pmap_kernel() && pv->pv_va == va) - break; - } while ((pv = pv->pv_next) != NULL); - } -#ifdef DEBUG - if (pv == NULL) - panic("pmap_enter_ptpage: PT page not entered"); -#endif - pv->pv_ptpte = ste; - pv->pv_ptpmap = pmap; -#ifdef DEBUG - if (pmapdebug & (PDB_ENTER|PDB_PTPAGE)) - printf("enter: new PT page at PA 0x%lx, ste at %p\n", ptpa, ste); -#endif - - /* - * Map the new PT page into the segment table. - * Reference count on the user segment tables incremented above - * to prevent race conditions. Note that we don't use vm_map_pageable - * to keep the count like we do for PT pages, this is mostly because - * it would be difficult to identify ST pages in pmap_pageable to - * release them. We also avoid the overhead of vm_map_pageable. - */ - *ste = ((ptpa >> PGSHIFT) << PG_SHIFT) | PG_KRE | PG_KWE | PG_V | - (pmap == pmap_kernel() ? PG_ASM : 0); - if (pmap != pmap_kernel()) { -#ifdef DEBUG - if (pmapdebug & (PDB_ENTER|PDB_PTPAGE|PDB_SEGTAB)) - printf("enter: stab %p refcnt %d\n", - pmap->pm_stab, pmap->pm_sref); -#endif - } -#if 0 - /* - * Flush stale TLB info. - */ - if (pmap == pmap_kernel()) - ALPHA_TBIAS(); - else - ALPHA_TBIAU(); -#endif - pmap->pm_ptpages++; - splx(s); -} - -/* - * Emulate reference and/or modified bit hits. - */ -void -pmap_emulate_reference(p, v, user, write) - struct proc *p; - vm_offset_t v; - int user; - int write; -{ - pt_entry_t faultoff, *pte; - vm_offset_t pa; - char attr; - -#ifdef DEBUG - if (pmapdebug & PDB_FOLLOW) - printf("pmap_emulate_reference: %p, 0x%lx, %d, %d\n", - p, v, user, write); -#endif - - /* - * Convert process and virtual address to physical address. - */ - if (v >= VM_MIN_KERNEL_ADDRESS) { - if (user) - panic("pmap_emulate_reference: user ref to kernel"); - pte = kvtopte(v); - } else { -#ifdef DIAGNOSTIC - if (p == NULL) - panic("pmap_emulate_reference: bad proc"); - if (p->p_vmspace == NULL) - panic("pmap_emulate_reference: bad p_vmspace"); -#endif - pte = pmap_pte(p->p_vmspace->vm_map.pmap, v); - } -#ifdef DEBUG - if (pmapdebug & PDB_FOLLOW) { - printf("\tpte = %p, ", pte); - printf("*pte = 0x%lx\n", *pte); - } -#endif -#ifdef DEBUG /* These checks are more expensive */ - if (!pmap_pte_v(pte)) - panic("pmap_emulate_reference: invalid pte"); -#if 0 - /* - * Can't do these, because cpu_fork and cpu_swapin call - * pmap_emulate_reference(), and the bits aren't guaranteed, - * for them... - */ - if (write) { - if (!(*pte & (user ? PG_UWE : PG_UWE | PG_KWE))) - panic("pmap_emulate_reference: write but unwritable"); - if (!(*pte & PG_FOW)) - panic("pmap_emulate_reference: write but not FOW"); - } else { - if (!(*pte & (user ? PG_URE : PG_URE | PG_KRE))) - panic("pmap_emulate_reference: !write but unreadable"); - if (!(*pte & (PG_FOR | PG_FOE))) - panic("pmap_emulate_reference: !write but not FOR|FOE"); - } -#endif - /* Other diagnostics? */ -#endif - pa = pmap_pte_pa(pte); -#ifdef DEBUG - if (pmapdebug & PDB_FOLLOW) - printf("\tpa = 0x%lx\n", pa); -#endif -#ifdef DIAGNOSTIC - if (!PAGE_IS_MANAGED(pa)) - printf("WARNING: pmap_emulate_reference(%p, 0x%lx, %d, %d): pa 0x%lx not managed\n", p, v, user, write, pa); -#endif - - /* - * Twiddle the appropriate bits to reflect the reference - * and/or modification.. - * - * The rules: - * (1) always mark page as used, and - * (2) if it was a write fault, mark page as modified. - */ - attr = PMAP_ATTR_REF; - faultoff = PG_FOR | PG_FOE; - if (write) { - attr |= PMAP_ATTR_MOD; - faultoff |= PG_FOW; - } - pmap_attributes[pa_index(pa)] |= attr; - pmap_changebit(pa, faultoff, FALSE); - if ((*pte & faultoff) != 0) { -#if 0 - /* - * This is apparently normal. Why? -- cgd - * XXX because was being called on unmanaged pages? - */ - printf("warning: pmap_changebit didn't."); -#endif - *pte &= ~faultoff; - ALPHA_TBIS(v); - } -} - -#ifdef DEBUG -/* static */ -void -pmap_pvdump(pa) - vm_offset_t pa; -{ - register pv_entry_t pv; - - printf("pa %lx", pa); - for (pv = pa_to_pvh(pa); pv; pv = pv->pv_next) - printf(" -> pmap %p, va %lx, stpte %p, ptpmap %p, flags %x", - pv->pv_pmap, pv->pv_va, pv->pv_ptpte, pv->pv_ptpmap, - pv->pv_flags); - printf("\n"); -} - -/* static */ -void -pmap_check_wiring(str, va) - char *str; - vm_offset_t va; -{ - vm_map_entry_t entry; - pt_entry_t *pte; - register int count; - - va = trunc_page(va); - if (!pmap_ste_v(pmap_kernel(), va) || - !pmap_pte_v(pmap_pte(pmap_kernel(), va))) - return; - - if (!vm_map_lookup_entry(pt_map, va, &entry)) { - printf("wired_check: entry for %lx not found\n", va); - return; - } - count = 0; - for (pte = (pt_entry_t *)va; pte < (pt_entry_t *)(va+PAGE_SIZE); pte++) - if (*pte) - count++; - if (entry->wired_count != count) - printf("*%s*: %lx: w%d/a%d\n", - str, va, entry->wired_count, count); -} -#endif - -vm_offset_t -vtophys(vaddr) - vm_offset_t vaddr; -{ - vm_offset_t paddr; - - if (vaddr < ALPHA_K0SEG_BASE) { - printf("vtophys: invalid vaddr 0x%lx", vaddr); - paddr = vaddr; - } else if (vaddr <= ALPHA_K0SEG_END) - paddr = ALPHA_K0SEG_TO_PHYS(vaddr); - else - paddr = vatopa(vaddr); - -#if 0 - printf("vtophys(0x%lx) -> %lx\n", vaddr, paddr); -#endif - - return (paddr); -} |