Annotation of OSKit-Mach/oskit/ds_routines.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Mach device server routines (oskit version).
                      3:  *
                      4:  * Mach Operating System
                      5:  * Copyright (c) 1993,1991,1990,1989 Carnegie Mellon University
                      6:  * All Rights Reserved.
                      7:  *
                      8:  * Permission to use, copy, modify and distribute this software and its
                      9:  * documentation is hereby granted, provided that both the copyright
                     10:  * notice and this permission notice appear in all copies of the
                     11:  * software, derivative works or modified versions, and any portions
                     12:  * thereof, and that both notices appear in supporting documentation.
                     13:  *
                     14:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
                     15:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
                     16:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
                     17:  *
                     18:  * Carnegie Mellon requests users of this software to return to
                     19:  *
                     20:  *  Software Distribution Coordinator  or  [email protected]
                     21:  *  School of Computer Science
                     22:  *  Carnegie Mellon University
                     23:  *  Pittsburgh PA 15213-3890
                     24:  *
                     25:  * any improvements or extensions that they make and grant Carnegie Mellon
                     26:  * the rights to redistribute these changes.
                     27:  */
                     28: 
                     29: #include "ds_oskit.h"
                     30: #include "device_error_reply.h"
                     31: 
                     32: #include <mach/boolean.h>
                     33: #include <mach/kern_return.h>
                     34: #include <mach/mig_errors.h>
                     35: #include <mach/port.h>
                     36: #include <mach/notify.h>
                     37: #include <mach/time_value.h>
                     38: 
                     39: #include <vm/vm_map.h>
                     40: #include <vm/vm_kern.h>
                     41: #include <vm/vm_page.h>
                     42: #include "pmap.h"
                     43: 
                     44: #include <ipc/ipc_port.h>
                     45: #include <ipc/ipc_space.h>
                     46: 
                     47: #include <oskit/dev/dev.h>
                     48: #include <oskit/error.h>
                     49: #include <oskit/unsupp/bus_walk.h>
                     50: #include <oskit/dev/bus.h>
                     51: #include <oskit/dev/blk.h>
                     52: #ifdef HAVE_OSKIT_DEV_STREAM_H
                     53: # include <oskit/dev/stream.h>
                     54: #endif
                     55: #include <oskit/dev/net.h>
                     56: #include <oskit/dev/linux.h>
                     57: #include <oskit/com/stream.h>
                     58: #include <oskit/c/stdlib.h>
                     59: 
                     60: #include <oskit/machine/pc/direct_cons.h> /* XXX direct_cons_set_flags */
                     61: 
                     62: #include <device/device_port.h>
                     63: 
                     64: #include <string.h>
                     65: 
                     66: 
                     67: #define NDEVICES               256
                     68: #define        DEVICE_IO_MAP_SIZE      (4 * 1024 * 1024)
                     69: 
                     70: zone_t dev_hdr_zone;
                     71: zone_t io_inband_zone; /* for inband reads */
                     72: 
                     73: queue_head_t           io_done_list;
                     74: decl_simple_lock_data(,        io_done_list_lock)
                     75: 
                     76: /* We maintain a hash table mapping COM oskit_device_t pointers to
                     77:    open device ports (device_t).   */
                     78: 
                     79: #define        NDEVHASH                7
                     80: #define        DEV_PTR_HASH(com)       ((natural_t) (com) % NDEVHASH)
                     81: queue_head_t dev_hash_table[NDEVHASH];
                     82: 
                     83: /*
                     84:  * Lock for device-number to device lookup.
                     85:  * Must be held before device-ref_count lock.
                     86:  */
                     87: decl_simple_lock_data(,dev_hash_lock)
                     88: 
                     89: static void
                     90: dev_hash_enter (device_t device)
                     91: {
                     92:   queue_enter (&dev_hash_table[DEV_PTR_HASH(device->com_device)],
                     93:               device, device_t, hash_chain);
                     94: }
                     95: 
                     96: static void
                     97: dev_hash_remove (device_t device)
                     98: {
                     99:   queue_remove (&dev_hash_table[DEV_PTR_HASH(device->com_device)],
                    100:                device, device_t, hash_chain);
                    101: }
                    102: 
                    103: 
                    104: static device_t
                    105: dev_hash_lookup (oskit_device_t *com_device, dev_mode_t mode)
                    106: {
                    107:   queue_t q;
                    108:   device_t device;
                    109: 
                    110:   q = &dev_hash_table[DEV_PTR_HASH (com_device)];
                    111:   queue_iterate (q, device, device_t, hash_chain)
                    112:     if (device->com_device == com_device && (mode &~ device->mode) == 0)
                    113:       return device;
                    114: 
                    115:   return DEVICE_NULL;
                    116: }
                    117: 
                    118: /*
                    119:  * Add a reference to the device.
                    120:  */
                    121: void
                    122: device_reference(device_t device)
                    123: {
                    124:   simple_lock(&device->ref_lock);
                    125:   device->ref_count++;
                    126:   simple_unlock(&device->ref_lock);
                    127: }
                    128: 
                    129: /*
                    130:  * Remove a reference to the device, and deallocate the
                    131:  * structure if no references are left.
                    132:  */
                    133: void
                    134: device_deallocate (device_t device)
                    135: {
                    136:   if (device == DEVICE_NULL)
                    137:     return;
                    138: 
                    139:   simple_lock (&device->ref_lock);
                    140:   if (device->ref_count > 1)
                    141:     {
                    142:       --device->ref_count;
                    143:       simple_unlock (&device->ref_lock);
                    144:       return;
                    145:     }
                    146:   simple_unlock (&device->ref_lock);
                    147: 
                    148:   if (device->com_device)
                    149:     {
                    150:       simple_lock(&dev_hash_lock);
                    151:       simple_lock(&device->ref_lock);
                    152:       if (--device->ref_count > 0)
                    153:        {
                    154:          simple_unlock (&device->ref_lock);
                    155:          simple_unlock (&dev_hash_lock);
                    156:          return;
                    157:        }
                    158: 
                    159:       dev_hash_remove (device);
                    160:       simple_unlock(&device->ref_lock);
                    161:       simple_unlock(&dev_hash_lock);
                    162:     }
                    163: 
                    164:   /* Destroy the port.  */
                    165:   ipc_kobject_set (device->port, IKO_NULL, IKOT_NONE);
                    166:   ipc_port_dealloc_kernel (device->port);
                    167:   device->port = IP_NULL;
                    168: 
                    169:   DEV_LOCK (device);
                    170:   if (device->ops && device->ops->close)
                    171:     (*device->ops->close) (device);
                    172:   if (device->com_device)      /* close hook might have cleared it */
                    173:     oskit_device_release (device->com_device);
                    174:   DEV_UNLOCK (device);
                    175: 
                    176:   zfree(dev_hdr_zone, (vm_offset_t)device);
                    177: }
                    178: 
                    179: const struct device_ops no_device_ops;
                    180: 
                    181: void ds_init()
                    182: {
                    183:        vm_offset_t     device_io_min, device_io_max;
                    184:        unsigned int i;
                    185: 
                    186:        queue_init(&io_done_list);
                    187:        simple_lock_init(&io_done_list_lock);
                    188: 
                    189:        device_io_map = kmem_suballoc(kernel_map,
                    190:                                      &device_io_min,
                    191:                                      &device_io_max,
                    192:                                      DEVICE_IO_MAP_SIZE,
                    193:                                      FALSE);
                    194:        /*
                    195:         *      If the kernel receives many device_write requests, the
                    196:         *      device_io_map might run out of space.  To prevent
                    197:         *      device_write_get from failing in this case, we enable
                    198:         *      wait_for_space on the map.  This causes kmem_io_map_copyout
                    199:         *      to block until there is sufficient space.
                    200:         *      (XXX Large writes may be starved by small writes.)
                    201:         *
                    202:         *      There is a potential deadlock problem with this solution,
                    203:         *      if a device_write from the default pager has to wait
                    204:         *      for the completion of a device_write which needs to wait
                    205:         *      for memory allocation.  Hence, once device_write_get
                    206:         *      allocates space in device_io_map, no blocking memory
                    207:         *      allocations should happen until device_write_dealloc
                    208:         *      frees the space.  (XXX A large write might starve
                    209:         *      a small write from the default pager.)
                    210:         */
                    211:        device_io_map->wait_for_space = TRUE;
                    212: 
                    213:        dev_hdr_zone = zinit(sizeof(struct device),
                    214:                             sizeof(struct device) * NDEVICES,
                    215:                             PAGE_SIZE,
                    216:                             FALSE,
                    217:                             "open device entry");
                    218: 
                    219:        io_inband_zone = zinit(sizeof(io_buf_ptr_inband_t),
                    220:                            1000 * sizeof(io_buf_ptr_inband_t),
                    221:                            10 * sizeof(io_buf_ptr_inband_t),
                    222:                            FALSE,
                    223:                            "io inband read buffers");
                    224: 
                    225:        simple_lock_init(&dev_hash_lock);
                    226:        for (i = 0; i < NDEVHASH; i++)
                    227:            queue_init(&dev_hash_table[i]);
                    228: 
                    229:        ds_osenv_init();
                    230:        ds_request_init();
                    231: 
                    232:        DEV_LOCK_INIT;
                    233: }
                    234: 
                    235: 
                    236: boolean_t
                    237: ds_notify (mach_msg_header_t *msg)
                    238: {
                    239:   if (msg->msgh_id == MACH_NOTIFY_NO_SENDERS)
                    240:     {
                    241:       device_t dev;
                    242:       mach_no_senders_notification_t *ns;
                    243: 
                    244:       ns = (mach_no_senders_notification_t *) msg;
                    245:       dev = dev_port_lookup ((ipc_port_t) ns->not_header.msgh_remote_port);
                    246:       assert (dev);
                    247: 
                    248:       /* Extant send rights held one ref on the device object,
                    249:         and we just got another one from dev_port_lookup.  */
                    250:       device_deallocate (dev);
                    251:       device_deallocate (dev);
                    252: 
                    253:       return TRUE;
                    254:     }
                    255: 
                    256:   printf ("ds_notify: strange notification %d\n", msg->msgh_id);
                    257:   return FALSE;
                    258: }
                    259: 
                    260: 
                    261: ipc_port_t
                    262: convert_device_to_port (device_t device)
                    263: {
                    264:   ipc_port_t port;
                    265: 
                    266:   if (! device)
                    267:     return IP_NULL;
                    268:   device_lock(device);
                    269:   port = ipc_port_make_send(device->port);
                    270:   device_unlock(device);
                    271:   device_deallocate(device);
                    272:   return port;
                    273: }
                    274: 
                    275: 
                    276: /*
                    277:  * Lookup a device by its port.
                    278:  * Doesn't consume the naked send right; produces a device reference.
                    279:  */
                    280: device_t
                    281: dev_port_lookup(port)
                    282:        ipc_port_t      port;
                    283: {
                    284:        register device_t       device;
                    285: 
                    286:        if (!IP_VALID(port))
                    287:            return (DEVICE_NULL);
                    288: 
                    289:        ip_lock(port);
                    290:        if (ip_active(port) && (ip_kotype(port) == IKOT_DEVICE)) {
                    291:            device = (device_t) port->ip_kobject;
                    292:            device_reference(device);
                    293:        }
                    294:        else
                    295:            device = DEVICE_NULL;
                    296: 
                    297:        ip_unlock(port);
                    298:        return (device);
                    299: }
                    300: 
                    301: 
                    302: /*** Opening devices.  ***/
                    303: 
                    304: 
                    305: device_t
                    306: dev_open_alloc (void)
                    307: {
                    308:   device_t dev = (device_t) zalloc (dev_hdr_zone);
                    309:   simple_lock_init(&dev->ref_lock);
                    310:   dev->ref_count = 1;
                    311:   simple_lock_init(&dev->lock);
                    312: 
                    313:   /*
                    314:    * Allocate port, keeping a reference for it.
                    315:    */
                    316:   dev->port = ipc_port_alloc_kernel ();
                    317:   if (dev->port == IP_NULL)
                    318:     {
                    319:       zfree (dev_hdr_zone, (vm_offset_t) dev);
                    320:       return DEVICE_NULL;
                    321:     }
                    322: 
                    323:   /* Associate the port with the device.  */
                    324:   ipc_kobject_set (dev->port, (ipc_kobject_t) dev, IKOT_DEVICE);
                    325: 
                    326:   return dev;
                    327: }
                    328: 
                    329: 
                    330: void
                    331: setup_no_senders (device_t dev)
                    332: {
                    333:   ipc_port_t notify;
                    334: 
                    335:   /*
                    336:    * Request no-senders notifications on device port.
                    337:    * One ref in DEV->ref_count is held by the existence of send rights;
                    338:    * the no-senders notification will release that ref.
                    339:    */
                    340:   notify = ipc_port_make_sonce(dev->port);
                    341:   ip_lock(dev->port);
                    342:   ipc_port_nsrequest(dev->port, 1, notify, &notify);
                    343:   assert(notify == IP_NULL);
                    344: 
                    345:   device_reference (dev);
                    346: }
                    347: 
                    348: 
                    349: /* Given a COM device object and an i/o mode, produce an open device.
                    350:    Always consumes a ref on COM_DEVICE.  */
                    351: static io_return_t
                    352: dev_open_com (oskit_device_t *com_device, dev_mode_t mode, device_t *devp,
                    353:              const char *diskpart)
                    354: {
                    355:   device_t dev;
                    356:   const struct device_ops *ops;
                    357: 
                    358:   /* First we look for an existing device port already open.  */
                    359:  lookup:
                    360:   simple_lock (&dev_hash_lock);
                    361:   dev = dev_hash_lookup (com_device, mode);
                    362:   if (dev != DEVICE_NULL)
                    363:     {
                    364:       /* Acquire a reference on the device, as by device_reference.
                    365:         We don't just call that because of the locking here.  */
                    366:       device_lock (dev);
                    367:       ++dev->ref_count;
                    368:       simple_unlock (&dev_hash_lock);
                    369: 
                    370:       DEV_LOCK (dev);
                    371:       oskit_device_release (com_device); /* consume ref passed in */
                    372:       DEV_UNLOCK (dev);
                    373:       if (dev->ops == 0)
                    374:        {
                    375:          /* Somebody else is blocked in the oskit getting this device open.
                    376:             We will block until they wake us up.  */
                    377:          dev->mode |= D_NODELAY;       /* mark for opener */
                    378:          thread_sleep ((event_t) dev, simple_lock_addr (dev->lock), TRUE);
                    379:          /* Repeat the lookup in case DEV got killed in a failed open.  */
                    380:          goto lookup;
                    381:        }
                    382:       else
                    383:        device_unlock (dev);
                    384: 
                    385:       goto got_device;
                    386:     }
                    387:   simple_unlock (&dev_hash_lock);
                    388: 
                    389:   /* Nope!  We will need a new device port.  */
                    390: 
                    391:   dev = dev_open_alloc ();
                    392:   if (!dev)
                    393:       return KERN_RESOURCE_SHORTAGE;
                    394: 
                    395:   dev->com_device = com_device;
                    396:   dev->mode = mode;
                    397:   dev->ops = 0;
                    398: 
                    399:   /* Put the device in the hash table under its COM device.  We hold the
                    400:      only reference to the device, and releasing that reference will remove
                    401:      it from the hash table.  While it's live, someone else might come
                    402:      along and find it in the hash table and get their own reference to
                    403:      keep it there.  After this point we need to use device_lock.  */
                    404:   simple_lock (&dev_hash_lock);
                    405:   dev_hash_enter (dev);
                    406:   simple_unlock (&dev_hash_lock);
                    407: 
                    408:   /* Now we must open the oskit device, first determining which flavor it is.
                    409:    */
                    410:   {
                    411:     oskit_bus_t *bus;
                    412:     oskit_blkdev_t *blkdev;
                    413:     oskit_netdev_t *netdev;
                    414: #ifdef oskit_streamdev_open
                    415:     oskit_streamdev_t *streamdev;
                    416: #endif
                    417:     oskit_error_t rc;
                    418:     inline void asyncio_init (device_t dev)
                    419:       {
                    420:        dev->com.stream.listening = 0;
                    421:        queue_init (&dev->com.stream.read_queue);
                    422:        queue_init (&dev->com.stream.write_queue);
                    423:        dev->com.stream.ready_queue.next = 0;
                    424:       }
                    425: 
                    426:     if (oskit_device_query (com_device, &oskit_stream_iid,
                    427:                            (void **) &dev->com.stream.io) == 0)
                    428:       {
                    429:        /* Special case for minimal console stream, not really a device.  */
                    430:        if (oskit_stream_query (dev->com.stream.io, &oskit_asyncio_iid,
                    431:                                (void **) &dev->com.stream.aio) == 0)
                    432:          {
                    433:            asyncio_init (dev);
                    434:            ops = &asyncio_device_ops;
                    435:          }
                    436:        else
                    437:          ops = &stream_device_ops;
                    438:        rc = 0;
                    439: 
                    440:        /* Kludge for kmsg.  */
                    441:        if ((void *) com_device == kmsg_stream && (mode & D_READ))
                    442:          ++kmsg_readers;
                    443:       }
                    444:     else if (oskit_device_query (com_device, &oskit_bus_iid,
                    445:                                 (void **) &bus) == 0)
                    446:       {
                    447:        if (mode & D_WRITE)
                    448:          {
                    449:            device_lock (dev);
                    450:            mode = dev->mode & D_NODELAY;
                    451:            device_unlock (dev);
                    452:            if (mode & D_NODELAY)
                    453:              /* Someone was waiting for us to finish opening.  */
                    454:              thread_wakeup ((event_t)dev);
                    455:            device_deallocate (dev);
                    456:            return D_READ_ONLY;
                    457:          }
                    458:        ops = &bus_device_ops;
                    459:        rc = populate_bus (dev, bus);
                    460:        oskit_bus_release (bus);
                    461:       }
                    462:     else if (oskit_device_query (com_device, &oskit_blkdev_iid,
                    463:                                 (void **) &blkdev) == 0)
                    464:       {
                    465:        ops = &block_device_ops;
                    466:        rc = oskit_blkdev_open (blkdev,
                    467:                                ((mode & D_READ) ? OSKIT_DEV_OPEN_READ : 0) |
                    468:                                ((mode & D_WRITE) ? OSKIT_DEV_OPEN_WRITE : 0),
                    469:                                &dev->com.blk.io);
                    470:        oskit_blkdev_release (blkdev);
                    471:        if (OSKIT_SUCCEEDED (rc))
                    472:          dev->com.blk.size = oskit_blkio_getblocksize (dev->com.blk.io);
                    473:        dev->com.blk.parts = 0;
                    474:       }
                    475:     else if (oskit_device_query (com_device, &oskit_netdev_iid,
                    476:                                 (void **) &netdev) == 0)
                    477:       {
                    478:        ops = &net_device_ops;
                    479:        rc = ds_netdev_open (dev, netdev);
                    480:       }
                    481: #ifdef oskit_streamdev_open
                    482:     else if (oskit_device_query (com_device, &oskit_streamdev_iid,
                    483:                                 (void **) &streamdev) == 0)
                    484:       {
                    485:        rc = oskit_streamdev_open (streamdev,
                    486:                                   ((mode & D_READ) ? OSKIT_DEV_OPEN_READ : 0)
                    487:                                   | ((mode & D_WRITE)
                    488:                                      ? OSKIT_DEV_OPEN_WRITE : 0),
                    489:                                   &dev->com.stream.io);
                    490:        oskit_streamdev_release (streamdev);
                    491:        if (OSKIT_SUCCEEDED (rc))
                    492:          {
                    493:            if (oskit_stream_query (dev->com.stream.io, &oskit_asyncio_iid,
                    494:                                    (void **) &dev->com.stream.aio) == 0)
                    495:              {
                    496:                asyncio_init (dev);
                    497:                ops = &asyncio_device_ops;
                    498:              }
                    499:            else
                    500:              ops = &stream_device_ops;
                    501:          }
                    502:       }
                    503: #endif
                    504: 
                    505:     if (OSKIT_FAILED (rc))
                    506:       {
                    507:        if (dev->mode & D_NODELAY)
                    508:          /* Someone was waiting for us to finish opening.  */
                    509:          thread_wakeup ((event_t)dev);
                    510:        device_deallocate (dev);
                    511:        return oskit_to_mach_error (rc);
                    512:       }
                    513:   }
                    514: 
                    515:   device_lock (dev);
                    516:   dev->ops = ops;
                    517:   mode = dev->mode & D_NODELAY;
                    518:   dev->mode &= ~D_NODELAY;
                    519:   device_unlock (dev);
                    520:   if (mode)
                    521:     /* Someone was waiting for us to finish opening.  */
                    522:     thread_wakeup ((event_t)dev);
                    523: 
                    524:   setup_no_senders (dev);
                    525: 
                    526:   /* Return the open device.  */
                    527: 
                    528:  got_device:
                    529: 
                    530:   if (diskpart)
                    531:     {
                    532:       diskpart_t *part;
                    533:       device_t subdev;
                    534: 
                    535:       /* Kludge for partitioning.  */
                    536:       if (dev->ops != &block_device_ops)
                    537:        {
                    538:          device_deallocate (dev);
                    539:          return D_NO_SUCH_DEVICE;
                    540:        }
                    541: 
                    542:       device_lock (dev);
                    543:       if (dev->com.blk.parts == 0)
                    544:        {
                    545:          diskpart_t *parts = (void *) kalloc (MAX_PARTS * sizeof *parts);
                    546:          int n = diskpart_blkio_get_partition (dev->com.blk.io,
                    547:                                                parts, MAX_PARTS);
                    548:          if (n <= 0)
                    549:            {
                    550:              device_unlock (dev);
                    551:              kfree ((vm_offset_t) parts, MAX_PARTS * sizeof *parts);
                    552:              device_deallocate (dev);
                    553:              return D_NO_SUCH_DEVICE;
                    554:            }
                    555:          dev->com.blk.parts = parts;
                    556:        }
                    557:       device_unlock (dev);
                    558: 
                    559:       part = diskpart_lookup_bsd_string (dev->com.blk.parts, diskpart);
                    560:       if (part == 0)
                    561:        {
                    562:          device_deallocate (dev);
                    563:          return D_NO_SUCH_DEVICE;
                    564:        }
                    565: 
                    566:       /* Now we have the pointer to the partition we want.  For partition
                    567:         pseudo-devices, we use this pointer in lieu of the COM object
                    568:         pointer as the key in the device hash table.  */
                    569:       simple_lock (&dev_hash_lock);
                    570:       subdev = dev_hash_lookup ((void *) part, mode);
                    571:       if (subdev != DEVICE_NULL)
                    572:        {
                    573:          device_lock (subdev);
                    574:          ++subdev->ref_count;
                    575:          simple_unlock (&dev_hash_lock);
                    576: 
                    577:          device_deallocate (dev);
                    578:          dev = subdev;
                    579:        }
                    580:       else
                    581:        {
                    582:          simple_unlock (&dev_hash_lock);
                    583: 
                    584:          subdev = dev_open_alloc ();
                    585:          if (!subdev)
                    586:            {
                    587:              device_deallocate (dev);
                    588:              return KERN_RESOURCE_SHORTAGE;
                    589:            }
                    590: 
                    591:          mode = dev->mode;
                    592:          subdev->com.blkpart.blk = dev; /* consumes our ref */
                    593:          subdev->com.blkpart.part = part;
                    594:          dev = subdev;
                    595: 
                    596:          dev->com_device = (void *) part;
                    597:          dev->mode = mode;
                    598:          dev->ops = &block_partition_device_ops;
                    599: 
                    600:          simple_lock (&dev_hash_lock);
                    601:          dev_hash_enter (dev);
                    602:          simple_unlock (&dev_hash_lock);
                    603: 
                    604:          setup_no_senders (dev);
                    605:        }
                    606:     }
                    607: 
                    608:   *devp = dev;                 /* Caller consumes the reference.  */
                    609:   return D_SUCCESS;
                    610: }
                    611: 
                    612: /* Create a special pseudo-device that maps contiguous physical memory
                    613:    starting with the physical memory backing the wired kernel virtual
                    614:    address KVA.  See ds_mem.c for the device ops.  */
                    615: static io_return_t
                    616: special_mem_device (device_t *loc,
                    617:                    dev_mode_t mode,
                    618:                    vm_offset_t kva, vm_size_t size, vm_size_t recsize,
                    619:                    device_t *out_dev)
                    620: {
                    621:   if (*loc == DEVICE_NULL)
                    622:     {
                    623:       device_t dev = dev_open_alloc ();
                    624:       if (dev == DEVICE_NULL)
                    625:        return KERN_RESOURCE_SHORTAGE;
                    626:       dev->mode = mode & (D_READ|D_WRITE);
                    627:       dev->com_device = 0;
                    628:       dev->com.mem.pa = pmap_extract (kernel_pmap, kva);
                    629:       dev->com.mem.size = size;
                    630:       dev->com.mem.recsize = recsize;
                    631:       dev->ops = &mem_device_ops;
                    632:       *loc = dev;
                    633: 
                    634:       /* The *LOC value (in a global variable) holds a reference that
                    635:         is never released.  */
                    636:     }
                    637: 
                    638:   device_reference (*loc);  /* This reference is consumed by the caller.  */
                    639:   *out_dev = *loc;
                    640:   return D_SUCCESS;
                    641: }
                    642: 
                    643: 
                    644: io_return_t
                    645: ds_device_open (ipc_port_t open_port, ipc_port_t reply_port,
                    646:                mach_msg_type_name_t reply_port_type, dev_mode_t mode,
                    647:                char *name, device_t *devp)
                    648: {
                    649:   char constructed[200];
                    650:   oskit_error_t rc;
                    651:   oskit_device_t *com_device;
                    652:   const char *subpart = 0;
                    653: 
                    654:   /* Open must be called on the master device port.  */
                    655:   if (open_port != master_device_port)
                    656:     INVALOP;
                    657: 
                    658:   /* There must be a reply port.  */
                    659:   if (! IP_VALID (reply_port))
                    660:     return MIG_NO_REPLY;
                    661: 
                    662:   if (name[0] == '@')          /* Bus tree location.  */
                    663:     {
                    664:       rc = oskit_bus_walk_lookup (name, &com_device, &subpart);
                    665:       if (OSKIT_FAILED (rc))
                    666:        return oskit_to_mach_error (rc);
                    667:     }
                    668:   else if (!strcmp (name, "console")) /* Special case.  */
                    669:     {
                    670:       com_device = (oskit_device_t *) ds_console_stream; /* not a device */
                    671:       oskit_device_addref (com_device);
                    672: 
                    673:       /* Kludge.  We don't do this at bootup so that the printing of any
                    674:         kernel lossage or panics will be easier to read.  But we need it
                    675:         set for real use of the console device.  It's harmless to call
                    676:         this more than once, since it just sets a variable.  */
                    677:       direct_cons_set_flags (DC_NO_ONLCR);
                    678:     }
                    679:   else if (!strcmp (name, "kmsg")) /* Special case.  */
                    680:     {
                    681:       com_device = (oskit_device_t *) kmsg_stream; /* not a device */
                    682:       oskit_device_addref (com_device);
                    683:     }
                    684:   else if (!strcmp (name, "time")) /* Special case.  */
                    685:     {
                    686:       extern time_value_t *mtime;
                    687:       static device_t mapped_time_device;
                    688:       if (mode & D_WRITE)      /* No writing of "time" device allowed;  */
                    689:        return D_READ_ONLY;     /* users must do host_set_time instead.  */
                    690:       return special_mem_device (&mapped_time_device, D_READ,
                    691:                                 (vm_offset_t) mtime,
                    692:                                 sizeof *mtime, sizeof mtime->seconds,
                    693:                                 devp);
                    694:     }
                    695:   else if (!strcmp (name, "mem")) /* Special case.  */
                    696:     {
                    697:       static device_t phys_mem_device;
                    698:       return special_mem_device (&phys_mem_device, mode,
                    699:                                 phystokv (0), ~(vm_offset_t)0, 1,
                    700:                                 devp);
                    701:     }
                    702:   else if (bus_walk_from_compat_string (name, constructed)) /* compat hack */
                    703:     {
                    704:       /* The name was recognized as a compatibility syntax, and CONSTRUCTED
                    705:         now contains a name in bus walk syntax (starting with an '@').  */
                    706:       rc = oskit_bus_walk_lookup (constructed, &com_device, &subpart);
                    707:       if (OSKIT_FAILED (rc))
                    708:        return oskit_to_mach_error (rc);
                    709:     }
                    710:   else                         /* I got no clue.  */
                    711:     return D_NO_SUCH_DEVICE;
                    712: 
                    713:   return dev_open_com (com_device, mode & (D_READ | D_WRITE), devp, subpart);
                    714: }
                    715: 
                    716: io_return_t
                    717: ds_device_close (device_t dev)
                    718: {
                    719:   if (dev == DEVICE_NULL)
                    720:     return D_NO_SUCH_DEVICE;
                    721: 
                    722:   /* The device_close RPC never does anything.
                    723:      The device gets closed when the last send right to its port dies.  */
                    724: 
                    725:   return D_SUCCESS;
                    726: }
                    727: 
                    728: 
                    729: 
                    730: /* Server functions for RPCs to open devices.
                    731: 
                    732:    Note: These functions expect a migworthy return value from the dev->ops
                    733:    functions, i.e. MIG_NO_REPLY and not D_IO_QUEUED.
                    734: */
                    735: 
                    736: io_return_t
                    737: ds_device_write (device_t dev, ipc_port_t reply_port,
                    738:                 mach_msg_type_name_t reply_port_type, dev_mode_t mode,
                    739:                 recnum_t recnum, io_buf_ptr_t data,
                    740:                 mach_msg_type_number_t count,
                    741:                 int *bytes_written)
                    742: {
                    743:   if (dev == DEVICE_NULL)
                    744:     return D_NO_SUCH_DEVICE;
                    745:   if (!(dev->mode & D_WRITE))
                    746:     INVALOP;
                    747:   if (! data)
                    748:     INVALSZ;
                    749:   if (! dev->ops->write)
                    750:     {
                    751:       if (!dev->ops->write_inband)
                    752:        return D_READ_ONLY;
                    753:       else
                    754:        {
                    755:          /*
                    756:           * Copy out-of-line data into kernel address space.
                    757:           * Since data is copied as page list, it will be
                    758:           * accessible.
                    759:           */
                    760:          vm_offset_t addr;
                    761:          kern_return_t kr = vm_map_copyout (device_io_map, &addr,
                    762:                                             (vm_map_copy_t) data);
                    763:          if (kr != KERN_SUCCESS)
                    764:            return kr;
                    765: 
                    766:          /* Note: we assume that write_inband can take a large count.  */
                    767:          kr = (*dev->ops->write_inband) (dev, reply_port,
                    768:                                          reply_port_type, mode, recnum,
                    769:                                          (char *) addr, count,
                    770:                                          bytes_written);
                    771:          (void) vm_deallocate (device_io_map, addr, count);
                    772:          if (kr == KERN_SUCCESS || kr == MIG_NO_REPLY)
                    773:            return kr;
                    774:          /* We don't want to return an error to our caller, because it
                    775:             will respond to that by destroying the message body--but we
                    776:             have already consumed DATA, and destroying it would be bad.  */
                    777:          if (IP_VALID (reply_port))
                    778:            ds_device_write_error_reply (reply_port, reply_port_type, kr);
                    779:          return MIG_NO_REPLY;
                    780:        }
                    781:     }
                    782:   return (*dev->ops->write) (dev, reply_port,
                    783:                             reply_port_type, mode, recnum,
                    784:                             data, count, bytes_written);
                    785: }
                    786: 
                    787: io_return_t
                    788: ds_device_write_inband (device_t dev, ipc_port_t reply_port,
                    789:                        mach_msg_type_name_t reply_port_type,
                    790:                        dev_mode_t mode, recnum_t recnum,
                    791:                        io_buf_ptr_inband_t data, unsigned count,
                    792:                        int *bytes_written)
                    793: {
                    794:   if (dev == DEVICE_NULL)
                    795:     return D_NO_SUCH_DEVICE;
                    796:   if (!(dev->mode & D_WRITE))
                    797:     INVALOP;
                    798:   if (! data)
                    799:     INVALSZ;
                    800:   assert (count <= IO_INBAND_MAX);
                    801:   if (! dev->ops->write_inband)
                    802:     {
                    803:       if (! dev->ops->write)
                    804:        INVALOP;
                    805:       else
                    806:        {
                    807:          vm_offset_t addr;
                    808:          kern_return_t kr;
                    809:          vm_map_copy_t copy;
                    810: 
                    811:          assert (IO_INBAND_MAX <= PAGE_SIZE);
                    812:          kr = kmem_alloc (kernel_map, &addr, PAGE_SIZE);
                    813:          if (kr != KERN_SUCCESS)
                    814:            return kr;
                    815: 
                    816:          memcpy ((char *) addr, data, count);
                    817:          kr = vm_map_copyin_page_list (kernel_map, addr, PAGE_SIZE,
                    818:                                        TRUE, TRUE, &copy, FALSE);
                    819:          assert (kr == KERN_SUCCESS);
                    820: 
                    821:          kr = (*dev->ops->write) (dev, reply_port,
                    822:                                   reply_port_type, mode, recnum,
                    823:                                   (char *) copy, count, bytes_written);
                    824:          if (kr != D_SUCCESS)
                    825:            vm_map_copy_discard (copy);
                    826:          return kr;
                    827:        }
                    828:     }
                    829:   return (*dev->ops->write_inband) (dev, reply_port,
                    830:                                    reply_port_type, mode, recnum,
                    831:                                    data, count, bytes_written);
                    832: }
                    833: 
                    834: io_return_t
                    835: ds_device_read (device_t dev, ipc_port_t reply_port,
                    836:                mach_msg_type_name_t reply_port_type, dev_mode_t mode,
                    837:                recnum_t recnum, int count, io_buf_ptr_t *data,
                    838:                unsigned *bytes_read)
                    839: {
                    840:   io_return_t err;
                    841: 
                    842:   /* There must be a reply port.  */
                    843:   if (! IP_VALID (reply_port))
                    844:     return MIG_NO_REPLY;
                    845:   if (dev == DEVICE_NULL)
                    846:     return D_NO_SUCH_DEVICE;
                    847:   if (!(dev->mode & D_READ))
                    848:     INVALOP;
                    849: 
                    850:   err = (dev->ops->read ? (*dev->ops->read) (dev, reply_port,
                    851:                                             reply_port_type, mode, recnum,
                    852:                                             count, data, bytes_read)
                    853:         : D_INVALID_OPERATION);
                    854: 
                    855:   /* The ops->read function can return D_INVALID_OPERATION to tell us that
                    856:      it doesn't want to deal with making a copy object for this read.  We
                    857:      fall back to the generic code below using the inband read function.  */
                    858:   if (err != D_INVALID_OPERATION)
                    859:     return err;
                    860: 
                    861:   if (! dev->ops->read_inband)
                    862:     INVALOP;
                    863:   else
                    864:     {
                    865:       vm_offset_t addr;
                    866:       vm_size_t size;
                    867:       kern_return_t kr;
                    868: 
                    869:       size = round_page (count);
                    870:       kr = kmem_alloc (kernel_map, &addr, size);
                    871:       if (kr != KERN_SUCCESS)
                    872:        return kr;
                    873:       kr = (*dev->ops->read_inband) (dev, reply_port,
                    874:                                     reply_port_type, mode, recnum,
                    875:                                     count, (char *) addr, bytes_read);
                    876:       if (kr == D_SUCCESS)
                    877:        {
                    878:          vm_size_t result_size = round_page (*bytes_read);
                    879: 
                    880:          /* Free any excess pages we allocated beyond what was used.  */
                    881:          size -= result_size;
                    882:          if (size > 0)
                    883:            vm_deallocate (kernel_map, addr + result_size, size);
                    884: 
                    885:          /* Zero memory that the device did not fill.  */
                    886:          memset ((char *) addr + *bytes_read, 0,
                    887:                  result_size - *bytes_read);
                    888: 
                    889:          kr = vm_map_copyin_page_list (kernel_map, addr, result_size,
                    890:                                        TRUE, TRUE, (vm_map_copy_t *) data,
                    891:                                        FALSE);
                    892:          if (kr != KERN_SUCCESS)
                    893:            panic ("vm_map_copyin_page_list failed");
                    894:        }
                    895:       else
                    896:        {
                    897:          /* Deallocate the pages since the read failed completely.  */
                    898:          vm_deallocate (kernel_map, addr, size);
                    899:        }
                    900:       return kr;
                    901:     }
                    902: }
                    903: 
                    904: io_return_t
                    905: ds_device_read_inband (device_t dev, ipc_port_t reply_port,
                    906:                       mach_msg_type_name_t reply_port_type, dev_mode_t mode,
                    907:                       recnum_t recnum, int count, char *data,
                    908:                       unsigned *bytes_read)
                    909: {
                    910:   /* There must be a reply port.  */
                    911:   if (! IP_VALID (reply_port))
                    912:     return MIG_NO_REPLY;
                    913:   if (dev == DEVICE_NULL)
                    914:     return D_NO_SUCH_DEVICE;
                    915:   if (!(dev->mode & D_READ))
                    916:     INVALOP;
                    917:   if (count > IO_INBAND_MAX)
                    918:     count = IO_INBAND_MAX;
                    919: 
                    920:   if (dev->ops->read_inband)
                    921:     return (*dev->ops->read_inband) (dev, reply_port,
                    922:                                     reply_port_type, mode, recnum,
                    923:                                     count, data, bytes_read);
                    924:   if (dev->ops->read)
                    925:     {
                    926:       vm_map_copy_t copy;
                    927:       io_return_t err = (*dev->ops->read) (dev, reply_port,
                    928:                                           reply_port_type, mode, recnum,
                    929:                                           count,
                    930:                                           (io_buf_ptr_t *) &copy,
                    931:                                           bytes_read);
                    932:       if (!err)
                    933:        {
                    934:          vm_offset_t addr;
                    935:          err = vm_map_copyout (kernel_map, &addr, copy);
                    936:          assert (!err);
                    937:          memcpy (data, (char *) addr, *bytes_read);
                    938:          vm_deallocate (kernel_map, addr, round_page (*bytes_read));
                    939:        }
                    940:       return err;
                    941:     }
                    942: 
                    943:   INVALOP;
                    944: }
                    945: 
                    946: io_return_t
                    947: ds_device_set_status (device_t dev, dev_flavor_t flavor,
                    948:                      dev_status_t status, mach_msg_type_number_t status_count)
                    949: {
                    950:   if (dev == DEVICE_NULL)
                    951:     return D_NO_SUCH_DEVICE;
                    952:   if (! dev->ops->set_status)
                    953:     INVALOP;
                    954: 
                    955:   return (*dev->ops->set_status) (dev, flavor, status,
                    956:                                       status_count);
                    957: }
                    958: 
                    959: io_return_t
                    960: ds_device_get_status (device_t dev, dev_flavor_t flavor, dev_status_t status,
                    961:                      mach_msg_type_number_t *status_count)
                    962: {
                    963:   if (dev == DEVICE_NULL)
                    964:     return D_NO_SUCH_DEVICE;
                    965:   if (! dev->ops->get_status)
                    966:     INVALOP;
                    967: 
                    968:   return (*dev->ops->get_status) (dev, flavor, status,
                    969:                                       status_count);
                    970: }
                    971: 
                    972: io_return_t
                    973: ds_device_set_filter (device_t dev, ipc_port_t receive_port, int priority,
                    974:                      filter_t *filter, unsigned filter_count)
                    975: {
                    976:   if (dev == DEVICE_NULL)
                    977:     return D_NO_SUCH_DEVICE;
                    978:   if (! dev->ops->set_filter)
                    979:     INVALOP;
                    980:   return (*dev->ops->set_filter) (dev, receive_port,
                    981:                                       priority, filter, filter_count);
                    982: }
                    983: 
                    984: io_return_t
                    985: ds_device_map (device_t dev, vm_prot_t prot, vm_offset_t offset,
                    986:               vm_size_t size, ipc_port_t *pager, boolean_t unmap)
                    987: {
                    988:   kern_return_t kr;
                    989: 
                    990:   if (dev == DEVICE_NULL)
                    991:     return D_NO_SUCH_DEVICE;
                    992:   if (! dev->ops->map)
                    993:     INVALOP;
                    994: 
                    995:   if (dev->mode != (D_READ | ((prot & VM_PROT_WRITE) ? D_WRITE : 0)))
                    996:     INVALOP;
                    997: 
                    998:   /* This call serves only to verify that this offset and size are valid.
                    999:      It does not do any mapping!  All the real work with the VM system
                   1000:      is done by the device pager code (found in device/dev_pager.c).  */
                   1001:   kr = (*dev->ops->map) (dev, prot, offset, size, 0);
                   1002:   if (!kr)
                   1003:     kr = device_pager_setup (dev, prot, offset, size, pager);
                   1004:   return kr;
                   1005: }
                   1006: 
                   1007: 
                   1008: io_return_t
                   1009: ds_device_write_trap (device_t dev, dev_mode_t mode,
                   1010:                      recnum_t recnum, vm_offset_t data, vm_size_t count)
                   1011: {
                   1012:   if (dev == DEVICE_NULL)
                   1013:     return D_NO_SUCH_DEVICE;
                   1014:   if (!(dev->mode & D_WRITE))
                   1015:     return D_INVALID_OPERATION;
                   1016:   if (! dev->ops->write_trap)
                   1017:     return D_INVALID_OPERATION;
                   1018:   return (*dev->ops->write_trap) (dev, mode, recnum, data, count);
                   1019: }
                   1020: 
                   1021: io_return_t
                   1022: ds_device_writev_trap (device_t dev, dev_mode_t mode,
                   1023:                       recnum_t recnum, io_buf_vec_t *iovec, vm_size_t count)
                   1024: {
                   1025:   if (dev == DEVICE_NULL)
                   1026:     return D_NO_SUCH_DEVICE;
                   1027:   if (!(dev->mode & D_WRITE))
                   1028:     return D_INVALID_OPERATION;
                   1029:   if (! dev->ops->writev_trap)
                   1030:     return D_INVALID_OPERATION;
                   1031:   return (*dev->ops->writev_trap) (dev, mode, recnum, iovec, count);
                   1032: }

unix.superglobalmegacorp.com

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