xref: /netbsd-src/sys/uvm/uvm_device.c (revision 4472dbe5e3bd91ef2540bada7a7ca7384627ff9b)
1 /*	$NetBSD: uvm_device.c,v 1.22 2000/05/28 10:21:55 drochner Exp $	*/
2 
3 /*
4  *
5  * Copyright (c) 1997 Charles D. Cranor and Washington University.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by Charles D. Cranor and
19  *      Washington University.
20  * 4. The name of the author may not be used to endorse or promote products
21  *    derived from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  * from: Id: uvm_device.c,v 1.1.2.9 1998/02/06 05:11:47 chs Exp
35  */
36 
37 #include "opt_uvmhist.h"
38 
39 /*
40  * uvm_device.c: the device pager.
41  */
42 
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/conf.h>
46 #include <sys/proc.h>
47 #include <sys/malloc.h>
48 #include <sys/vnode.h>
49 
50 #include <vm/vm.h>
51 #include <vm/vm_page.h>
52 #include <vm/vm_kern.h>
53 
54 #include <uvm/uvm.h>
55 #include <uvm/uvm_device.h>
56 
57 /*
58  * private global data structure
59  *
60  * we keep a list of active device objects in the system.
61  */
62 
63 LIST_HEAD(udv_list_struct, uvm_device);
64 static struct udv_list_struct udv_list;
65 static simple_lock_data_t udv_lock;
66 
67 /*
68  * functions
69  */
70 
71 static void		udv_init __P((void));
72 static void             udv_reference __P((struct uvm_object *));
73 static void             udv_detach __P((struct uvm_object *));
74 static int		udv_fault __P((struct uvm_faultinfo *, vaddr_t,
75 				       vm_page_t *, int, int, vm_fault_t,
76 				       vm_prot_t, int));
77 static int		udv_asyncget __P((struct uvm_object *, voff_t,
78 				       int));
79 static boolean_t        udv_flush __P((struct uvm_object *, voff_t, voff_t,
80 				       int));
81 static int		udv_put __P((struct uvm_object *, vm_page_t *,
82 					int, boolean_t));
83 
84 /*
85  * master pager structure
86  */
87 
88 struct uvm_pagerops uvm_deviceops = {
89 	udv_init,
90 	udv_reference,
91 	udv_detach,
92 	udv_fault,
93 	udv_flush,
94 	NULL,		/* no get function since we have udv_fault */
95 	udv_asyncget,
96 	udv_put,
97 	NULL,		/* no cluster function */
98 	NULL,		/* no put cluster function */
99 	NULL,		/* no AIO-DONE function since no async i/o */
100 	NULL,		/* no releasepg function since no normal pages */
101 };
102 
103 /*
104  * the ops!
105  */
106 
107 /*
108  * udv_init
109  *
110  * init pager private data structures.
111  */
112 
113 void
114 udv_init()
115 {
116 
117 	LIST_INIT(&udv_list);
118 	simple_lock_init(&udv_lock);
119 }
120 
121 /*
122  * udv_attach
123  *
124  * get a VM object that is associated with a device.   allocate a new
125  * one if needed.
126  *
127  * => caller must _not_ already be holding the lock on the uvm_object.
128  * => in fact, nothing should be locked so that we can sleep here.
129  */
130 struct uvm_object *
131 udv_attach(arg, accessprot, off, size)
132 	void *arg;
133 	vm_prot_t accessprot;
134 	voff_t off;			/* used only for access check */
135 	vsize_t size;			/* used only for access check */
136 {
137 	dev_t device = *((dev_t *) arg);
138 	struct uvm_device *udv, *lcv;
139 	int (*mapfn) __P((dev_t, int, int));
140 	UVMHIST_FUNC("udv_attach"); UVMHIST_CALLED(maphist);
141 
142 	UVMHIST_LOG(maphist, "(device=0x%x)", device,0,0,0);
143 
144 	/*
145 	 * before we do anything, ensure this device supports mmap
146 	 */
147 
148 	mapfn = cdevsw[major(device)].d_mmap;
149 	if (mapfn == NULL ||
150 			mapfn == (int (*) __P((dev_t, int, int))) enodev ||
151 			mapfn == (int (*) __P((dev_t, int, int))) nullop)
152 		return(NULL);
153 
154 	/*
155 	 * As long as the device d_mmap interface gets an "int"
156 	 * offset, we have to watch out not to overflow its
157 	 * numeric range. (assuming it will be interpreted as
158 	 * "unsigned")
159 	 */
160 	if (((off + size - 1) & (u_int)-1) != off + size - 1)
161 		return (0);
162 
163 	/*
164 	 * Check that the specified range of the device allows the
165 	 * desired protection.
166 	 *
167 	 * XXX assumes VM_PROT_* == PROT_*
168 	 * XXX clobbers off and size, but nothing else here needs them.
169 	 */
170 
171 	while (size != 0) {
172 		if ((*mapfn)(device, off, accessprot) == -1)
173 			return (NULL);
174 		off += PAGE_SIZE; size -= PAGE_SIZE;
175 	}
176 
177 	/*
178 	 * keep looping until we get it
179 	 */
180 
181 	while (1) {
182 
183 		/*
184 		 * first, attempt to find it on the main list
185 		 */
186 
187 		simple_lock(&udv_lock);
188 		for (lcv = udv_list.lh_first ; lcv != NULL ; lcv = lcv->u_list.le_next) {
189 			if (device == lcv->u_device)
190 				break;
191 		}
192 
193 		/*
194 		 * got it on main list.  put a hold on it and unlock udv_lock.
195 		 */
196 
197 		if (lcv) {
198 
199 			/*
200 			 * if someone else has a hold on it, sleep and start
201 			 * over again.
202 			 */
203 
204 			if (lcv->u_flags & UVM_DEVICE_HOLD) {
205 				lcv->u_flags |= UVM_DEVICE_WANTED;
206 				UVM_UNLOCK_AND_WAIT(lcv, &udv_lock, FALSE,
207 				    "udv_attach",0);
208 				continue;
209 			}
210 
211 			/* we are now holding it */
212 			lcv->u_flags |= UVM_DEVICE_HOLD;
213 			simple_unlock(&udv_lock);
214 
215 			/*
216 			 * bump reference count, unhold, return.
217 			 */
218 
219 			simple_lock(&lcv->u_obj.vmobjlock);
220 			lcv->u_obj.uo_refs++;
221 			simple_unlock(&lcv->u_obj.vmobjlock);
222 
223 			simple_lock(&udv_lock);
224 			if (lcv->u_flags & UVM_DEVICE_WANTED)
225 				wakeup(lcv);
226 			lcv->u_flags &= ~(UVM_DEVICE_WANTED|UVM_DEVICE_HOLD);
227 			simple_unlock(&udv_lock);
228 			return(&lcv->u_obj);
229 		}
230 
231 		/*
232 		 * did not find it on main list.   need to malloc a new one.
233 		 */
234 
235 		simple_unlock(&udv_lock);
236 		/* NOTE: we could sleep in the following malloc() */
237 		MALLOC(udv, struct uvm_device *, sizeof(*udv), M_TEMP, M_WAITOK);
238 		simple_lock(&udv_lock);
239 
240 		/*
241 		 * now we have to double check to make sure no one added it
242 		 * to the list while we were sleeping...
243 		 */
244 
245 		for (lcv = udv_list.lh_first ; lcv != NULL ;
246 		    lcv = lcv->u_list.le_next) {
247 			if (device == lcv->u_device)
248 				break;
249 		}
250 
251 		/*
252 		 * did we lose a race to someone else?   free our memory and retry.
253 		 */
254 
255 		if (lcv) {
256 			simple_unlock(&udv_lock);
257 			FREE(udv, M_TEMP);
258 			continue;
259 		}
260 
261 		/*
262 		 * we have it!   init the data structures, add to list
263 		 * and return.
264 		 */
265 
266 		simple_lock_init(&udv->u_obj.vmobjlock);
267 		udv->u_obj.pgops = &uvm_deviceops;
268 		TAILQ_INIT(&udv->u_obj.memq);	/* not used, but be safe */
269 		udv->u_obj.uo_npages = 0;
270 		udv->u_obj.uo_refs = 1;
271 		udv->u_flags = 0;
272 		udv->u_device = device;
273 		LIST_INSERT_HEAD(&udv_list, udv, u_list);
274 		simple_unlock(&udv_lock);
275 
276 		return(&udv->u_obj);
277 
278 	}  /* while(1) loop */
279 
280 	/*NOTREACHED*/
281 }
282 
283 /*
284  * udv_reference
285  *
286  * add a reference to a VM object.   Note that the reference count must
287  * already be one (the passed in reference) so there is no chance of the
288  * udv being released or locked out here.
289  *
290  * => caller must call with object unlocked.
291  */
292 
293 static void
294 udv_reference(uobj)
295 	struct uvm_object *uobj;
296 {
297 	UVMHIST_FUNC("udv_reference"); UVMHIST_CALLED(maphist);
298 
299 	simple_lock(&uobj->vmobjlock);
300 	uobj->uo_refs++;
301 	UVMHIST_LOG(maphist, "<- done (uobj=0x%x, ref = %d)",
302 	uobj, uobj->uo_refs,0,0);
303 	simple_unlock(&uobj->vmobjlock);
304 }
305 
306 /*
307  * udv_detach
308  *
309  * remove a reference to a VM object.
310  *
311  * => caller must call with object unlocked and map locked.
312  */
313 
314 static void
315 udv_detach(uobj)
316 	struct uvm_object *uobj;
317 {
318 	struct uvm_device *udv = (struct uvm_device *) uobj;
319 	UVMHIST_FUNC("udv_detach"); UVMHIST_CALLED(maphist);
320 
321 	/*
322 	 * loop until done
323 	 */
324 
325 	while (1) {
326 		simple_lock(&uobj->vmobjlock);
327 
328 		if (uobj->uo_refs > 1) {
329 			uobj->uo_refs--;			/* drop ref! */
330 			simple_unlock(&uobj->vmobjlock);
331 			UVMHIST_LOG(maphist," <- done, uobj=0x%x, ref=%d",
332 				  uobj,uobj->uo_refs,0,0);
333 			return;
334 		}
335 
336 #ifdef DIAGNOSTIC
337 		if (uobj->uo_npages || uobj->memq.tqh_first)
338 			panic("udv_detach: pages in a device object?");
339 #endif
340 
341 		/*
342 		 * now lock udv_lock
343 		 */
344 		simple_lock(&udv_lock);
345 
346 		/*
347 		 * is it being held?   if so, wait until others are done.
348 		 */
349 		if (udv->u_flags & UVM_DEVICE_HOLD) {
350 
351 			/*
352 			 * want it
353 			 */
354 			udv->u_flags |= UVM_DEVICE_WANTED;
355 			simple_unlock(&uobj->vmobjlock);
356 			UVM_UNLOCK_AND_WAIT(udv, &udv_lock, FALSE, "udv_detach",0);
357 			continue;
358 		}
359 
360 		/*
361 		 * got it!   nuke it now.
362 		 */
363 
364 		LIST_REMOVE(udv, u_list);
365 		if (udv->u_flags & UVM_DEVICE_WANTED)
366 			wakeup(udv);
367 		FREE(udv, M_TEMP);
368 		break;	/* DONE! */
369 
370 	}	/* while (1) loop */
371 
372 	UVMHIST_LOG(maphist," <- done, freed uobj=0x%x", uobj,0,0,0);
373 	return;
374 }
375 
376 
377 /*
378  * udv_flush
379  *
380  * flush pages out of a uvm object.   a no-op for devices.
381  */
382 
383 static boolean_t udv_flush(uobj, start, stop, flags)
384 	struct uvm_object *uobj;
385 	voff_t start, stop;
386 	int flags;
387 {
388 
389 	return(TRUE);
390 }
391 
392 /*
393  * udv_fault: non-standard fault routine for device "pages"
394  *
395  * => rather than having a "get" function, we have a fault routine
396  *	since we don't return vm_pages we need full control over the
397  *	pmap_enter map in
398  * => all the usual fault data structured are locked by the caller
399  *	(i.e. maps(read), amap (if any), uobj)
400  * => on return, we unlock all fault data structures
401  * => flags: PGO_ALLPAGES: get all of the pages
402  *	     PGO_LOCKED: fault data structures are locked
403  *    XXX: currently PGO_LOCKED is always required ... consider removing
404  *	it as a flag
405  * => NOTE: vaddr is the VA of pps[0] in ufi->entry, _NOT_ pps[centeridx]
406  */
407 
408 static int
409 udv_fault(ufi, vaddr, pps, npages, centeridx, fault_type, access_type, flags)
410 	struct uvm_faultinfo *ufi;
411 	vaddr_t vaddr;
412 	vm_page_t *pps;
413 	int npages, centeridx, flags;
414 	vm_fault_t fault_type;
415 	vm_prot_t access_type;
416 {
417 	struct vm_map_entry *entry = ufi->entry;
418 	struct uvm_object *uobj = entry->object.uvm_obj;
419 	struct uvm_device *udv = (struct uvm_device *)uobj;
420 	vaddr_t curr_va;
421 	int curr_offset;
422 	paddr_t paddr;
423 	int lcv, retval, mdpgno;
424 	dev_t device;
425 	int (*mapfn) __P((dev_t, int, int));
426 	vm_prot_t mapprot;
427 	UVMHIST_FUNC("udv_fault"); UVMHIST_CALLED(maphist);
428 	UVMHIST_LOG(maphist,"  flags=%d", flags,0,0,0);
429 
430 	/*
431 	 * XXX: !PGO_LOCKED calls are currently not allowed (or used)
432 	 */
433 
434 	if ((flags & PGO_LOCKED) == 0)
435 		panic("udv_fault: !PGO_LOCKED fault");
436 
437 	/*
438 	 * we do not allow device mappings to be mapped copy-on-write
439 	 * so we kill any attempt to do so here.
440 	 */
441 
442 	if (UVM_ET_ISCOPYONWRITE(entry)) {
443 		UVMHIST_LOG(maphist, "<- failed -- COW entry (etype=0x%x)",
444 		entry->etype, 0,0,0);
445 		uvmfault_unlockall(ufi, ufi->entry->aref.ar_amap, uobj, NULL);
446 		return(VM_PAGER_ERROR);
447 	}
448 
449 	/*
450 	 * get device map function.
451 	 */
452 	device = udv->u_device;
453 	mapfn = cdevsw[major(device)].d_mmap;
454 
455 	/*
456 	 * now we must determine the offset in udv to use and the VA to
457 	 * use for pmap_enter.  note that we always use orig_map's pmap
458 	 * for pmap_enter (even if we have a submap).   since virtual
459 	 * addresses in a submap must match the main map, this is ok.
460 	 */
461 	/* udv offset = (offset from start of entry) + entry's offset */
462 	curr_offset = (int)((vaddr - entry->start) + entry->offset);
463 	/* pmap va = vaddr (virtual address of pps[0]) */
464 	curr_va = vaddr;
465 
466 	/*
467 	 * loop over the page range entering in as needed
468 	 */
469 
470 	retval = VM_PAGER_OK;
471 	for (lcv = 0 ; lcv < npages ; lcv++, curr_offset += PAGE_SIZE,
472 	    curr_va += PAGE_SIZE) {
473 		if ((flags & PGO_ALLPAGES) == 0 && lcv != centeridx)
474 			continue;
475 
476 		if (pps[lcv] == PGO_DONTCARE)
477 			continue;
478 
479 		mdpgno = (*mapfn)(device, curr_offset, access_type);
480 		if (mdpgno == -1) {
481 			retval = VM_PAGER_ERROR;
482 			break;
483 		}
484 		paddr = pmap_phys_address(mdpgno);
485 		mapprot = ufi->entry->protection;
486 		UVMHIST_LOG(maphist,
487 		    "  MAPPING: device: pm=0x%x, va=0x%x, pa=0x%x, at=%d",
488 		    ufi->orig_map->pmap, curr_va, (int)paddr, mapprot);
489 		if (pmap_enter(ufi->orig_map->pmap, curr_va, paddr,
490 		    mapprot, PMAP_CANFAIL | mapprot) != KERN_SUCCESS) {
491 			/*
492 			 * pmap_enter() didn't have the resource to
493 			 * enter this mapping.  Unlock everything,
494 			 * wait for the pagedaemon to free up some
495 			 * pages, and then tell uvm_fault() to start
496 			 * the fault again.
497 			 *
498 			 * XXX Needs some rethinking for the PGO_ALLPAGES
499 			 * XXX case.
500 			 */
501 			uvmfault_unlockall(ufi, ufi->entry->aref.ar_amap,
502 			    uobj, NULL);
503 			uvm_wait("udv_fault");
504 			return (VM_PAGER_REFAULT);
505 		}
506 	}
507 
508 	uvmfault_unlockall(ufi, ufi->entry->aref.ar_amap, uobj, NULL);
509 	return (retval);
510 }
511 
512 /*
513  * udv_asyncget: start async I/O to bring pages into ram
514  *
515  * => caller must lock object(???XXX: see if this is best)
516  * => a no-op for devices
517  */
518 
519 static int
520 udv_asyncget(uobj, offset, npages)
521 	struct uvm_object *uobj;
522 	voff_t offset;
523 	int npages;
524 {
525 
526 	return(KERN_SUCCESS);
527 }
528 
529 /*
530  * udv_put: flush page data to backing store.
531  *
532  * => this function should never be called (since we never have any
533  *	page structures to "put")
534  */
535 
536 static int
537 udv_put(uobj, pps, npages, flags)
538 	struct uvm_object *uobj;
539 	struct vm_page **pps;
540 	int npages, flags;
541 {
542 
543 	panic("udv_put: trying to page out to a device!");
544 }
545