Annotation of OSKit-Mach/oskit/ds_routines.c, revision 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.