1*45749Smckusick /* 2*45749Smckusick * Copyright (c) 1990 University of Utah. 3*45749Smckusick * Copyright (c) 1991 The Regents of the University of California. 4*45749Smckusick * All rights reserved. 5*45749Smckusick * 6*45749Smckusick * This code is derived from software contributed to Berkeley by 7*45749Smckusick * the Systems Programming Group of the University of Utah Computer 8*45749Smckusick * Science Department. 9*45749Smckusick * 10*45749Smckusick * %sccs.include.redist.c% 11*45749Smckusick * 12*45749Smckusick * @(#)device_pager.c 7.1 (Berkeley) 12/05/90 13*45749Smckusick */ 14*45749Smckusick 15*45749Smckusick /* 16*45749Smckusick * Page to/from special files. 17*45749Smckusick */ 18*45749Smckusick 19*45749Smckusick #include "devpager.h" 20*45749Smckusick #if NDEVPAGER > 0 21*45749Smckusick 22*45749Smckusick #include "param.h" 23*45749Smckusick #include "queue.h" 24*45749Smckusick #include "conf.h" 25*45749Smckusick #include "mman.h" 26*45749Smckusick #include "malloc.h" 27*45749Smckusick #include "uio.h" 28*45749Smckusick 29*45749Smckusick #include "../vm/vm_param.h" 30*45749Smckusick #include "../vm/vm_map.h" 31*45749Smckusick #include "../vm/vm_pager.h" 32*45749Smckusick #include "../vm/vm_page.h" 33*45749Smckusick #include "../vm/vm_kern.h" 34*45749Smckusick #include "../vm/device_pager.h" 35*45749Smckusick 36*45749Smckusick queue_head_t dev_pager_list; /* list of managed devices */ 37*45749Smckusick 38*45749Smckusick #ifdef DEBUG 39*45749Smckusick int dpagerdebug = 0; 40*45749Smckusick #define DDB_FOLLOW 0x01 41*45749Smckusick #define DDB_INIT 0x02 42*45749Smckusick #define DDB_ALLOC 0x04 43*45749Smckusick #define DDB_FAIL 0x08 44*45749Smckusick #endif 45*45749Smckusick 46*45749Smckusick void 47*45749Smckusick dev_pager_init() 48*45749Smckusick { 49*45749Smckusick #ifdef DEBUG 50*45749Smckusick if (dpagerdebug & DDB_FOLLOW) 51*45749Smckusick printf("dev_pager_init()\n"); 52*45749Smckusick #endif 53*45749Smckusick queue_init(&dev_pager_list); 54*45749Smckusick } 55*45749Smckusick 56*45749Smckusick vm_pager_t 57*45749Smckusick dev_pager_alloc(handle, size, prot) 58*45749Smckusick caddr_t handle; 59*45749Smckusick vm_size_t size; 60*45749Smckusick vm_prot_t prot; 61*45749Smckusick { 62*45749Smckusick dev_t dev; 63*45749Smckusick vm_pager_t pager; 64*45749Smckusick int (*mapfunc)(), nprot; 65*45749Smckusick register vm_object_t object; 66*45749Smckusick register vm_page_t page; 67*45749Smckusick register dev_pager_t devp; 68*45749Smckusick register int npages, off; 69*45749Smckusick extern int nulldev(), nodev(); 70*45749Smckusick 71*45749Smckusick 72*45749Smckusick #ifdef DEBUG 73*45749Smckusick if (dpagerdebug & DDB_FOLLOW) 74*45749Smckusick printf("dev_pager_alloc(%x, %x, %x)\n", handle, size, prot); 75*45749Smckusick #endif 76*45749Smckusick /* 77*45749Smckusick * Pageout to device, should never happen. 78*45749Smckusick */ 79*45749Smckusick if (handle == NULL) 80*45749Smckusick panic("dev_pager_alloc called"); 81*45749Smckusick 82*45749Smckusick /* 83*45749Smckusick * Look it up, creating as necessary 84*45749Smckusick */ 85*45749Smckusick pager = vm_pager_lookup(&dev_pager_list, handle); 86*45749Smckusick if (pager == VM_PAGER_NULL) { 87*45749Smckusick /* 88*45749Smckusick * Validation. Make sure this device can be mapped 89*45749Smckusick * and that range to map is acceptible to device. 90*45749Smckusick */ 91*45749Smckusick dev = (dev_t)handle; 92*45749Smckusick mapfunc = cdevsw[major(dev)].d_mmap; 93*45749Smckusick if (!mapfunc || mapfunc == nodev || mapfunc == nulldev) 94*45749Smckusick return(VM_PAGER_NULL); 95*45749Smckusick nprot = 0; 96*45749Smckusick if (prot & VM_PROT_READ) 97*45749Smckusick nprot |= PROT_READ; 98*45749Smckusick if (prot & VM_PROT_WRITE) 99*45749Smckusick nprot |= PROT_WRITE; 100*45749Smckusick if (prot & VM_PROT_EXECUTE) 101*45749Smckusick nprot |= PROT_EXEC; 102*45749Smckusick npages = atop(round_page(size)); 103*45749Smckusick for (off = 0; npages--; off += PAGE_SIZE) 104*45749Smckusick if ((*mapfunc)(dev, off, nprot) == -1) 105*45749Smckusick return(VM_PAGER_NULL); 106*45749Smckusick /* 107*45749Smckusick * Allocate and initialize pager structs 108*45749Smckusick */ 109*45749Smckusick pager = (vm_pager_t)malloc(sizeof *pager, M_VMPAGER, M_WAITOK); 110*45749Smckusick if (pager == VM_PAGER_NULL) 111*45749Smckusick return(VM_PAGER_NULL); 112*45749Smckusick devp = (dev_pager_t)malloc(sizeof *devp, M_VMPGDATA, M_WAITOK); 113*45749Smckusick if (devp == DEV_PAGER_NULL) { 114*45749Smckusick free((caddr_t)pager, M_VMPAGER); 115*45749Smckusick return(VM_PAGER_NULL); 116*45749Smckusick } 117*45749Smckusick devp->devp_dev = dev; 118*45749Smckusick devp->devp_npages = atop(round_page(size)); 119*45749Smckusick pager->pg_handle = handle; 120*45749Smckusick pager->pg_ops = &devicepagerops; 121*45749Smckusick pager->pg_type = PG_DEVICE; 122*45749Smckusick pager->pg_data = (caddr_t)devp; 123*45749Smckusick /* 124*45749Smckusick * Allocate object and vm_page structures to describe memory 125*45749Smckusick */ 126*45749Smckusick npages = devp->devp_npages; 127*45749Smckusick object = devp->devp_object = vm_object_allocate(ptoa(npages)); 128*45749Smckusick vm_object_enter(object, pager); 129*45749Smckusick vm_object_setpager(object, pager, (vm_offset_t)0, FALSE); 130*45749Smckusick devp->devp_pages = (vm_page_t) 131*45749Smckusick kmem_alloc(kernel_map, npages*sizeof(struct vm_page)); 132*45749Smckusick off = 0; 133*45749Smckusick for (page = devp->devp_pages; 134*45749Smckusick page < &devp->devp_pages[npages]; page++) { 135*45749Smckusick vm_object_lock(object); 136*45749Smckusick vm_page_init(page, object, off); 137*45749Smckusick page->phys_addr = 138*45749Smckusick pmap_phys_address((*mapfunc)(dev, off, nprot)); 139*45749Smckusick page->wire_count = 1; 140*45749Smckusick page->fictitious = TRUE; 141*45749Smckusick PAGE_WAKEUP(page); 142*45749Smckusick vm_object_unlock(object); 143*45749Smckusick off += PAGE_SIZE; 144*45749Smckusick } 145*45749Smckusick /* 146*45749Smckusick * Finally, put it on the managed list so other can find it. 147*45749Smckusick */ 148*45749Smckusick queue_enter(&dev_pager_list, devp, dev_pager_t, devp_list); 149*45749Smckusick #ifdef DEBUG 150*45749Smckusick if (dpagerdebug & DDB_ALLOC) 151*45749Smckusick printf("dev_pager_alloc: pages %d@%x\n", 152*45749Smckusick devp->devp_npages, devp->devp_pages); 153*45749Smckusick #endif 154*45749Smckusick } else { 155*45749Smckusick /* 156*45749Smckusick * vm_object_lookup() gains a reference and also 157*45749Smckusick * removes the object from the cache. 158*45749Smckusick */ 159*45749Smckusick devp = (dev_pager_t)pager->pg_data; 160*45749Smckusick if (vm_object_lookup(pager) != devp->devp_object) 161*45749Smckusick panic("dev_pager_setup: bad object"); 162*45749Smckusick } 163*45749Smckusick #ifdef DEBUG 164*45749Smckusick if (dpagerdebug & DDB_ALLOC) { 165*45749Smckusick printf("dev_pager_alloc: pager %x devp %x object %x\n", 166*45749Smckusick pager, devp, object); 167*45749Smckusick vm_object_print(object, FALSE); 168*45749Smckusick } 169*45749Smckusick #endif 170*45749Smckusick return(pager); 171*45749Smckusick 172*45749Smckusick } 173*45749Smckusick 174*45749Smckusick void 175*45749Smckusick dev_pager_dealloc(pager) 176*45749Smckusick vm_pager_t pager; 177*45749Smckusick { 178*45749Smckusick dev_pager_t devp = (dev_pager_t)pager->pg_data; 179*45749Smckusick register vm_object_t object; 180*45749Smckusick 181*45749Smckusick #ifdef DEBUG 182*45749Smckusick if (dpagerdebug & DDB_FOLLOW) 183*45749Smckusick printf("dev_pager_dealloc(%x)\n", pager); 184*45749Smckusick #endif 185*45749Smckusick queue_remove(&dev_pager_list, devp, dev_pager_t, devp_list); 186*45749Smckusick object = devp->devp_object; 187*45749Smckusick #ifdef DEBUG 188*45749Smckusick if (dpagerdebug & DDB_ALLOC) 189*45749Smckusick printf("dev_pager_dealloc: devp %x object %x pages %d@%x\n", 190*45749Smckusick devp, object, devp->devp_npages, devp->devp_pages); 191*45749Smckusick #endif 192*45749Smckusick while (!queue_empty(&object->memq)) 193*45749Smckusick vm_page_remove((vm_page_t)queue_first(&object->memq)); 194*45749Smckusick kmem_free(kernel_map, devp->devp_pages, 195*45749Smckusick devp->devp_npages * sizeof(struct vm_page)); 196*45749Smckusick free((caddr_t)devp, M_VMPGDATA); 197*45749Smckusick pager->pg_data = 0; 198*45749Smckusick } 199*45749Smckusick 200*45749Smckusick dev_pager_getpage(pager, m, sync) 201*45749Smckusick vm_pager_t pager; 202*45749Smckusick vm_page_t m; 203*45749Smckusick boolean_t sync; 204*45749Smckusick { 205*45749Smckusick #ifdef DEBUG 206*45749Smckusick if (dpagerdebug & DDB_FOLLOW) 207*45749Smckusick printf("dev_pager_getpage(%x, %x)\n", pager, m); 208*45749Smckusick #endif 209*45749Smckusick return(VM_PAGER_BAD); 210*45749Smckusick } 211*45749Smckusick 212*45749Smckusick dev_pager_putpage(pager, m, sync) 213*45749Smckusick vm_pager_t pager; 214*45749Smckusick vm_page_t m; 215*45749Smckusick boolean_t sync; 216*45749Smckusick { 217*45749Smckusick #ifdef DEBUG 218*45749Smckusick if (dpagerdebug & DDB_FOLLOW) 219*45749Smckusick printf("dev_pager_putpage(%x, %x)\n", pager, m); 220*45749Smckusick #endif 221*45749Smckusick if (pager == VM_PAGER_NULL) 222*45749Smckusick return; 223*45749Smckusick panic("dev_pager_putpage called"); 224*45749Smckusick } 225*45749Smckusick 226*45749Smckusick boolean_t 227*45749Smckusick dev_pager_haspage(pager, offset) 228*45749Smckusick vm_pager_t pager; 229*45749Smckusick vm_offset_t offset; 230*45749Smckusick { 231*45749Smckusick #ifdef DEBUG 232*45749Smckusick if (dpagerdebug & DDB_FOLLOW) 233*45749Smckusick printf("dev_pager_haspage(%x, %x)\n", pager, offset); 234*45749Smckusick #endif 235*45749Smckusick return(TRUE); 236*45749Smckusick } 237*45749Smckusick #endif 238