Fixed broken pte bit definitions. I fixed this long ago in pte.h, but
[unix-history] / sys / vm / device_pager.c
CommitLineData
15637ed4
RG
1/*
2 * Copyright (c) 1990 University of Utah.
0a8fbd8d
DG
3 * Copyright (c) 1991, 1993
4 * The Regents of the University of California. All rights reserved.
15637ed4
RG
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 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
0a8fbd8d 38 * @(#)device_pager.c 8.1 (Berkeley) 6/11/93
15637ed4
RG
39 */
40
41/*
42 * Page to/from special files.
43 */
44
0a8fbd8d
DG
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/conf.h>
48#include <sys/mman.h>
49#include <sys/malloc.h>
15637ed4 50
0a8fbd8d
DG
51#include <vm/vm.h>
52#include <vm/vm_kern.h>
53#include <vm/vm_page.h>
54#include <vm/device_pager.h>
15637ed4 55
3ed7acd6
PR
56#include "vnode.h"
57#include "specdev.h"
15637ed4 58
0a8fbd8d
DG
59queue_head_t dev_pager_list; /* list of managed devices */
60queue_head_t dev_pager_fakelist; /* list of available vm_page_t's */
15637ed4
RG
61
62#ifdef DEBUG
63int dpagerdebug = 0;
64#define DDB_FOLLOW 0x01
65#define DDB_INIT 0x02
66#define DDB_ALLOC 0x04
67#define DDB_FAIL 0x08
68#endif
69
0a8fbd8d
DG
70static vm_pager_t dev_pager_alloc
71 __P((caddr_t, vm_size_t, vm_prot_t, vm_offset_t));
72static void dev_pager_dealloc __P((vm_pager_t));
73static int dev_pager_getpage
74 __P((vm_pager_t, vm_page_t, boolean_t));
75static boolean_t dev_pager_haspage __P((vm_pager_t, vm_offset_t));
76static void dev_pager_init __P((void));
77static int dev_pager_putpage
78 __P((vm_pager_t, vm_page_t, boolean_t));
79static vm_page_t dev_pager_getfake __P((vm_offset_t));
80static void dev_pager_putfake __P((vm_page_t));
81
82struct pagerops devicepagerops = {
83 dev_pager_init,
84 dev_pager_alloc,
85 dev_pager_dealloc,
86 dev_pager_getpage,
55768178 87 0,
0a8fbd8d 88 dev_pager_putpage,
22c84afa 89 0,
0a8fbd8d
DG
90 dev_pager_haspage
91};
92
93static void
15637ed4
RG
94dev_pager_init()
95{
96#ifdef DEBUG
97 if (dpagerdebug & DDB_FOLLOW)
98 printf("dev_pager_init()\n");
99#endif
100 queue_init(&dev_pager_list);
0a8fbd8d 101 queue_init(&dev_pager_fakelist);
15637ed4
RG
102}
103
0a8fbd8d
DG
104static vm_pager_t
105dev_pager_alloc(handle, size, prot, foff)
15637ed4
RG
106 caddr_t handle;
107 vm_size_t size;
108 vm_prot_t prot;
0a8fbd8d 109 vm_offset_t foff;
15637ed4 110{
2dbd2022 111 dev_t dev;
15637ed4 112 vm_pager_t pager;
0a8fbd8d
DG
113 int (*mapfunc)();
114 vm_object_t object;
115 dev_pager_t devp;
116 unsigned int npages, off;
15637ed4
RG
117
118#ifdef DEBUG
119 if (dpagerdebug & DDB_FOLLOW)
0a8fbd8d
DG
120 printf("dev_pager_alloc(%x, %x, %x, %x)\n",
121 handle, size, prot, foff);
15637ed4 122#endif
0a8fbd8d 123#ifdef DIAGNOSTIC
15637ed4
RG
124 /*
125 * Pageout to device, should never happen.
126 */
127 if (handle == NULL)
128 panic("dev_pager_alloc called");
0a8fbd8d
DG
129#endif
130
131 /*
132 * Make sure this device can be mapped.
133 */
2dbd2022
DG
134 dev = (dev_t)(u_long)handle;
135 mapfunc = cdevsw[major(dev)].d_mmap;
0a8fbd8d
DG
136 if (mapfunc == NULL || mapfunc == enodev || mapfunc == nullop)
137 return(NULL);
138
139 /*
140 * Offset should be page aligned.
141 */
55768178 142 if (foff & (PAGE_SIZE-1))
0a8fbd8d 143 return(NULL);
15637ed4
RG
144
145 /*
0a8fbd8d
DG
146 * Check that the specified range of the device allows the
147 * desired protection.
148 *
149 * XXX assumes VM_PROT_* == PROT_*
15637ed4 150 */
0a8fbd8d
DG
151 npages = atop(round_page(size));
152 for (off = foff; npages--; off += PAGE_SIZE)
153 if ((*mapfunc)(dev, off, (int)prot) == -1)
154 return(NULL);
155
156 /*
157 * Look up pager, creating as necessary.
158 */
159top:
15637ed4
RG
160 pager = vm_pager_lookup(&dev_pager_list, handle);
161 if (pager == NULL) {
15637ed4
RG
162 /*
163 * Allocate and initialize pager structs
164 */
165 pager = (vm_pager_t)malloc(sizeof *pager, M_VMPAGER, M_WAITOK);
166 if (pager == NULL)
167 return(NULL);
168 devp = (dev_pager_t)malloc(sizeof *devp, M_VMPGDATA, M_WAITOK);
169 if (devp == NULL) {
170 free((caddr_t)pager, M_VMPAGER);
171 return(NULL);
172 }
15637ed4
RG
173 pager->pg_handle = handle;
174 pager->pg_ops = &devicepagerops;
175 pager->pg_type = PG_DEVICE;
176 pager->pg_data = (caddr_t)devp;
0a8fbd8d 177 queue_init(&devp->devp_pglist);
15637ed4 178 /*
0a8fbd8d 179 * Allocate object and associate it with the pager.
15637ed4 180 */
0a8fbd8d 181 object = devp->devp_object = vm_object_allocate(0);
15637ed4 182 vm_object_enter(object, pager);
0a8fbd8d 183 vm_object_setpager(object, pager, (vm_offset_t)foff, FALSE);
15637ed4
RG
184 /*
185 * Finally, put it on the managed list so other can find it.
0a8fbd8d
DG
186 * First we re-lookup in case someone else beat us to this
187 * point (due to blocking in the various mallocs). If so,
188 * we free everything and start over.
15637ed4 189 */
0a8fbd8d
DG
190 if (vm_pager_lookup(&dev_pager_list, handle)) {
191 free((caddr_t)devp, M_VMPGDATA);
192 free((caddr_t)pager, M_VMPAGER);
193 goto top;
194 }
15637ed4
RG
195 queue_enter(&dev_pager_list, pager, vm_pager_t, pg_list);
196#ifdef DEBUG
0a8fbd8d
DG
197 if (dpagerdebug & DDB_ALLOC) {
198 printf("dev_pager_alloc: pager %x devp %x object %x\n",
199 pager, devp, object);
200 vm_object_print(object, FALSE);
201 }
15637ed4
RG
202#endif
203 } else {
204 /*
205 * vm_object_lookup() gains a reference and also
206 * removes the object from the cache.
207 */
0a8fbd8d
DG
208 object = vm_object_lookup(pager);
209#ifdef DIAGNOSTIC
15637ed4 210 devp = (dev_pager_t)pager->pg_data;
0a8fbd8d 211 if (object != devp->devp_object)
15637ed4 212 panic("dev_pager_setup: bad object");
15637ed4 213#endif
0a8fbd8d 214 }
15637ed4 215 return(pager);
15637ed4
RG
216}
217
0a8fbd8d 218static void
15637ed4
RG
219dev_pager_dealloc(pager)
220 vm_pager_t pager;
221{
0a8fbd8d
DG
222 dev_pager_t devp;
223 vm_object_t object;
224 vm_page_t m;
15637ed4
RG
225
226#ifdef DEBUG
227 if (dpagerdebug & DDB_FOLLOW)
228 printf("dev_pager_dealloc(%x)\n", pager);
229#endif
230 queue_remove(&dev_pager_list, pager, vm_pager_t, pg_list);
0a8fbd8d
DG
231 /*
232 * Get the object.
233 * Note: cannot use vm_object_lookup since object has already
234 * been removed from the hash chain.
235 */
236 devp = (dev_pager_t)pager->pg_data;
15637ed4
RG
237 object = devp->devp_object;
238#ifdef DEBUG
239 if (dpagerdebug & DDB_ALLOC)
0a8fbd8d 240 printf("dev_pager_dealloc: devp %x object %x\n", devp, object);
15637ed4 241#endif
0a8fbd8d
DG
242 /*
243 * Free up our fake pages.
244 */
245 while (!queue_empty(&devp->devp_pglist)) {
246 queue_remove_first(&devp->devp_pglist, m, vm_page_t, pageq);
247 dev_pager_putfake(m);
248 }
15637ed4
RG
249 free((caddr_t)devp, M_VMPGDATA);
250 free((caddr_t)pager, M_VMPAGER);
15637ed4
RG
251}
252
0a8fbd8d 253static int
15637ed4
RG
254dev_pager_getpage(pager, m, sync)
255 vm_pager_t pager;
256 vm_page_t m;
257 boolean_t sync;
258{
0a8fbd8d
DG
259 register vm_object_t object;
260 vm_offset_t offset, paddr;
261 vm_page_t page;
2dbd2022 262 dev_t dev;
55768178 263 int s;
0a8fbd8d
DG
264 int (*mapfunc)(), prot;
265
15637ed4
RG
266#ifdef DEBUG
267 if (dpagerdebug & DDB_FOLLOW)
268 printf("dev_pager_getpage(%x, %x)\n", pager, m);
269#endif
0a8fbd8d
DG
270
271 object = m->object;
2dbd2022 272 dev = (dev_t)(u_long)pager->pg_handle;
0a8fbd8d
DG
273 offset = m->offset + object->paging_offset;
274 prot = PROT_READ; /* XXX should pass in? */
2dbd2022 275 mapfunc = cdevsw[major(dev)].d_mmap;
9f6fb340 276
0a8fbd8d
DG
277 if (mapfunc == NULL || mapfunc == enodev || mapfunc == nullop)
278 panic("dev_pager_getpage: no map function");
9f6fb340
DG
279
280 paddr = pmap_phys_address((*mapfunc)((dev_t)dev, (int)offset, prot));
0a8fbd8d
DG
281#ifdef DIAGNOSTIC
282 if (paddr == -1)
283 panic("dev_pager_getpage: map function returns error");
284#endif
285 /*
286 * Replace the passed in page with our own fake page and free
287 * up the original.
288 */
289 page = dev_pager_getfake(paddr);
290 queue_enter(&((dev_pager_t)pager->pg_data)->devp_pglist,
291 page, vm_page_t, pageq);
292 vm_object_lock(object);
293 vm_page_lock_queues();
294 vm_page_free(m);
295 vm_page_unlock_queues();
55768178 296 s = splhigh();
0a8fbd8d 297 vm_page_insert(page, object, offset);
55768178 298 splx(s);
0a8fbd8d
DG
299 PAGE_WAKEUP(m);
300 if (offset + PAGE_SIZE > object->size)
301 object->size = offset + PAGE_SIZE; /* XXX anal */
302 vm_object_unlock(object);
303
304 return(VM_PAGER_OK);
15637ed4
RG
305}
306
0a8fbd8d 307static int
15637ed4
RG
308dev_pager_putpage(pager, m, sync)
309 vm_pager_t pager;
310 vm_page_t m;
311 boolean_t sync;
312{
313#ifdef DEBUG
314 if (dpagerdebug & DDB_FOLLOW)
315 printf("dev_pager_putpage(%x, %x)\n", pager, m);
316#endif
317 if (pager == NULL)
4c45483e 318 return 0;
15637ed4
RG
319 panic("dev_pager_putpage called");
320}
321
0a8fbd8d 322static boolean_t
15637ed4
RG
323dev_pager_haspage(pager, offset)
324 vm_pager_t pager;
325 vm_offset_t offset;
326{
327#ifdef DEBUG
328 if (dpagerdebug & DDB_FOLLOW)
329 printf("dev_pager_haspage(%x, %x)\n", pager, offset);
330#endif
331 return(TRUE);
332}
0a8fbd8d
DG
333
334static vm_page_t
335dev_pager_getfake(paddr)
336 vm_offset_t paddr;
337{
338 vm_page_t m;
339 int i;
340
341 if (queue_empty(&dev_pager_fakelist)) {
342 m = (vm_page_t)malloc(PAGE_SIZE, M_VMPGDATA, M_WAITOK);
343 for (i = PAGE_SIZE / sizeof(*m); i > 0; i--) {
344 queue_enter(&dev_pager_fakelist, m, vm_page_t, pageq);
345 m++;
346 }
347 }
348 queue_remove_first(&dev_pager_fakelist, m, vm_page_t, pageq);
9f6fb340 349
0a8fbd8d 350 m->flags = PG_BUSY | PG_CLEAN | PG_FAKE | PG_FICTITIOUS;
9f6fb340 351
0a8fbd8d 352 m->wire_count = 1;
9f6fb340
DG
353 m->phys_addr = paddr;
354
0a8fbd8d
DG
355 return(m);
356}
357
358static void
359dev_pager_putfake(m)
360 vm_page_t m;
361{
362#ifdef DIAGNOSTIC
0a8fbd8d 363 if (!(m->flags & PG_FICTITIOUS))
0a8fbd8d
DG
364 panic("dev_pager_putfake: bad page");
365#endif
366 queue_enter(&dev_pager_fakelist, m, vm_page_t, pageq);
367}