xref: /original-bsd/sys/vm/device_pager.c (revision 3705696b)
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