xref: /original-bsd/sys/vm/device_pager.c (revision 7596ee73)
1 /*
2  * Copyright (c) 1990 University of Utah.
3  * Copyright (c) 1991 The Regents of the University of California.
4  * 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	7.1 (Berkeley) 12/05/90
13  */
14 
15 /*
16  * Page to/from special files.
17  */
18 
19 #include "devpager.h"
20 #if NDEVPAGER > 0
21 
22 #include "param.h"
23 #include "queue.h"
24 #include "conf.h"
25 #include "mman.h"
26 #include "malloc.h"
27 #include "uio.h"
28 
29 #include "../vm/vm_param.h"
30 #include "../vm/vm_map.h"
31 #include "../vm/vm_pager.h"
32 #include "../vm/vm_page.h"
33 #include "../vm/vm_kern.h"
34 #include "../vm/device_pager.h"
35 
36 queue_head_t	dev_pager_list;	/* list of managed devices */
37 
38 #ifdef DEBUG
39 int	dpagerdebug = 0;
40 #define	DDB_FOLLOW	0x01
41 #define DDB_INIT	0x02
42 #define DDB_ALLOC	0x04
43 #define DDB_FAIL	0x08
44 #endif
45 
46 void
47 dev_pager_init()
48 {
49 #ifdef DEBUG
50 	if (dpagerdebug & DDB_FOLLOW)
51 		printf("dev_pager_init()\n");
52 #endif
53 	queue_init(&dev_pager_list);
54 }
55 
56 vm_pager_t
57 dev_pager_alloc(handle, size, prot)
58 	caddr_t handle;
59 	vm_size_t size;
60 	vm_prot_t prot;
61 {
62 	dev_t dev;
63 	vm_pager_t pager;
64 	int (*mapfunc)(), nprot;
65 	register vm_object_t object;
66 	register vm_page_t page;
67 	register dev_pager_t devp;
68 	register int npages, off;
69 	extern int nulldev(), nodev();
70 
71 
72 #ifdef DEBUG
73 	if (dpagerdebug & DDB_FOLLOW)
74 		printf("dev_pager_alloc(%x, %x, %x)\n", handle, size, prot);
75 #endif
76 	/*
77 	 * Pageout to device, should never happen.
78 	 */
79 	if (handle == NULL)
80 		panic("dev_pager_alloc called");
81 
82 	/*
83 	 * Look it up, creating as necessary
84 	 */
85 	pager = vm_pager_lookup(&dev_pager_list, handle);
86 	if (pager == VM_PAGER_NULL) {
87 		/*
88 		 * Validation.  Make sure this device can be mapped
89 		 * and that range to map is acceptible to device.
90 		 */
91 		dev = (dev_t)handle;
92 		mapfunc = cdevsw[major(dev)].d_mmap;
93 		if (!mapfunc || mapfunc == nodev || mapfunc == nulldev)
94 			return(VM_PAGER_NULL);
95 		nprot = 0;
96 		if (prot & VM_PROT_READ)
97 			nprot |= PROT_READ;
98 		if (prot & VM_PROT_WRITE)
99 			nprot |= PROT_WRITE;
100 		if (prot & VM_PROT_EXECUTE)
101 			nprot |= PROT_EXEC;
102 		npages = atop(round_page(size));
103 		for (off = 0; npages--; off += PAGE_SIZE)
104 			if ((*mapfunc)(dev, off, nprot) == -1)
105 				return(VM_PAGER_NULL);
106 		/*
107 		 * Allocate and initialize pager structs
108 		 */
109 		pager = (vm_pager_t)malloc(sizeof *pager, M_VMPAGER, M_WAITOK);
110 		if (pager == VM_PAGER_NULL)
111 			return(VM_PAGER_NULL);
112 		devp = (dev_pager_t)malloc(sizeof *devp, M_VMPGDATA, M_WAITOK);
113 		if (devp == DEV_PAGER_NULL) {
114 			free((caddr_t)pager, M_VMPAGER);
115 			return(VM_PAGER_NULL);
116 		}
117 		devp->devp_dev = dev;
118 		devp->devp_npages = atop(round_page(size));
119 		pager->pg_handle = handle;
120 		pager->pg_ops = &devicepagerops;
121 		pager->pg_type = PG_DEVICE;
122 		pager->pg_data = (caddr_t)devp;
123 		/*
124 		 * Allocate object and vm_page structures to describe memory
125 		 */
126 		npages = devp->devp_npages;
127 		object = devp->devp_object = vm_object_allocate(ptoa(npages));
128 		vm_object_enter(object, pager);
129 		vm_object_setpager(object, pager, (vm_offset_t)0, FALSE);
130 		devp->devp_pages = (vm_page_t)
131 			kmem_alloc(kernel_map, npages*sizeof(struct vm_page));
132 		off = 0;
133 		for (page = devp->devp_pages;
134 		     page < &devp->devp_pages[npages]; page++) {
135 			vm_object_lock(object);
136 			vm_page_init(page, object, off);
137 			page->phys_addr =
138 				pmap_phys_address((*mapfunc)(dev, off, nprot));
139 			page->wire_count = 1;
140 			page->fictitious = TRUE;
141 			PAGE_WAKEUP(page);
142 			vm_object_unlock(object);
143 			off += PAGE_SIZE;
144 		}
145 		/*
146 		 * Finally, put it on the managed list so other can find it.
147 		 */
148 		queue_enter(&dev_pager_list, devp, dev_pager_t, devp_list);
149 #ifdef DEBUG
150 		if (dpagerdebug & DDB_ALLOC)
151 			printf("dev_pager_alloc: pages %d@%x\n",
152 			       devp->devp_npages, devp->devp_pages);
153 #endif
154 	} else {
155 		/*
156 		 * vm_object_lookup() gains a reference and also
157 		 * removes the object from the cache.
158 		 */
159 		devp = (dev_pager_t)pager->pg_data;
160 		if (vm_object_lookup(pager) != devp->devp_object)
161 			panic("dev_pager_setup: bad object");
162 	}
163 #ifdef DEBUG
164 	if (dpagerdebug & DDB_ALLOC) {
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 	return(pager);
171 
172 }
173 
174 void
175 dev_pager_dealloc(pager)
176 	vm_pager_t pager;
177 {
178 	dev_pager_t devp = (dev_pager_t)pager->pg_data;
179 	register vm_object_t object;
180 
181 #ifdef DEBUG
182 	if (dpagerdebug & DDB_FOLLOW)
183 		printf("dev_pager_dealloc(%x)\n", pager);
184 #endif
185 	queue_remove(&dev_pager_list, devp, dev_pager_t, devp_list);
186 	object = devp->devp_object;
187 #ifdef DEBUG
188 	if (dpagerdebug & DDB_ALLOC)
189 		printf("dev_pager_dealloc: devp %x object %x pages %d@%x\n",
190 		       devp, object, devp->devp_npages, devp->devp_pages);
191 #endif
192 	while (!queue_empty(&object->memq))
193 		vm_page_remove((vm_page_t)queue_first(&object->memq));
194 	kmem_free(kernel_map, devp->devp_pages,
195 		  devp->devp_npages * sizeof(struct vm_page));
196 	free((caddr_t)devp, M_VMPGDATA);
197 	pager->pg_data = 0;
198 }
199 
200 dev_pager_getpage(pager, m, sync)
201 	vm_pager_t pager;
202 	vm_page_t m;
203 	boolean_t sync;
204 {
205 #ifdef DEBUG
206 	if (dpagerdebug & DDB_FOLLOW)
207 		printf("dev_pager_getpage(%x, %x)\n", pager, m);
208 #endif
209 	return(VM_PAGER_BAD);
210 }
211 
212 dev_pager_putpage(pager, m, sync)
213 	vm_pager_t pager;
214 	vm_page_t m;
215 	boolean_t sync;
216 {
217 #ifdef DEBUG
218 	if (dpagerdebug & DDB_FOLLOW)
219 		printf("dev_pager_putpage(%x, %x)\n", pager, m);
220 #endif
221 	if (pager == VM_PAGER_NULL)
222 		return;
223 	panic("dev_pager_putpage called");
224 }
225 
226 boolean_t
227 dev_pager_haspage(pager, offset)
228 	vm_pager_t pager;
229 	vm_offset_t offset;
230 {
231 #ifdef DEBUG
232 	if (dpagerdebug & DDB_FOLLOW)
233 		printf("dev_pager_haspage(%x, %x)\n", pager, offset);
234 #endif
235 	return(TRUE);
236 }
237 #endif
238