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