device_pager.c revision 43129
11541Srgrimes/* 21541Srgrimes * Copyright (c) 1990 University of Utah. 31541Srgrimes * Copyright (c) 1991, 1993 41541Srgrimes * The Regents of the University of California. All rights reserved. 51541Srgrimes * 61541Srgrimes * This code is derived from software contributed to Berkeley by 71541Srgrimes * the Systems Programming Group of the University of Utah Computer 81541Srgrimes * Science Department. 91541Srgrimes * 101541Srgrimes * Redistribution and use in source and binary forms, with or without 111541Srgrimes * modification, are permitted provided that the following conditions 121541Srgrimes * are met: 131541Srgrimes * 1. Redistributions of source code must retain the above copyright 141541Srgrimes * notice, this list of conditions and the following disclaimer. 151541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 161541Srgrimes * notice, this list of conditions and the following disclaimer in the 171541Srgrimes * documentation and/or other materials provided with the distribution. 181541Srgrimes * 3. All advertising materials mentioning features or use of this software 191541Srgrimes * must display the following acknowledgement: 201541Srgrimes * This product includes software developed by the University of 211541Srgrimes * California, Berkeley and its contributors. 221541Srgrimes * 4. Neither the name of the University nor the names of its contributors 231541Srgrimes * may be used to endorse or promote products derived from this software 241541Srgrimes * without specific prior written permission. 251541Srgrimes * 261541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 271541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 281541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 291541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 301541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 311541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 321541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 331541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 341541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 351541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 361541Srgrimes * SUCH DAMAGE. 371541Srgrimes * 381549Srgrimes * @(#)device_pager.c 8.1 (Berkeley) 6/11/93 3943129Sdillon * $Id: device_pager.c,v 1.38 1999/01/21 08:29:09 dillon Exp $ 401541Srgrimes */ 411541Srgrimes 421541Srgrimes#include <sys/param.h> 431541Srgrimes#include <sys/systm.h> 441541Srgrimes#include <sys/conf.h> 451541Srgrimes#include <sys/mman.h> 461541Srgrimes#include <sys/malloc.h> 471541Srgrimes 481541Srgrimes#include <vm/vm.h> 4912662Sdg#include <vm/vm_prot.h> 5012662Sdg#include <vm/vm_object.h> 511541Srgrimes#include <vm/vm_page.h> 529507Sdg#include <vm/vm_pager.h> 5340558Sdg#include <vm/vm_zone.h> 541541Srgrimes 5512820Sphkstatic void dev_pager_init __P((void)); 5640286Sdgstatic vm_object_t dev_pager_alloc __P((void *, vm_ooffset_t, vm_prot_t, 5712820Sphk vm_ooffset_t)); 5812820Sphkstatic void dev_pager_dealloc __P((vm_object_t)); 5912820Sphkstatic int dev_pager_getpages __P((vm_object_t, vm_page_t *, int, int)); 6043129Sdillonstatic void dev_pager_putpages __P((vm_object_t, vm_page_t *, int, 6112820Sphk boolean_t, int *)); 6212820Sphkstatic boolean_t dev_pager_haspage __P((vm_object_t, vm_pindex_t, int *, 6312820Sphk int *)); 641541Srgrimes 6512820Sphk/* list of device pager objects */ 6612820Sphkstatic struct pagerlst dev_pager_object_list; 6712820Sphk 6840558Sdgstatic vm_zone_t fakepg_zone; 6940558Sdgstatic struct vm_zone fakepg_zone_store; 7012820Sphk 715455Sdgstatic vm_page_t dev_pager_getfake __P((vm_offset_t)); 725455Sdgstatic void dev_pager_putfake __P((vm_page_t)); 731541Srgrimes 749507Sdgstatic int dev_pager_alloc_lock, dev_pager_alloc_lock_want; 759507Sdg 761541Srgrimesstruct pagerops devicepagerops = { 771541Srgrimes dev_pager_init, 781541Srgrimes dev_pager_alloc, 791541Srgrimes dev_pager_dealloc, 809507Sdg dev_pager_getpages, 819507Sdg dev_pager_putpages, 829507Sdg dev_pager_haspage, 839507Sdg NULL 841541Srgrimes}; 851541Srgrimes 8612820Sphkstatic void 871541Srgrimesdev_pager_init() 881541Srgrimes{ 899507Sdg TAILQ_INIT(&dev_pager_object_list); 9040558Sdg fakepg_zone = &fakepg_zone_store; 9140558Sdg zinitna(fakepg_zone, NULL, "DP fakepg", sizeof(struct vm_page), 0, 0, 2); 921541Srgrimes} 931541Srgrimes 9412820Sphkstatic vm_object_t 9540286Sdgdev_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot, vm_ooffset_t foff) 961541Srgrimes{ 971541Srgrimes dev_t dev; 9812591Sbde d_mmap_t *mapfunc; 991541Srgrimes vm_object_t object; 10041004Sdfr unsigned int npages; 10141004Sdfr vm_offset_t off; 1021541Srgrimes 1031541Srgrimes /* 1041541Srgrimes * Make sure this device can be mapped. 1051541Srgrimes */ 10637649Sbde dev = (dev_t) (uintptr_t) handle; 10712813Sjulian mapfunc = cdevsw[major(dev)]->d_mmap; 10812610Sbde if (mapfunc == NULL || mapfunc == (d_mmap_t *)nullop) { 10912610Sbde printf("obsolete map function %p\n", (void *)mapfunc); 1105455Sdg return (NULL); 11112610Sbde } 1121541Srgrimes 1131541Srgrimes /* 1141541Srgrimes * Offset should be page aligned. 1151541Srgrimes */ 11615583Sphk if (foff & PAGE_MASK) 1175455Sdg return (NULL); 1181541Srgrimes 11940286Sdg size = round_page(size); 12040286Sdg 1211541Srgrimes /* 1225455Sdg * Check that the specified range of the device allows the desired 1235455Sdg * protection. 1248876Srgrimes * 1251541Srgrimes * XXX assumes VM_PROT_* == PROT_* 1261541Srgrimes */ 12740286Sdg npages = OFF_TO_IDX(size); 1281541Srgrimes for (off = foff; npages--; off += PAGE_SIZE) 1295455Sdg if ((*mapfunc) (dev, off, (int) prot) == -1) 1305455Sdg return (NULL); 1311541Srgrimes 1321541Srgrimes /* 1339507Sdg * Lock to prevent object creation race contion. 1349507Sdg */ 1359507Sdg while (dev_pager_alloc_lock) { 1369507Sdg dev_pager_alloc_lock_want++; 1379507Sdg tsleep(&dev_pager_alloc_lock, PVM, "dvpall", 0); 1389507Sdg dev_pager_alloc_lock_want--; 1399507Sdg } 1409507Sdg dev_pager_alloc_lock = 1; 1419507Sdg 1429507Sdg /* 1431541Srgrimes * Look up pager, creating as necessary. 1441541Srgrimes */ 1459507Sdg object = vm_pager_object_lookup(&dev_pager_object_list, handle); 1469507Sdg if (object == NULL) { 1471541Srgrimes /* 1481541Srgrimes * Allocate object and associate it with the pager. 1491541Srgrimes */ 15012767Sdyson object = vm_object_allocate(OBJT_DEVICE, 15140286Sdg OFF_TO_IDX(foff + size)); 1529507Sdg object->handle = handle; 1539507Sdg TAILQ_INIT(&object->un_pager.devp.devp_pglist); 1549507Sdg TAILQ_INSERT_TAIL(&dev_pager_object_list, object, pager_object_list); 1551541Srgrimes } else { 1561541Srgrimes /* 1576585Sdg * Gain a reference to the object. 1581541Srgrimes */ 1599507Sdg vm_object_reference(object); 16040286Sdg if (OFF_TO_IDX(foff + size) > object->size) 16140286Sdg object->size = OFF_TO_IDX(foff + size); 1621541Srgrimes } 1639507Sdg 1649507Sdg dev_pager_alloc_lock = 0; 1659507Sdg if (dev_pager_alloc_lock_want) 1669507Sdg wakeup(&dev_pager_alloc_lock); 1679507Sdg 1689507Sdg return (object); 1691541Srgrimes} 1701541Srgrimes 17112820Sphkstatic void 1729507Sdgdev_pager_dealloc(object) 1739507Sdg vm_object_t object; 1741541Srgrimes{ 1751541Srgrimes vm_page_t m; 1761541Srgrimes 1779507Sdg TAILQ_REMOVE(&dev_pager_object_list, object, pager_object_list); 1781541Srgrimes /* 1791541Srgrimes * Free up our fake pages. 1801541Srgrimes */ 18115809Sdyson while ((m = TAILQ_FIRST(&object->un_pager.devp.devp_pglist)) != 0) { 1829507Sdg TAILQ_REMOVE(&object->un_pager.devp.devp_pglist, m, pageq); 1831541Srgrimes dev_pager_putfake(m); 1841541Srgrimes } 1851541Srgrimes} 1861541Srgrimes 18712820Sphkstatic int 1889507Sdgdev_pager_getpages(object, m, count, reqpage) 1899507Sdg vm_object_t object; 1909507Sdg vm_page_t *m; 1919507Sdg int count; 1929507Sdg int reqpage; 1931541Srgrimes{ 19412767Sdyson vm_offset_t offset; 19512767Sdyson vm_offset_t paddr; 1961541Srgrimes vm_page_t page; 1971541Srgrimes dev_t dev; 1989507Sdg int i, s; 19912591Sbde d_mmap_t *mapfunc; 20012591Sbde int prot; 2011541Srgrimes 20237649Sbde dev = (dev_t) (uintptr_t) object->handle; 20342957Sdillon offset = m[reqpage]->pindex; 2041541Srgrimes prot = PROT_READ; /* XXX should pass in? */ 20512813Sjulian mapfunc = cdevsw[major(dev)]->d_mmap; 2061549Srgrimes 20712610Sbde if (mapfunc == NULL || mapfunc == (d_mmap_t *)nullop) 2081541Srgrimes panic("dev_pager_getpage: no map function"); 2091549Srgrimes 21041004Sdfr paddr = pmap_phys_address((*mapfunc) ((dev_t) dev, (vm_offset_t) offset << PAGE_SHIFT, prot)); 21142408Seivind KASSERT(paddr != -1,("dev_pager_getpage: map function returns error")); 2121541Srgrimes /* 2139507Sdg * Replace the passed in reqpage page with our own fake page and free up the 2149507Sdg * all of the original pages. 2151541Srgrimes */ 2161541Srgrimes page = dev_pager_getfake(paddr); 2179507Sdg TAILQ_INSERT_TAIL(&object->un_pager.devp.devp_pglist, page, pageq); 2189507Sdg for (i = 0; i < count; i++) { 2199507Sdg vm_page_free(m[i]); 2209507Sdg } 2211549Srgrimes s = splhigh(); 2221541Srgrimes vm_page_insert(page, object, offset); 2231549Srgrimes splx(s); 2241541Srgrimes 2255455Sdg return (VM_PAGER_OK); 2261541Srgrimes} 2271541Srgrimes 22843129Sdillonstatic void 2299507Sdgdev_pager_putpages(object, m, count, sync, rtvals) 2309507Sdg vm_object_t object; 2319507Sdg vm_page_t *m; 2329507Sdg int count; 2331541Srgrimes boolean_t sync; 2349507Sdg int *rtvals; 2351541Srgrimes{ 2361541Srgrimes panic("dev_pager_putpage called"); 2371541Srgrimes} 2381541Srgrimes 23912820Sphkstatic boolean_t 24012767Sdysondev_pager_haspage(object, pindex, before, after) 2419507Sdg vm_object_t object; 24212767Sdyson vm_pindex_t pindex; 2439507Sdg int *before; 2449507Sdg int *after; 2451541Srgrimes{ 2469507Sdg if (before != NULL) 2479507Sdg *before = 0; 2489507Sdg if (after != NULL) 2499507Sdg *after = 0; 2505455Sdg return (TRUE); 2511541Srgrimes} 2521541Srgrimes 2531541Srgrimesstatic vm_page_t 2541541Srgrimesdev_pager_getfake(paddr) 2551541Srgrimes vm_offset_t paddr; 2561541Srgrimes{ 2571541Srgrimes vm_page_t m; 2581541Srgrimes 25940558Sdg m = zalloc(fakepg_zone); 2601549Srgrimes 2615455Sdg m->flags = PG_BUSY | PG_FICTITIOUS; 2629507Sdg m->valid = VM_PAGE_BITS_ALL; 2635455Sdg m->dirty = 0; 2645455Sdg m->busy = 0; 26513490Sdyson m->queue = PQ_NONE; 26640557Sdg m->object = NULL; 2671549Srgrimes 2681549Srgrimes m->wire_count = 1; 26914430Sdyson m->hold_count = 0; 2701541Srgrimes m->phys_addr = paddr; 2711549Srgrimes 2725455Sdg return (m); 2731541Srgrimes} 2741541Srgrimes 2751541Srgrimesstatic void 2761541Srgrimesdev_pager_putfake(m) 2771541Srgrimes vm_page_t m; 2781541Srgrimes{ 2791541Srgrimes if (!(m->flags & PG_FICTITIOUS)) 2801541Srgrimes panic("dev_pager_putfake: bad page"); 28140558Sdg zfree(fakepg_zone, m); 2821541Srgrimes} 283