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