1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1991, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * This code is derived from software contributed to Berkeley by 6df8bae1dSRodney W. Grimes * The Mach Operating System project at Carnegie-Mellon University. 7df8bae1dSRodney W. Grimes * 8df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 9df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 10df8bae1dSRodney W. Grimes * are met: 11df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 12df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 13df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 14df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 15df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 16df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 17df8bae1dSRodney W. Grimes * must display the following acknowledgement: 18df8bae1dSRodney W. Grimes * This product includes software developed by the University of 19df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 20df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 21df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 22df8bae1dSRodney W. Grimes * without specific prior written permission. 23df8bae1dSRodney W. Grimes * 24df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34df8bae1dSRodney W. Grimes * SUCH DAMAGE. 35df8bae1dSRodney W. Grimes * 36df8bae1dSRodney W. Grimes * @(#)vm_pager.c 8.6 (Berkeley) 1/12/94 37df8bae1dSRodney W. Grimes * 38df8bae1dSRodney W. Grimes * 39df8bae1dSRodney W. Grimes * Copyright (c) 1987, 1990 Carnegie-Mellon University. 40df8bae1dSRodney W. Grimes * All rights reserved. 41df8bae1dSRodney W. Grimes * 42df8bae1dSRodney W. Grimes * Authors: Avadis Tevanian, Jr., Michael Wayne Young 43df8bae1dSRodney W. Grimes * 44df8bae1dSRodney W. Grimes * Permission to use, copy, modify and distribute this software and 45df8bae1dSRodney W. Grimes * its documentation is hereby granted, provided that both the copyright 46df8bae1dSRodney W. Grimes * notice and this permission notice appear in all copies of the 47df8bae1dSRodney W. Grimes * software, derivative works or modified versions, and any portions 48df8bae1dSRodney W. Grimes * thereof, and that both notices appear in supporting documentation. 49df8bae1dSRodney W. Grimes * 50df8bae1dSRodney W. Grimes * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 51df8bae1dSRodney W. Grimes * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 52df8bae1dSRodney W. Grimes * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 53df8bae1dSRodney W. Grimes * 54df8bae1dSRodney W. Grimes * Carnegie Mellon requests users of this software to return to 55df8bae1dSRodney W. Grimes * 56df8bae1dSRodney W. Grimes * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 57df8bae1dSRodney W. Grimes * School of Computer Science 58df8bae1dSRodney W. Grimes * Carnegie Mellon University 59df8bae1dSRodney W. Grimes * Pittsburgh PA 15213-3890 60df8bae1dSRodney W. Grimes * 61df8bae1dSRodney W. Grimes * any improvements or extensions that they make and grant Carnegie the 62df8bae1dSRodney W. Grimes * rights to redistribute these changes. 63df8bae1dSRodney W. Grimes */ 64df8bae1dSRodney W. Grimes 65df8bae1dSRodney W. Grimes /* 66df8bae1dSRodney W. Grimes * Paging space routine stubs. Emulates a matchmaker-like interface 67df8bae1dSRodney W. Grimes * for builtin pagers. 68df8bae1dSRodney W. Grimes */ 69df8bae1dSRodney W. Grimes 70df8bae1dSRodney W. Grimes #include <sys/param.h> 71df8bae1dSRodney W. Grimes #include <sys/systm.h> 72df8bae1dSRodney W. Grimes #include <sys/malloc.h> 73df8bae1dSRodney W. Grimes 74df8bae1dSRodney W. Grimes #include <vm/vm.h> 75df8bae1dSRodney W. Grimes #include <vm/vm_page.h> 76df8bae1dSRodney W. Grimes #include <vm/vm_kern.h> 77df8bae1dSRodney W. Grimes 78df8bae1dSRodney W. Grimes extern struct pagerops swappagerops; 79df8bae1dSRodney W. Grimes extern struct pagerops vnodepagerops; 80df8bae1dSRodney W. Grimes extern struct pagerops devicepagerops; 81df8bae1dSRodney W. Grimes 82df8bae1dSRodney W. Grimes struct pagerops *pagertab[] = { 83df8bae1dSRodney W. Grimes &swappagerops, /* PG_SWAP */ 84df8bae1dSRodney W. Grimes &vnodepagerops, /* PG_VNODE */ 85df8bae1dSRodney W. Grimes &devicepagerops, /* PG_DEV */ 86df8bae1dSRodney W. Grimes }; 87df8bae1dSRodney W. Grimes int npagers = sizeof (pagertab) / sizeof (pagertab[0]); 88df8bae1dSRodney W. Grimes 89df8bae1dSRodney W. Grimes struct pagerops *dfltpagerops = NULL; /* default pager */ 90df8bae1dSRodney W. Grimes 91df8bae1dSRodney W. Grimes /* 92df8bae1dSRodney W. Grimes * Kernel address space for mapping pages. 93df8bae1dSRodney W. Grimes * Used by pagers where KVAs are needed for IO. 94df8bae1dSRodney W. Grimes * 95df8bae1dSRodney W. Grimes * XXX needs to be large enough to support the number of pending async 96df8bae1dSRodney W. Grimes * cleaning requests (NPENDINGIO == 64) * the maximum swap cluster size 97df8bae1dSRodney W. Grimes * (MAXPHYS == 64k) if you want to get the most efficiency. 98df8bae1dSRodney W. Grimes */ 99df8bae1dSRodney W. Grimes #define PAGER_MAP_SIZE (4 * 1024 * 1024) 100df8bae1dSRodney W. Grimes 10126f9a767SRodney W. Grimes int pager_map_size = PAGER_MAP_SIZE; 102df8bae1dSRodney W. Grimes vm_map_t pager_map; 103df8bae1dSRodney W. Grimes boolean_t pager_map_wanted; 104df8bae1dSRodney W. Grimes vm_offset_t pager_sva, pager_eva; 105df8bae1dSRodney W. Grimes 106df8bae1dSRodney W. Grimes void 107df8bae1dSRodney W. Grimes vm_pager_init() 108df8bae1dSRodney W. Grimes { 109df8bae1dSRodney W. Grimes struct pagerops **pgops; 110df8bae1dSRodney W. Grimes 111df8bae1dSRodney W. Grimes /* 112df8bae1dSRodney W. Grimes * Allocate a kernel submap for tracking get/put page mappings 113df8bae1dSRodney W. Grimes */ 11426f9a767SRodney W. Grimes /* 115df8bae1dSRodney W. Grimes pager_map = kmem_suballoc(kernel_map, &pager_sva, &pager_eva, 116df8bae1dSRodney W. Grimes PAGER_MAP_SIZE, FALSE); 11726f9a767SRodney W. Grimes */ 118df8bae1dSRodney W. Grimes /* 119df8bae1dSRodney W. Grimes * Initialize known pagers 120df8bae1dSRodney W. Grimes */ 121df8bae1dSRodney W. Grimes for (pgops = pagertab; pgops < &pagertab[npagers]; pgops++) 122df8bae1dSRodney W. Grimes if (pgops) 123df8bae1dSRodney W. Grimes (*(*pgops)->pgo_init)(); 124df8bae1dSRodney W. Grimes if (dfltpagerops == NULL) 125df8bae1dSRodney W. Grimes panic("no default pager"); 126df8bae1dSRodney W. Grimes } 127df8bae1dSRodney W. Grimes 128df8bae1dSRodney W. Grimes /* 129df8bae1dSRodney W. Grimes * Allocate an instance of a pager of the given type. 130df8bae1dSRodney W. Grimes * Size, protection and offset parameters are passed in for pagers that 131df8bae1dSRodney W. Grimes * need to perform page-level validation (e.g. the device pager). 132df8bae1dSRodney W. Grimes */ 133df8bae1dSRodney W. Grimes vm_pager_t 134df8bae1dSRodney W. Grimes vm_pager_allocate(type, handle, size, prot, off) 135df8bae1dSRodney W. Grimes int type; 136df8bae1dSRodney W. Grimes caddr_t handle; 137df8bae1dSRodney W. Grimes vm_size_t size; 138df8bae1dSRodney W. Grimes vm_prot_t prot; 139df8bae1dSRodney W. Grimes vm_offset_t off; 140df8bae1dSRodney W. Grimes { 141df8bae1dSRodney W. Grimes struct pagerops *ops; 142df8bae1dSRodney W. Grimes 143df8bae1dSRodney W. Grimes ops = (type == PG_DFLT) ? dfltpagerops : pagertab[type]; 144df8bae1dSRodney W. Grimes if (ops) 145df8bae1dSRodney W. Grimes return ((*ops->pgo_alloc)(handle, size, prot, off)); 146df8bae1dSRodney W. Grimes return (NULL); 147df8bae1dSRodney W. Grimes } 148df8bae1dSRodney W. Grimes 149df8bae1dSRodney W. Grimes void 150df8bae1dSRodney W. Grimes vm_pager_deallocate(pager) 151df8bae1dSRodney W. Grimes vm_pager_t pager; 152df8bae1dSRodney W. Grimes { 153df8bae1dSRodney W. Grimes if (pager == NULL) 154df8bae1dSRodney W. Grimes panic("vm_pager_deallocate: null pager"); 155df8bae1dSRodney W. Grimes 156df8bae1dSRodney W. Grimes (*pager->pg_ops->pgo_dealloc)(pager); 157df8bae1dSRodney W. Grimes } 158df8bae1dSRodney W. Grimes 15926f9a767SRodney W. Grimes 160df8bae1dSRodney W. Grimes int 16126f9a767SRodney W. Grimes vm_pager_get_pages(pager, m, count, reqpage, sync) 162df8bae1dSRodney W. Grimes vm_pager_t pager; 16326f9a767SRodney W. Grimes vm_page_t *m; 16426f9a767SRodney W. Grimes int count; 16526f9a767SRodney W. Grimes int reqpage; 166df8bae1dSRodney W. Grimes boolean_t sync; 167df8bae1dSRodney W. Grimes { 16826f9a767SRodney W. Grimes extern boolean_t vm_page_zero_fill(); 16926f9a767SRodney W. Grimes extern int vm_pageout_count; 17026f9a767SRodney W. Grimes int i; 171df8bae1dSRodney W. Grimes 172df8bae1dSRodney W. Grimes if (pager == NULL) { 17326f9a767SRodney W. Grimes for (i=0;i<count;i++) { 17426f9a767SRodney W. Grimes if( i != reqpage) { 17526f9a767SRodney W. Grimes PAGE_WAKEUP(m[i]); 17626f9a767SRodney W. Grimes vm_page_free(m[i]); 177df8bae1dSRodney W. Grimes } 17826f9a767SRodney W. Grimes } 17926f9a767SRodney W. Grimes vm_page_zero_fill(m[reqpage]); 18026f9a767SRodney W. Grimes return VM_PAGER_OK; 18126f9a767SRodney W. Grimes } 18226f9a767SRodney W. Grimes 18326f9a767SRodney W. Grimes if( pager->pg_ops->pgo_getpages == 0) { 18426f9a767SRodney W. Grimes for(i=0;i<count;i++) { 18526f9a767SRodney W. Grimes if( i != reqpage) { 18626f9a767SRodney W. Grimes PAGE_WAKEUP(m[i]); 18726f9a767SRodney W. Grimes vm_page_free(m[i]); 18826f9a767SRodney W. Grimes } 18926f9a767SRodney W. Grimes } 19026f9a767SRodney W. Grimes return(VM_PAGER_GET(pager, m[reqpage], sync)); 19126f9a767SRodney W. Grimes } else { 19226f9a767SRodney W. Grimes return(VM_PAGER_GET_MULTI(pager, m, count, reqpage, sync)); 19326f9a767SRodney W. Grimes } 194df8bae1dSRodney W. Grimes } 195df8bae1dSRodney W. Grimes 196df8bae1dSRodney W. Grimes int 19726f9a767SRodney W. Grimes vm_pager_put_pages(pager, m, count, sync, rtvals) 198df8bae1dSRodney W. Grimes vm_pager_t pager; 19926f9a767SRodney W. Grimes vm_page_t *m; 20026f9a767SRodney W. Grimes int count; 201df8bae1dSRodney W. Grimes boolean_t sync; 20226f9a767SRodney W. Grimes int *rtvals; 203df8bae1dSRodney W. Grimes { 20426f9a767SRodney W. Grimes int i; 20526f9a767SRodney W. Grimes 20626f9a767SRodney W. Grimes if( pager->pg_ops->pgo_putpages) 20726f9a767SRodney W. Grimes return(VM_PAGER_PUT_MULTI(pager, m, count, sync, rtvals)); 20826f9a767SRodney W. Grimes else { 20926f9a767SRodney W. Grimes for(i=0;i<count;i++) { 21026f9a767SRodney W. Grimes rtvals[i] = VM_PAGER_PUT( pager, m[i], sync); 21126f9a767SRodney W. Grimes } 21226f9a767SRodney W. Grimes return rtvals[0]; 21326f9a767SRodney W. Grimes } 214df8bae1dSRodney W. Grimes } 215df8bae1dSRodney W. Grimes 216df8bae1dSRodney W. Grimes boolean_t 217df8bae1dSRodney W. Grimes vm_pager_has_page(pager, offset) 218df8bae1dSRodney W. Grimes vm_pager_t pager; 219df8bae1dSRodney W. Grimes vm_offset_t offset; 220df8bae1dSRodney W. Grimes { 221df8bae1dSRodney W. Grimes if (pager == NULL) 222df8bae1dSRodney W. Grimes panic("vm_pager_has_page: null pager"); 223df8bae1dSRodney W. Grimes return ((*pager->pg_ops->pgo_haspage)(pager, offset)); 224df8bae1dSRodney W. Grimes } 225df8bae1dSRodney W. Grimes 226df8bae1dSRodney W. Grimes /* 227df8bae1dSRodney W. Grimes * Called by pageout daemon before going back to sleep. 228df8bae1dSRodney W. Grimes * Gives pagers a chance to clean up any completed async pageing operations. 229df8bae1dSRodney W. Grimes */ 230df8bae1dSRodney W. Grimes void 231df8bae1dSRodney W. Grimes vm_pager_sync() 232df8bae1dSRodney W. Grimes { 233df8bae1dSRodney W. Grimes struct pagerops **pgops; 234df8bae1dSRodney W. Grimes 235df8bae1dSRodney W. Grimes for (pgops = pagertab; pgops < &pagertab[npagers]; pgops++) 236df8bae1dSRodney W. Grimes if (pgops) 23726f9a767SRodney W. Grimes (*(*pgops)->pgo_putpage)(NULL, NULL, 0); 238df8bae1dSRodney W. Grimes } 239df8bae1dSRodney W. Grimes 24026f9a767SRodney W. Grimes #if 0 241df8bae1dSRodney W. Grimes void 242df8bae1dSRodney W. Grimes vm_pager_cluster(pager, offset, loff, hoff) 243df8bae1dSRodney W. Grimes vm_pager_t pager; 244df8bae1dSRodney W. Grimes vm_offset_t offset; 245df8bae1dSRodney W. Grimes vm_offset_t *loff; 246df8bae1dSRodney W. Grimes vm_offset_t *hoff; 247df8bae1dSRodney W. Grimes { 248df8bae1dSRodney W. Grimes if (pager == NULL) 249df8bae1dSRodney W. Grimes panic("vm_pager_cluster: null pager"); 250df8bae1dSRodney W. Grimes return ((*pager->pg_ops->pgo_cluster)(pager, offset, loff, hoff)); 251df8bae1dSRodney W. Grimes } 25226f9a767SRodney W. Grimes #endif 253df8bae1dSRodney W. Grimes 254df8bae1dSRodney W. Grimes vm_offset_t 25526f9a767SRodney W. Grimes vm_pager_map_page(m) 256df8bae1dSRodney W. Grimes vm_page_t m; 25726f9a767SRodney W. Grimes { 25826f9a767SRodney W. Grimes vm_offset_t kva; 259df8bae1dSRodney W. Grimes 26026f9a767SRodney W. Grimes kva = kmem_alloc_wait(pager_map, PAGE_SIZE); 26126f9a767SRodney W. Grimes pmap_enter(vm_map_pmap(pager_map), kva, VM_PAGE_TO_PHYS(m), 262df8bae1dSRodney W. Grimes VM_PROT_DEFAULT, TRUE); 263df8bae1dSRodney W. Grimes return(kva); 264df8bae1dSRodney W. Grimes } 265df8bae1dSRodney W. Grimes 266df8bae1dSRodney W. Grimes void 26726f9a767SRodney W. Grimes vm_pager_unmap_page(kva) 268df8bae1dSRodney W. Grimes vm_offset_t kva; 269df8bae1dSRodney W. Grimes { 27026f9a767SRodney W. Grimes kmem_free_wakeup(pager_map, kva, PAGE_SIZE); 271df8bae1dSRodney W. Grimes } 272df8bae1dSRodney W. Grimes 273df8bae1dSRodney W. Grimes vm_page_t 274df8bae1dSRodney W. Grimes vm_pager_atop(kva) 275df8bae1dSRodney W. Grimes vm_offset_t kva; 276df8bae1dSRodney W. Grimes { 277df8bae1dSRodney W. Grimes vm_offset_t pa; 278df8bae1dSRodney W. Grimes 279df8bae1dSRodney W. Grimes pa = pmap_extract(vm_map_pmap(pager_map), kva); 280df8bae1dSRodney W. Grimes if (pa == 0) 281df8bae1dSRodney W. Grimes panic("vm_pager_atop"); 282df8bae1dSRodney W. Grimes return (PHYS_TO_VM_PAGE(pa)); 283df8bae1dSRodney W. Grimes } 284df8bae1dSRodney W. Grimes 285df8bae1dSRodney W. Grimes vm_pager_t 286df8bae1dSRodney W. Grimes vm_pager_lookup(pglist, handle) 287df8bae1dSRodney W. Grimes register struct pagerlst *pglist; 288df8bae1dSRodney W. Grimes caddr_t handle; 289df8bae1dSRodney W. Grimes { 290df8bae1dSRodney W. Grimes register vm_pager_t pager; 291df8bae1dSRodney W. Grimes 292df8bae1dSRodney W. Grimes for (pager = pglist->tqh_first; pager; pager = pager->pg_list.tqe_next) 293df8bae1dSRodney W. Grimes if (pager->pg_handle == handle) 294df8bae1dSRodney W. Grimes return (pager); 295df8bae1dSRodney W. Grimes return (NULL); 296df8bae1dSRodney W. Grimes } 297df8bae1dSRodney W. Grimes 298df8bae1dSRodney W. Grimes /* 299df8bae1dSRodney W. Grimes * This routine gains a reference to the object. 300df8bae1dSRodney W. Grimes * Explicit deallocation is necessary. 301df8bae1dSRodney W. Grimes */ 302df8bae1dSRodney W. Grimes int 303df8bae1dSRodney W. Grimes pager_cache(object, should_cache) 304df8bae1dSRodney W. Grimes vm_object_t object; 305df8bae1dSRodney W. Grimes boolean_t should_cache; 306df8bae1dSRodney W. Grimes { 307df8bae1dSRodney W. Grimes if (object == NULL) 308df8bae1dSRodney W. Grimes return (KERN_INVALID_ARGUMENT); 309df8bae1dSRodney W. Grimes 310df8bae1dSRodney W. Grimes vm_object_cache_lock(); 311df8bae1dSRodney W. Grimes vm_object_lock(object); 312df8bae1dSRodney W. Grimes if (should_cache) 313df8bae1dSRodney W. Grimes object->flags |= OBJ_CANPERSIST; 314df8bae1dSRodney W. Grimes else 315df8bae1dSRodney W. Grimes object->flags &= ~OBJ_CANPERSIST; 316df8bae1dSRodney W. Grimes vm_object_unlock(object); 317df8bae1dSRodney W. Grimes vm_object_cache_unlock(); 318df8bae1dSRodney W. Grimes 319df8bae1dSRodney W. Grimes vm_object_deallocate(object); 320df8bae1dSRodney W. Grimes 321df8bae1dSRodney W. Grimes return (KERN_SUCCESS); 322df8bae1dSRodney W. Grimes } 323