145749Smckusick /* 245749Smckusick * Copyright (c) 1990 University of Utah. 345749Smckusick * Copyright (c) 1991 The Regents of the University of California. 445749Smckusick * All rights reserved. 545749Smckusick * 645749Smckusick * This code is derived from software contributed to Berkeley by 745749Smckusick * the Systems Programming Group of the University of Utah Computer 845749Smckusick * Science Department. 945749Smckusick * 1045749Smckusick * %sccs.include.redist.c% 1145749Smckusick * 12*48386Skarels * @(#)device_pager.c 7.2 (Berkeley) 04/20/91 1345749Smckusick */ 1445749Smckusick 1545749Smckusick /* 1645749Smckusick * Page to/from special files. 1745749Smckusick */ 1845749Smckusick 1945749Smckusick #include "devpager.h" 2045749Smckusick #if NDEVPAGER > 0 2145749Smckusick 2245749Smckusick #include "param.h" 2345749Smckusick #include "conf.h" 2445749Smckusick #include "mman.h" 2545749Smckusick #include "malloc.h" 2645749Smckusick 27*48386Skarels #include "vm.h" 28*48386Skarels #include "vm_page.h" 29*48386Skarels #include "vm_kern.h" 30*48386Skarels #include "device_pager.h" 3145749Smckusick 3245749Smckusick queue_head_t dev_pager_list; /* list of managed devices */ 3345749Smckusick 3445749Smckusick #ifdef DEBUG 3545749Smckusick int dpagerdebug = 0; 3645749Smckusick #define DDB_FOLLOW 0x01 3745749Smckusick #define DDB_INIT 0x02 3845749Smckusick #define DDB_ALLOC 0x04 3945749Smckusick #define DDB_FAIL 0x08 4045749Smckusick #endif 4145749Smckusick 4245749Smckusick void 4345749Smckusick dev_pager_init() 4445749Smckusick { 4545749Smckusick #ifdef DEBUG 4645749Smckusick if (dpagerdebug & DDB_FOLLOW) 4745749Smckusick printf("dev_pager_init()\n"); 4845749Smckusick #endif 4945749Smckusick queue_init(&dev_pager_list); 5045749Smckusick } 5145749Smckusick 5245749Smckusick vm_pager_t 5345749Smckusick dev_pager_alloc(handle, size, prot) 5445749Smckusick caddr_t handle; 5545749Smckusick vm_size_t size; 5645749Smckusick vm_prot_t prot; 5745749Smckusick { 5845749Smckusick dev_t dev; 5945749Smckusick vm_pager_t pager; 6045749Smckusick int (*mapfunc)(), nprot; 6145749Smckusick register vm_object_t object; 6245749Smckusick register vm_page_t page; 6345749Smckusick register dev_pager_t devp; 6445749Smckusick register int npages, off; 65*48386Skarels extern int nullop(), enodev(); 6645749Smckusick 6745749Smckusick 6845749Smckusick #ifdef DEBUG 6945749Smckusick if (dpagerdebug & DDB_FOLLOW) 7045749Smckusick printf("dev_pager_alloc(%x, %x, %x)\n", handle, size, prot); 7145749Smckusick #endif 7245749Smckusick /* 7345749Smckusick * Pageout to device, should never happen. 7445749Smckusick */ 7545749Smckusick if (handle == NULL) 7645749Smckusick panic("dev_pager_alloc called"); 7745749Smckusick 7845749Smckusick /* 7945749Smckusick * Look it up, creating as necessary 8045749Smckusick */ 8145749Smckusick pager = vm_pager_lookup(&dev_pager_list, handle); 82*48386Skarels if (pager == NULL) { 8345749Smckusick /* 8445749Smckusick * Validation. Make sure this device can be mapped 8545749Smckusick * and that range to map is acceptible to device. 8645749Smckusick */ 8745749Smckusick dev = (dev_t)handle; 8845749Smckusick mapfunc = cdevsw[major(dev)].d_mmap; 89*48386Skarels if (!mapfunc || mapfunc == enodev || mapfunc == nullop) 90*48386Skarels return(NULL); 9145749Smckusick nprot = 0; 9245749Smckusick if (prot & VM_PROT_READ) 9345749Smckusick nprot |= PROT_READ; 9445749Smckusick if (prot & VM_PROT_WRITE) 9545749Smckusick nprot |= PROT_WRITE; 9645749Smckusick if (prot & VM_PROT_EXECUTE) 9745749Smckusick nprot |= PROT_EXEC; 9845749Smckusick npages = atop(round_page(size)); 9945749Smckusick for (off = 0; npages--; off += PAGE_SIZE) 10045749Smckusick if ((*mapfunc)(dev, off, nprot) == -1) 101*48386Skarels return(NULL); 10245749Smckusick /* 10345749Smckusick * Allocate and initialize pager structs 10445749Smckusick */ 10545749Smckusick pager = (vm_pager_t)malloc(sizeof *pager, M_VMPAGER, M_WAITOK); 106*48386Skarels if (pager == NULL) 107*48386Skarels return(NULL); 10845749Smckusick devp = (dev_pager_t)malloc(sizeof *devp, M_VMPGDATA, M_WAITOK); 109*48386Skarels if (devp == NULL) { 11045749Smckusick free((caddr_t)pager, M_VMPAGER); 111*48386Skarels return(NULL); 11245749Smckusick } 11345749Smckusick devp->devp_dev = dev; 11445749Smckusick devp->devp_npages = atop(round_page(size)); 11545749Smckusick pager->pg_handle = handle; 11645749Smckusick pager->pg_ops = &devicepagerops; 11745749Smckusick pager->pg_type = PG_DEVICE; 11845749Smckusick pager->pg_data = (caddr_t)devp; 11945749Smckusick /* 12045749Smckusick * Allocate object and vm_page structures to describe memory 12145749Smckusick */ 12245749Smckusick npages = devp->devp_npages; 12345749Smckusick object = devp->devp_object = vm_object_allocate(ptoa(npages)); 12445749Smckusick vm_object_enter(object, pager); 12545749Smckusick vm_object_setpager(object, pager, (vm_offset_t)0, FALSE); 12645749Smckusick devp->devp_pages = (vm_page_t) 12745749Smckusick kmem_alloc(kernel_map, npages*sizeof(struct vm_page)); 12845749Smckusick off = 0; 12945749Smckusick for (page = devp->devp_pages; 13045749Smckusick page < &devp->devp_pages[npages]; page++) { 13145749Smckusick vm_object_lock(object); 13245749Smckusick vm_page_init(page, object, off); 13345749Smckusick page->phys_addr = 13445749Smckusick pmap_phys_address((*mapfunc)(dev, off, nprot)); 13545749Smckusick page->wire_count = 1; 13645749Smckusick page->fictitious = TRUE; 13745749Smckusick PAGE_WAKEUP(page); 13845749Smckusick vm_object_unlock(object); 13945749Smckusick off += PAGE_SIZE; 14045749Smckusick } 14145749Smckusick /* 14245749Smckusick * Finally, put it on the managed list so other can find it. 14345749Smckusick */ 14445749Smckusick queue_enter(&dev_pager_list, devp, dev_pager_t, devp_list); 14545749Smckusick #ifdef DEBUG 14645749Smckusick if (dpagerdebug & DDB_ALLOC) 14745749Smckusick printf("dev_pager_alloc: pages %d@%x\n", 14845749Smckusick devp->devp_npages, devp->devp_pages); 14945749Smckusick #endif 15045749Smckusick } else { 15145749Smckusick /* 15245749Smckusick * vm_object_lookup() gains a reference and also 15345749Smckusick * removes the object from the cache. 15445749Smckusick */ 15545749Smckusick devp = (dev_pager_t)pager->pg_data; 15645749Smckusick if (vm_object_lookup(pager) != devp->devp_object) 15745749Smckusick panic("dev_pager_setup: bad object"); 15845749Smckusick } 15945749Smckusick #ifdef DEBUG 16045749Smckusick if (dpagerdebug & DDB_ALLOC) { 16145749Smckusick printf("dev_pager_alloc: pager %x devp %x object %x\n", 16245749Smckusick pager, devp, object); 16345749Smckusick vm_object_print(object, FALSE); 16445749Smckusick } 16545749Smckusick #endif 16645749Smckusick return(pager); 16745749Smckusick 16845749Smckusick } 16945749Smckusick 17045749Smckusick void 17145749Smckusick dev_pager_dealloc(pager) 17245749Smckusick vm_pager_t pager; 17345749Smckusick { 17445749Smckusick dev_pager_t devp = (dev_pager_t)pager->pg_data; 17545749Smckusick register vm_object_t object; 17645749Smckusick 17745749Smckusick #ifdef DEBUG 17845749Smckusick if (dpagerdebug & DDB_FOLLOW) 17945749Smckusick printf("dev_pager_dealloc(%x)\n", pager); 18045749Smckusick #endif 18145749Smckusick queue_remove(&dev_pager_list, devp, dev_pager_t, devp_list); 18245749Smckusick object = devp->devp_object; 18345749Smckusick #ifdef DEBUG 18445749Smckusick if (dpagerdebug & DDB_ALLOC) 18545749Smckusick printf("dev_pager_dealloc: devp %x object %x pages %d@%x\n", 18645749Smckusick devp, object, devp->devp_npages, devp->devp_pages); 18745749Smckusick #endif 18845749Smckusick while (!queue_empty(&object->memq)) 18945749Smckusick vm_page_remove((vm_page_t)queue_first(&object->memq)); 19045749Smckusick kmem_free(kernel_map, devp->devp_pages, 19145749Smckusick devp->devp_npages * sizeof(struct vm_page)); 19245749Smckusick free((caddr_t)devp, M_VMPGDATA); 19345749Smckusick pager->pg_data = 0; 19445749Smckusick } 19545749Smckusick 19645749Smckusick dev_pager_getpage(pager, m, sync) 19745749Smckusick vm_pager_t pager; 19845749Smckusick vm_page_t m; 19945749Smckusick boolean_t sync; 20045749Smckusick { 20145749Smckusick #ifdef DEBUG 20245749Smckusick if (dpagerdebug & DDB_FOLLOW) 20345749Smckusick printf("dev_pager_getpage(%x, %x)\n", pager, m); 20445749Smckusick #endif 20545749Smckusick return(VM_PAGER_BAD); 20645749Smckusick } 20745749Smckusick 20845749Smckusick dev_pager_putpage(pager, m, sync) 20945749Smckusick vm_pager_t pager; 21045749Smckusick vm_page_t m; 21145749Smckusick boolean_t sync; 21245749Smckusick { 21345749Smckusick #ifdef DEBUG 21445749Smckusick if (dpagerdebug & DDB_FOLLOW) 21545749Smckusick printf("dev_pager_putpage(%x, %x)\n", pager, m); 21645749Smckusick #endif 217*48386Skarels if (pager == NULL) 21845749Smckusick return; 21945749Smckusick panic("dev_pager_putpage called"); 22045749Smckusick } 22145749Smckusick 22245749Smckusick boolean_t 22345749Smckusick dev_pager_haspage(pager, offset) 22445749Smckusick vm_pager_t pager; 22545749Smckusick vm_offset_t offset; 22645749Smckusick { 22745749Smckusick #ifdef DEBUG 22845749Smckusick if (dpagerdebug & DDB_FOLLOW) 22945749Smckusick printf("dev_pager_haspage(%x, %x)\n", pager, offset); 23045749Smckusick #endif 23145749Smckusick return(TRUE); 23245749Smckusick } 23345749Smckusick #endif 234