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*52595Storek * @(#)device_pager.c 7.4 (Berkeley) 02/19/92 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 2748386Skarels #include "vm.h" 2848386Skarels #include "vm_page.h" 2948386Skarels #include "vm_kern.h" 3048386Skarels #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; 6548386Skarels 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); 8248386Skarels 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; 8948386Skarels if (!mapfunc || mapfunc == enodev || mapfunc == nullop) 9048386Skarels 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) 10148386Skarels return(NULL); 10245749Smckusick /* 10345749Smckusick * Allocate and initialize pager structs 10445749Smckusick */ 10545749Smckusick pager = (vm_pager_t)malloc(sizeof *pager, M_VMPAGER, M_WAITOK); 10648386Skarels if (pager == NULL) 10748386Skarels return(NULL); 10845749Smckusick devp = (dev_pager_t)malloc(sizeof *devp, M_VMPGDATA, M_WAITOK); 10948386Skarels if (devp == NULL) { 11045749Smckusick free((caddr_t)pager, M_VMPAGER); 11148386Skarels 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); 132*52595Storek 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 14650857Smckusick if (dpagerdebug & DDB_ALLOC) { 14745749Smckusick printf("dev_pager_alloc: pages %d@%x\n", 14845749Smckusick devp->devp_npages, devp->devp_pages); 14950857Smckusick printf("dev_pager_alloc: pager %x devp %x object %x\n", 15050857Smckusick pager, devp, object); 15150857Smckusick vm_object_print(object, FALSE); 15250857Smckusick } 15345749Smckusick #endif 15445749Smckusick } else { 15545749Smckusick /* 15645749Smckusick * vm_object_lookup() gains a reference and also 15745749Smckusick * removes the object from the cache. 15845749Smckusick */ 15945749Smckusick devp = (dev_pager_t)pager->pg_data; 16045749Smckusick if (vm_object_lookup(pager) != devp->devp_object) 16145749Smckusick panic("dev_pager_setup: bad object"); 16245749Smckusick } 16345749Smckusick return(pager); 16445749Smckusick 16545749Smckusick } 16645749Smckusick 16745749Smckusick void 16845749Smckusick dev_pager_dealloc(pager) 16945749Smckusick vm_pager_t pager; 17045749Smckusick { 17145749Smckusick dev_pager_t devp = (dev_pager_t)pager->pg_data; 17245749Smckusick register vm_object_t object; 17345749Smckusick 17445749Smckusick #ifdef DEBUG 17545749Smckusick if (dpagerdebug & DDB_FOLLOW) 17645749Smckusick printf("dev_pager_dealloc(%x)\n", pager); 17745749Smckusick #endif 17845749Smckusick queue_remove(&dev_pager_list, devp, dev_pager_t, devp_list); 17945749Smckusick object = devp->devp_object; 18045749Smckusick #ifdef DEBUG 18145749Smckusick if (dpagerdebug & DDB_ALLOC) 18245749Smckusick printf("dev_pager_dealloc: devp %x object %x pages %d@%x\n", 18345749Smckusick devp, object, devp->devp_npages, devp->devp_pages); 18445749Smckusick #endif 18545749Smckusick while (!queue_empty(&object->memq)) 18645749Smckusick vm_page_remove((vm_page_t)queue_first(&object->memq)); 18745749Smckusick kmem_free(kernel_map, devp->devp_pages, 18845749Smckusick devp->devp_npages * sizeof(struct vm_page)); 18945749Smckusick free((caddr_t)devp, M_VMPGDATA); 19045749Smckusick pager->pg_data = 0; 19145749Smckusick } 19245749Smckusick 19345749Smckusick dev_pager_getpage(pager, m, sync) 19445749Smckusick vm_pager_t pager; 19545749Smckusick vm_page_t m; 19645749Smckusick boolean_t sync; 19745749Smckusick { 19845749Smckusick #ifdef DEBUG 19945749Smckusick if (dpagerdebug & DDB_FOLLOW) 20045749Smckusick printf("dev_pager_getpage(%x, %x)\n", pager, m); 20145749Smckusick #endif 20245749Smckusick return(VM_PAGER_BAD); 20345749Smckusick } 20445749Smckusick 20545749Smckusick dev_pager_putpage(pager, m, sync) 20645749Smckusick vm_pager_t pager; 20745749Smckusick vm_page_t m; 20845749Smckusick boolean_t sync; 20945749Smckusick { 21045749Smckusick #ifdef DEBUG 21145749Smckusick if (dpagerdebug & DDB_FOLLOW) 21245749Smckusick printf("dev_pager_putpage(%x, %x)\n", pager, m); 21345749Smckusick #endif 21448386Skarels if (pager == NULL) 21545749Smckusick return; 21645749Smckusick panic("dev_pager_putpage called"); 21745749Smckusick } 21845749Smckusick 21945749Smckusick boolean_t 22045749Smckusick dev_pager_haspage(pager, offset) 22145749Smckusick vm_pager_t pager; 22245749Smckusick vm_offset_t offset; 22345749Smckusick { 22445749Smckusick #ifdef DEBUG 22545749Smckusick if (dpagerdebug & DDB_FOLLOW) 22645749Smckusick printf("dev_pager_haspage(%x, %x)\n", pager, offset); 22745749Smckusick #endif 22845749Smckusick return(TRUE); 22945749Smckusick } 23045749Smckusick #endif 231