|
|
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, ¬ify); ! 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, ©, 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 *) ©, ! 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.