xref: /csrg-svn/sys/vm/device_pager.c (revision 45749)
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