[BACK]Return to uvm_device.c CVS log [TXT][DIR] Up to [local] / sys / uvm

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