Annotation of Gnu-Mach/device/dev_pager.c, revision 1.1.1.6

1.1.1.2   root        1: /*
1.1       root        2:  * Mach Operating System
                      3:  * Copyright (c) 1993-1989 Carnegie Mellon University
                      4:  * All Rights Reserved.
1.1.1.2   root        5:  *
1.1       root        6:  * Permission to use, copy, modify and distribute this software and its
                      7:  * documentation is hereby granted, provided that both the copyright
                      8:  * notice and this permission notice appear in all copies of the
                      9:  * software, derivative works or modified versions, and any portions
                     10:  * thereof, and that both notices appear in supporting documentation.
1.1.1.2   root       11:  *
1.1       root       12:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
                     13:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
                     14:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
1.1.1.2   root       15:  *
1.1       root       16:  * Carnegie Mellon requests users of this software to return to
1.1.1.2   root       17:  *
1.1       root       18:  *  Software Distribution Coordinator  or  [email protected]
                     19:  *  School of Computer Science
                     20:  *  Carnegie Mellon University
                     21:  *  Pittsburgh PA 15213-3890
1.1.1.2   root       22:  *
1.1       root       23:  * any improvements or extensions that they make and grant Carnegie Mellon
                     24:  * the rights to redistribute these changes.
                     25:  */
                     26: /*
                     27:  *     Author: David B. Golub, Carnegie Mellon University
                     28:  *     Date:   3/89
                     29:  *
                     30:  *     Device pager.
                     31:  */
1.1.1.3   root       32: 
                     33: #include <string.h>
1.1       root       34: 
                     35: #include <mach/boolean.h>
                     36: #include <mach/port.h>
                     37: #include <mach/message.h>
                     38: #include <mach/std_types.h>
                     39: #include <mach/mach_types.h>
                     40: 
                     41: #include <ipc/ipc_port.h>
                     42: #include <ipc/ipc_space.h>
                     43: 
1.1.1.3   root       44: #include <kern/debug.h>
                     45: #include <kern/printf.h>
1.1       root       46: #include <kern/queue.h>
1.1.1.3   root       47: #include <kern/slab.h>
1.1       root       48: 
                     49: #include <vm/vm_page.h>
                     50: #include <vm/vm_kern.h>
1.1.1.3   root       51: #include <vm/vm_user.h>
1.1       root       52: 
                     53: #include <device/device_types.h>
                     54: #include <device/ds_routines.h>
                     55: #include <device/dev_hdr.h>
                     56: #include <device/io_req.h>
1.1.1.3   root       57: #include <device/memory_object_reply.user.h>
1.1.1.4   root       58: #include <device/dev_pager.h>
                     59: #include <device/blkio.h>
1.1       root       60: 
                     61: /*
                     62:  *     The device pager routines are called directly from the message
                     63:  *     system (via mach_msg), and thus run in the kernel-internal
                     64:  *     environment.  All ports are in internal form (ipc_port_t),
                     65:  *     and must be correctly reference-counted in order to be saved
                     66:  *     in other data structures.  Kernel routines may be called
                     67:  *     directly.  Kernel types are used for data objects (tasks,
                     68:  *     memory objects, ports).  The only IPC routines that may be
                     69:  *     called are ones that masquerade as the kernel task (via
                     70:  *     msg_send_from_kernel).
                     71:  *
                     72:  *     Port rights and references are maintained as follows:
                     73:  *             Memory object port:
                     74:  *                     The device_pager task has all rights.
                     75:  *             Memory object control port:
                     76:  *                     The device_pager task has only send rights.
                     77:  *             Memory object name port:
                     78:  *                     The device_pager task has only send rights.
                     79:  *                     The name port is not even recorded.
                     80:  *     Regardless how the object is created, the control and name
                     81:  *     ports are created by the kernel and passed through the memory
                     82:  *     management interface.
                     83:  *
                     84:  *     The device_pager assumes that access to its memory objects
                     85:  *     will not be propagated to more that one host, and therefore
                     86:  *     provides no consistency guarantees beyond those made by the
                     87:  *     kernel.
                     88:  *
                     89:  *     In the event that more than one host attempts to use a device
                     90:  *     memory object, the device_pager will only record the last set
                     91:  *     of port names.  [This can happen with only one host if a new
                     92:  *     mapping is being established while termination of all previous
                     93:  *     mappings is taking place.]  Currently, the device_pager assumes
                     94:  *     that its clients adhere to the initialization and termination
                     95:  *     protocols in the memory management interface; otherwise, port
                     96:  *     rights or out-of-line memory from erroneous messages may be
                     97:  *     allowed to accumulate.
                     98:  *
                     99:  *     [The phrase "currently" has been used above to denote aspects of
                    100:  *     the implementation that could be altered without changing the rest
                    101:  *     of the basic documentation.]
                    102:  */
                    103: 
                    104: /*
                    105:  * Basic device pager structure.
                    106:  */
                    107: struct dev_pager {
                    108:        decl_simple_lock_data(, lock)   /* lock for reference count */
                    109:        int             ref_count;      /* reference count */
                    110:        int             client_count;   /* How many memory_object_create
                    111:                                         * calls have we received */
                    112:        ipc_port_t      pager;          /* pager port */
                    113:        ipc_port_t      pager_request;  /* Known request port */
                    114:        ipc_port_t      pager_name;     /* Known name port */
                    115:        mach_device_t   device;         /* Device handle */
                    116:        int             type;           /* to distinguish */
                    117: #define DEV_PAGER_TYPE 0
                    118: #define CHAR_PAGER_TYPE        1
                    119:        /* char pager specifics */
                    120:        int             prot;
                    121:        vm_size_t       size;
                    122: };
                    123: typedef struct dev_pager *dev_pager_t;
                    124: #define        DEV_PAGER_NULL  ((dev_pager_t)0)
                    125: 
                    126: 
1.1.1.3   root      127: struct kmem_cache      dev_pager_cache;
1.1       root      128: 
1.1.1.3   root      129: void dev_pager_reference(dev_pager_t   ds)
1.1       root      130: {
                    131:        simple_lock(&ds->lock);
                    132:        ds->ref_count++;
                    133:        simple_unlock(&ds->lock);
                    134: }
                    135: 
1.1.1.3   root      136: void dev_pager_deallocate(dev_pager_t  ds)
1.1       root      137: {
                    138:        simple_lock(&ds->lock);
                    139:        if (--ds->ref_count > 0) {
                    140:            simple_unlock(&ds->lock);
                    141:            return;
                    142:        }
                    143: 
                    144:        simple_unlock(&ds->lock);
1.1.1.3   root      145:        kmem_cache_free(&dev_pager_cache, (vm_offset_t)ds);
1.1       root      146: }
                    147: 
                    148: /*
                    149:  * A hash table of ports for device_pager backed objects.
                    150:  */
                    151: 
                    152: #define        DEV_PAGER_HASH_COUNT            127
                    153: 
                    154: struct dev_pager_entry {
                    155:        queue_chain_t   links;
                    156:        ipc_port_t      name;
                    157:        dev_pager_t     pager_rec;
                    158: };
                    159: typedef struct dev_pager_entry *dev_pager_entry_t;
                    160: 
                    161: queue_head_t   dev_pager_hashtable[DEV_PAGER_HASH_COUNT];
1.1.1.3   root      162: struct kmem_cache      dev_pager_hash_cache;
1.1       root      163: decl_simple_lock_data(,
                    164:                dev_pager_hash_lock)
                    165: 
                    166: #define        dev_pager_hash(name_port) \
1.1.1.3   root      167:                (((vm_offset_t)(name_port) & 0xffffff) % DEV_PAGER_HASH_COUNT)
1.1       root      168: 
                    169: void dev_pager_hash_init(void)
                    170: {
1.1.1.3   root      171:        int             i;
                    172:        vm_size_t       size;
1.1       root      173: 
                    174:        size = sizeof(struct dev_pager_entry);
1.1.1.3   root      175:        kmem_cache_init(&dev_pager_hash_cache, "dev_pager_entry", size, 0,
1.1.1.5   root      176:                        NULL, 0);
1.1       root      177:        for (i = 0; i < DEV_PAGER_HASH_COUNT; i++)
                    178:            queue_init(&dev_pager_hashtable[i]);
                    179:        simple_lock_init(&dev_pager_hash_lock);
                    180: }
                    181: 
                    182: void dev_pager_hash_insert(
1.1.1.4   root      183:        const ipc_port_t        name_port,
                    184:        const dev_pager_t       rec)
1.1       root      185: {
1.1.1.3   root      186:        dev_pager_entry_t new_entry;
1.1       root      187: 
1.1.1.3   root      188:        new_entry = (dev_pager_entry_t) kmem_cache_alloc(&dev_pager_hash_cache);
1.1       root      189:        new_entry->name = name_port;
                    190:        new_entry->pager_rec = rec;
                    191: 
                    192:        simple_lock(&dev_pager_hash_lock);
                    193:        queue_enter(&dev_pager_hashtable[dev_pager_hash(name_port)],
                    194:                        new_entry, dev_pager_entry_t, links);
                    195:        simple_unlock(&dev_pager_hash_lock);
                    196: }
                    197: 
1.1.1.4   root      198: void dev_pager_hash_delete(const ipc_port_t name_port)
1.1       root      199: {
1.1.1.3   root      200:        queue_t                 bucket;
                    201:        dev_pager_entry_t       entry;
1.1       root      202: 
                    203:        bucket = &dev_pager_hashtable[dev_pager_hash(name_port)];
                    204: 
                    205:        simple_lock(&dev_pager_hash_lock);
                    206:        for (entry = (dev_pager_entry_t)queue_first(bucket);
                    207:             !queue_end(bucket, &entry->links);
                    208:             entry = (dev_pager_entry_t)queue_next(&entry->links)) {
                    209:            if (entry->name == name_port) {
                    210:                queue_remove(bucket, entry, dev_pager_entry_t, links);
                    211:                break;
                    212:            }
                    213:        }
                    214:        simple_unlock(&dev_pager_hash_lock);
                    215:        if (entry)
1.1.1.3   root      216:            kmem_cache_free(&dev_pager_hash_cache, (vm_offset_t)entry);
1.1       root      217: }
                    218: 
1.1.1.4   root      219: dev_pager_t dev_pager_hash_lookup(const ipc_port_t name_port)
1.1       root      220: {
1.1.1.3   root      221:        queue_t                 bucket;
                    222:        dev_pager_entry_t       entry;
                    223:        dev_pager_t             pager;
1.1       root      224: 
                    225:        bucket = &dev_pager_hashtable[dev_pager_hash(name_port)];
                    226: 
                    227:        simple_lock(&dev_pager_hash_lock);
                    228:        for (entry = (dev_pager_entry_t)queue_first(bucket);
                    229:             !queue_end(bucket, &entry->links);
                    230:             entry = (dev_pager_entry_t)queue_next(&entry->links)) {
                    231:            if (entry->name == name_port) {
                    232:                pager = entry->pager_rec;
                    233:                dev_pager_reference(pager);
                    234:                simple_unlock(&dev_pager_hash_lock);
                    235:                return (pager);
                    236:            }
                    237:        }
                    238:        simple_unlock(&dev_pager_hash_lock);
                    239:        return (DEV_PAGER_NULL);
                    240: }
                    241: 
                    242: kern_return_t  device_pager_setup(
1.1.1.4   root      243:        const mach_device_t     device,
                    244:        int                     prot,
                    245:        vm_offset_t             offset,
                    246:        vm_size_t               size,
                    247:        mach_port_t             *pager)
1.1       root      248: {
1.1.1.3   root      249:        dev_pager_t     d;
1.1       root      250: 
                    251:        /*
                    252:         *      Verify the device is indeed mappable
                    253:         */
                    254:        if (!device->dev_ops->d_mmap || (device->dev_ops->d_mmap == nomap))
                    255:                return (D_INVALID_OPERATION);
                    256: 
                    257:        /*
                    258:         *      Allocate a structure to hold the arguments
                    259:         *      and port to represent this object.
                    260:         */
                    261: 
                    262:        d = dev_pager_hash_lookup((ipc_port_t)device);  /* HACK */
                    263:        if (d != DEV_PAGER_NULL) {
                    264:                *pager = (mach_port_t) ipc_port_make_send(d->pager);
                    265:                dev_pager_deallocate(d);
                    266:                return (D_SUCCESS);
                    267:        }
                    268: 
1.1.1.3   root      269:        d = (dev_pager_t) kmem_cache_alloc(&dev_pager_cache);
1.1       root      270:        if (d == DEV_PAGER_NULL)
                    271:                return (KERN_RESOURCE_SHORTAGE);
                    272: 
                    273:        simple_lock_init(&d->lock);
                    274:        d->ref_count = 1;
                    275: 
                    276:        /*
                    277:         * Allocate the pager port.
                    278:         */
                    279:        d->pager = ipc_port_alloc_kernel();
                    280:        if (d->pager == IP_NULL) {
                    281:                dev_pager_deallocate(d);
                    282:                return (KERN_RESOURCE_SHORTAGE);
                    283:        }
                    284: 
                    285:        d->client_count = 0;
                    286:        d->pager_request = IP_NULL;
                    287:        d->pager_name = IP_NULL;
                    288:        d->device = device;
                    289:        mach_device_reference(device);
                    290:        d->prot = prot;
                    291:        d->size = round_page(size);
                    292:        if (device->dev_ops->d_mmap == block_io_mmap) {
                    293:                d->type = DEV_PAGER_TYPE;
                    294:        } else {
                    295:                d->type = CHAR_PAGER_TYPE;
                    296:        }
                    297: 
                    298:        dev_pager_hash_insert(d->pager, d);
                    299:        dev_pager_hash_insert((ipc_port_t)device, d);   /* HACK */
                    300: 
                    301:        *pager = (mach_port_t) ipc_port_make_send(d->pager);
                    302:        return (KERN_SUCCESS);
                    303: }
                    304: 
                    305: /*
                    306:  *     Routine:        device_pager_release
                    307:  *     Purpose:
                    308:  *             Relinquish any references or rights that were
                    309:  *             associated with the result of a call to
                    310:  *             device_pager_setup.
                    311:  */
                    312: void   device_pager_release(memory_object_t    object)
                    313: {
                    314:        if (MACH_PORT_VALID(object))
                    315:                ipc_port_release_send((ipc_port_t) object);
                    316: }
                    317: 
                    318: boolean_t      device_pager_debug = FALSE;
                    319: 
                    320: kern_return_t  device_pager_data_request(
1.1.1.4   root      321:        const ipc_port_t        pager,
                    322:        const ipc_port_t        pager_request,
                    323:        vm_offset_t             offset,
                    324:        vm_size_t               length,
                    325:        vm_prot_t               protection_required)
1.1       root      326: {
1.1.1.3   root      327:        dev_pager_t     ds;
1.1       root      328: 
                    329:        if (device_pager_debug)
1.1.1.3   root      330:                printf("(device_pager)data_request: pager=%p, offset=0x%lx, length=0x%x\n",
1.1       root      331:                        pager, offset, length);
                    332: 
1.1.1.4   root      333:        ds = dev_pager_hash_lookup(pager);
1.1       root      334:        if (ds == DEV_PAGER_NULL)
                    335:                panic("(device_pager)data_request: lookup failed");
                    336: 
                    337:        if (ds->pager_request != pager_request)
                    338:                panic("(device_pager)data_request: bad pager_request");
                    339: 
                    340:        if (ds->type == CHAR_PAGER_TYPE) {
1.1.1.3   root      341:            vm_object_t                 object;
1.1       root      342: 
                    343:            object = vm_object_lookup(pager_request);
                    344:            if (object == VM_OBJECT_NULL) {
                    345:                    (void) r_memory_object_data_error(pager_request,
                    346:                                                      offset, length,
                    347:                                                      KERN_FAILURE);
                    348:                    dev_pager_deallocate(ds);
                    349:                    return (KERN_SUCCESS);
                    350:            }
                    351: 
                    352:            vm_object_page_map(object,
                    353:                               offset, length,
1.1.1.4   root      354:                               device_map_page, (void *)ds);
1.1       root      355: 
                    356:            vm_object_deallocate(object);
                    357:        }
                    358:        else {
                    359:            panic("(device_pager)data_request: dev pager");
                    360:        }
                    361: 
                    362:        dev_pager_deallocate(ds);
                    363: 
                    364:        return (KERN_SUCCESS);
                    365: }
                    366: 
                    367: kern_return_t device_pager_copy(
1.1.1.4   root      368:        const ipc_port_t        pager,
                    369:        const ipc_port_t        pager_request,
1.1.1.3   root      370:        vm_offset_t             offset,
                    371:        vm_size_t               length,
1.1.1.4   root      372:        const ipc_port_t        new_pager)
1.1       root      373: {
                    374:        panic("(device_pager)copy: called");
                    375: }
                    376: 
                    377: kern_return_t
                    378: device_pager_supply_completed(
1.1.1.4   root      379:        const ipc_port_t pager,
                    380:        const ipc_port_t pager_request,
1.1       root      381:        vm_offset_t offset,
                    382:        vm_size_t length,
                    383:        kern_return_t result,
                    384:        vm_offset_t error_offset)
                    385: {
                    386:        panic("(device_pager)supply_completed: called");
                    387: }
                    388: 
                    389: kern_return_t
                    390: device_pager_data_return(
1.1.1.4   root      391:        const ipc_port_t        pager,
                    392:        const ipc_port_t        pager_request,
1.1       root      393:        vm_offset_t             offset,
1.1.1.3   root      394:        pointer_t               addr,
1.1       root      395:        vm_size_t               data_cnt,
                    396:        boolean_t               dirty,
                    397:        boolean_t               kernel_copy)
                    398: {
                    399:        panic("(device_pager)data_return: called");
                    400: }
                    401: 
                    402: kern_return_t
                    403: device_pager_change_completed(
1.1.1.4   root      404:        const ipc_port_t pager,
1.1       root      405:        boolean_t may_cache,
                    406:        memory_object_copy_strategy_t copy_strategy)
                    407: {
                    408:        panic("(device_pager)change_completed: called");
                    409: }
                    410: 
                    411: /*
                    412:  *     The mapping function takes a byte offset, but returns
                    413:  *     a machine-dependent page frame number.  We convert
                    414:  *     that into something that the pmap module will
                    415:  *     accept later.
                    416:  */
                    417: vm_offset_t device_map_page(
                    418:        void            *dsp,
                    419:        vm_offset_t     offset)
                    420: {
1.1.1.3   root      421:        dev_pager_t     ds = (dev_pager_t) dsp;
1.1       root      422: 
                    423:        return pmap_phys_address(
                    424:                   (*(ds->device->dev_ops->d_mmap))
                    425:                        (ds->device->dev_number, offset, ds->prot));
                    426: }
                    427: 
                    428: kern_return_t device_pager_init_pager(
1.1.1.4   root      429:        const ipc_port_t        pager,
                    430:        const ipc_port_t        pager_request,
                    431:        const ipc_port_t        pager_name,
                    432:        vm_size_t               pager_page_size)
1.1       root      433: {
1.1.1.3   root      434:        dev_pager_t     ds;
1.1       root      435: 
                    436:        if (device_pager_debug)
1.1.1.3   root      437:                printf("(device_pager)init: pager=%p, request=%p, name=%p\n",
1.1       root      438:                       pager, pager_request, pager_name);
                    439: 
                    440:        assert(pager_page_size == PAGE_SIZE);
                    441:        assert(IP_VALID(pager_request));
                    442:        assert(IP_VALID(pager_name));
                    443: 
                    444:        ds = dev_pager_hash_lookup(pager);
                    445:        assert(ds != DEV_PAGER_NULL);
                    446: 
                    447:        assert(ds->client_count == 0);
                    448:        assert(ds->pager_request == IP_NULL);
                    449:        assert(ds->pager_name == IP_NULL);
                    450: 
                    451:        ds->client_count = 1;
                    452: 
                    453:        /*
                    454:         * We save the send rights for the request and name ports.
                    455:         */
                    456: 
                    457:        ds->pager_request = pager_request;
                    458:        ds->pager_name = pager_name;
                    459: 
                    460:        if (ds->type == CHAR_PAGER_TYPE) {
                    461:            /*
                    462:             * Reply that the object is ready
                    463:             */
1.1.1.6 ! root      464:            (void) r_memory_object_ready(pager_request,
        !           465:                                         FALSE, /* do not cache */
        !           466:                                         MEMORY_OBJECT_COPY_NONE);
1.1       root      467:        } else {
1.1.1.6 ! root      468:            (void) r_memory_object_ready(pager_request,
        !           469:                                         TRUE,  /* cache */
        !           470:                                         MEMORY_OBJECT_COPY_DELAY);
1.1       root      471:        }
                    472: 
                    473:        dev_pager_deallocate(ds);
                    474:        return (KERN_SUCCESS);
                    475: }
                    476: 
                    477: kern_return_t device_pager_terminate(
1.1.1.4   root      478:        const ipc_port_t        pager,
                    479:        const ipc_port_t        pager_request,
                    480:        const ipc_port_t        pager_name)
1.1       root      481: {
1.1.1.3   root      482:        dev_pager_t     ds;
1.1       root      483: 
                    484:        assert(IP_VALID(pager_request));
                    485:        assert(IP_VALID(pager_name));
                    486: 
                    487:        ds = dev_pager_hash_lookup(pager);
                    488:        assert(ds != DEV_PAGER_NULL);
                    489: 
                    490:        assert(ds->client_count == 1);
                    491:        assert(ds->pager_request == pager_request);
                    492:        assert(ds->pager_name == pager_name);
                    493: 
                    494:        dev_pager_hash_delete(ds->pager);
                    495:        dev_pager_hash_delete((ipc_port_t)ds->device);  /* HACK */
                    496:        mach_device_deallocate(ds->device);
                    497: 
                    498:        /* release the send rights we have saved from the init call */
                    499: 
                    500:        ipc_port_release_send(pager_request);
                    501:        ipc_port_release_send(pager_name);
                    502: 
                    503:        /* release the naked receive rights we just acquired */
                    504: 
                    505:        ipc_port_release_receive(pager_request);
                    506:        ipc_port_release_receive(pager_name);
                    507: 
                    508:        /* release the kernel's receive right for the pager port */
                    509: 
                    510:        ipc_port_dealloc_kernel(pager);
                    511: 
                    512:        /* once for ref from lookup, once to make it go away */
                    513:        dev_pager_deallocate(ds);
                    514:        dev_pager_deallocate(ds);
                    515: 
                    516:        return (KERN_SUCCESS);
                    517: }
                    518: 
                    519: kern_return_t device_pager_data_unlock(
1.1.1.4   root      520:        const ipc_port_t memory_object,
                    521:        const ipc_port_t memory_control_port,
1.1       root      522:        vm_offset_t offset,
                    523:        vm_size_t length,
                    524:        vm_prot_t desired_access)
                    525: {
                    526:        panic("(device_pager)data_unlock: called");
                    527:        return (KERN_FAILURE);
                    528: }
                    529: 
                    530: kern_return_t device_pager_lock_completed(
1.1.1.4   root      531:        const ipc_port_t        memory_object,
                    532:        const ipc_port_t        pager_request_port,
                    533:        vm_offset_t             offset,
                    534:        vm_size_t               length)
1.1       root      535: {
                    536:        panic("(device_pager)lock_completed: called");
                    537:        return (KERN_FAILURE);
                    538: }
                    539: 
                    540: void device_pager_init(void)
                    541: {
1.1.1.3   root      542:        vm_size_t       size;
1.1       root      543: 
                    544:        /*
1.1.1.3   root      545:         * Initialize cache of paging structures.
1.1       root      546:         */
                    547:        size = sizeof(struct dev_pager);
1.1.1.3   root      548:        kmem_cache_init(&dev_pager_cache, "dev_pager", size, 0,
1.1.1.5   root      549:                        NULL, 0);
1.1       root      550: 
                    551:        /*
                    552:         *      Initialize the name port hashing stuff.
                    553:         */
                    554:        dev_pager_hash_init();
                    555: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.