|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1991,1990 Carnegie Mellon University ! 4: * All Rights Reserved. ! 5: * ! 6: * Permission to use, copy, modify and distribute this software and its ! 7: * documentation is hereby granted, provided that both the copyright ! 8: * notice and this permission notice appear in all copies of the ! 9: * software, derivative works or modified versions, and any portions ! 10: * thereof, and that both notices appear in supporting documentation. ! 11: * ! 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 15: * ! 16: * Carnegie Mellon requests users of this software to return to ! 17: * ! 18: * Software Distribution Coordinator or [email protected] ! 19: * School of Computer Science ! 20: * Carnegie Mellon University ! 21: * Pittsburgh PA 15213-3890 ! 22: * ! 23: * any improvements or extensions that they make and grant Carnegie Mellon ! 24: * the rights to redistribute these changes. ! 25: */ ! 26: ! 27: #include <norma_vm.h> ! 28: ! 29: #include <mach/boolean.h> ! 30: #include <mach/port.h> ! 31: #include <mach/message.h> ! 32: #include <mach/thread_status.h> ! 33: #include <kern/ast.h> ! 34: #include <kern/ipc_tt.h> ! 35: #include <kern/thread.h> ! 36: #include <kern/task.h> ! 37: #include <kern/ipc_kobject.h> ! 38: #include <vm/vm_map.h> ! 39: #include <vm/vm_user.h> ! 40: #include <ipc/port.h> ! 41: #include <ipc/ipc_kmsg.h> ! 42: #include <ipc/ipc_entry.h> ! 43: #include <ipc/ipc_object.h> ! 44: #include <ipc/ipc_mqueue.h> ! 45: #include <ipc/ipc_space.h> ! 46: #include <ipc/ipc_port.h> ! 47: #include <ipc/ipc_pset.h> ! 48: #include <ipc/ipc_thread.h> ! 49: #include <device/device_types.h> ! 50: ! 51: ! 52: /* ! 53: * Routine: mach_msg_send_from_kernel ! 54: * Purpose: ! 55: * Send a message from the kernel. ! 56: * ! 57: * This is used by the client side of KernelUser interfaces ! 58: * to implement SimpleRoutines. Currently, this includes ! 59: * device_reply and memory_object messages. ! 60: * Conditions: ! 61: * Nothing locked. ! 62: * Returns: ! 63: * MACH_MSG_SUCCESS Sent the message. ! 64: * MACH_SEND_INVALID_DATA Bad destination port. ! 65: */ ! 66: ! 67: mach_msg_return_t ! 68: mach_msg_send_from_kernel( ! 69: mach_msg_header_t *msg, ! 70: mach_msg_size_t send_size) ! 71: { ! 72: ipc_kmsg_t kmsg; ! 73: mach_msg_return_t mr; ! 74: ! 75: if (!MACH_PORT_VALID(msg->msgh_remote_port)) ! 76: return MACH_SEND_INVALID_DEST; ! 77: ! 78: mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg); ! 79: if (mr != MACH_MSG_SUCCESS) ! 80: panic("mach_msg_send_from_kernel"); ! 81: ! 82: ipc_kmsg_copyin_from_kernel(kmsg); ! 83: ipc_mqueue_send_always(kmsg); ! 84: ! 85: return MACH_MSG_SUCCESS; ! 86: } ! 87: ! 88: mach_msg_return_t ! 89: mach_msg_rpc_from_kernel(msg, send_size, reply_size) ! 90: mach_msg_header_t *msg; ! 91: mach_msg_size_t send_size; ! 92: mach_msg_size_t reply_size; ! 93: { ! 94: panic("mach_msg_rpc_from_kernel"); /*XXX*/ ! 95: } ! 96: ! 97: #if NORMA_VM ! 98: /* ! 99: * Routine: mach_msg_rpc_from_kernel ! 100: * Purpose: ! 101: * Send a message from the kernel and receive a reply. ! 102: * Uses ith_rpc_reply for the reply port. ! 103: * ! 104: * This is used by the client side of KernelUser interfaces ! 105: * to implement Routines. ! 106: * Conditions: ! 107: * Nothing locked. ! 108: * Returns: ! 109: * MACH_MSG_SUCCESS Sent the message. ! 110: * MACH_RCV_PORT_DIED The reply port was deallocated. ! 111: */ ! 112: ! 113: mach_msg_return_t ! 114: mach_msg_rpc_from_kernel( ! 115: mach_msg_header_t *msg, ! 116: mach_msg_size_t send_size, ! 117: mach_msg_size_t rcv_size) ! 118: { ! 119: ipc_thread_t self = current_thread(); ! 120: ipc_port_t reply; ! 121: ipc_kmsg_t kmsg; ! 122: mach_port_seqno_t seqno; ! 123: mach_msg_return_t mr; ! 124: ! 125: assert(MACH_PORT_VALID(msg->msgh_remote_port)); ! 126: assert(msg->msgh_local_port == MACH_PORT_NULL); ! 127: ! 128: mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg); ! 129: if (mr != MACH_MSG_SUCCESS) ! 130: panic("mach_msg_rpc_from_kernel"); ! 131: ! 132: ipc_kmsg_copyin_from_kernel(kmsg); ! 133: ! 134: ith_lock(self); ! 135: assert(self->ith_self != IP_NULL); ! 136: ! 137: reply = self->ith_rpc_reply; ! 138: if (reply == IP_NULL) { ! 139: ith_unlock(self); ! 140: reply = ipc_port_alloc_reply(); ! 141: ith_lock(self); ! 142: if ((reply == IP_NULL) || ! 143: (self->ith_rpc_reply != IP_NULL)) ! 144: panic("mach_msg_rpc_from_kernel"); ! 145: self->ith_rpc_reply = reply; ! 146: } ! 147: ! 148: /* insert send-once right for the reply port */ ! 149: kmsg->ikm_header.msgh_local_port = ! 150: (mach_port_t) ipc_port_make_sonce(reply); ! 151: ! 152: ipc_port_reference(reply); ! 153: ith_unlock(self); ! 154: ! 155: ipc_mqueue_send_always(kmsg); ! 156: ! 157: for (;;) { ! 158: ipc_mqueue_t mqueue; ! 159: ! 160: ip_lock(reply); ! 161: if (!ip_active(reply)) { ! 162: ip_unlock(reply); ! 163: ipc_port_release(reply); ! 164: return MACH_RCV_PORT_DIED; ! 165: } ! 166: ! 167: assert(reply->ip_pset == IPS_NULL); ! 168: mqueue = &reply->ip_messages; ! 169: imq_lock(mqueue); ! 170: ip_unlock(reply); ! 171: ! 172: mr = ipc_mqueue_receive(mqueue, MACH_MSG_OPTION_NONE, ! 173: MACH_MSG_SIZE_MAX, ! 174: MACH_MSG_TIMEOUT_NONE, ! 175: FALSE, IMQ_NULL_CONTINUE, ! 176: &kmsg, &seqno); ! 177: /* mqueue is unlocked */ ! 178: if (mr == MACH_MSG_SUCCESS) ! 179: break; ! 180: ! 181: assert((mr == MACH_RCV_INTERRUPTED) || ! 182: (mr == MACH_RCV_PORT_DIED)); ! 183: ! 184: while (thread_should_halt(self)) { ! 185: /* don't terminate while holding a reference */ ! 186: if (self->ast & AST_TERMINATE) ! 187: ipc_port_release(reply); ! 188: thread_halt_self(); ! 189: } ! 190: } ! 191: ipc_port_release(reply); ! 192: ! 193: kmsg->ikm_header.msgh_seqno = seqno; ! 194: ! 195: if (rcv_size < kmsg->ikm_header.msgh_size) { ! 196: ipc_kmsg_copyout_dest(kmsg, ipc_space_reply); ! 197: ipc_kmsg_put_to_kernel(msg, kmsg, kmsg->ikm_header.msgh_size); ! 198: return MACH_RCV_TOO_LARGE; ! 199: } ! 200: ! 201: /* ! 202: * We want to preserve rights and memory in reply! ! 203: * We don't have to put them anywhere; just leave them ! 204: * as they are. ! 205: */ ! 206: ! 207: ipc_kmsg_copyout_to_kernel(kmsg, ipc_space_reply); ! 208: ipc_kmsg_put_to_kernel(msg, kmsg, kmsg->ikm_header.msgh_size); ! 209: return MACH_MSG_SUCCESS; ! 210: } ! 211: #endif /* NORMA_VM */ ! 212: ! 213: /* ! 214: * Routine: mach_msg_abort_rpc ! 215: * Purpose: ! 216: * Destroy the thread's ith_rpc_reply port. ! 217: * This will interrupt a mach_msg_rpc_from_kernel ! 218: * with a MACH_RCV_PORT_DIED return code. ! 219: * Conditions: ! 220: * Nothing locked. ! 221: */ ! 222: ! 223: void ! 224: mach_msg_abort_rpc(thread) ! 225: ipc_thread_t thread; ! 226: { ! 227: ipc_port_t reply = IP_NULL; ! 228: ! 229: ith_lock(thread); ! 230: if (thread->ith_self != IP_NULL) { ! 231: reply = thread->ith_rpc_reply; ! 232: thread->ith_rpc_reply = IP_NULL; ! 233: } ! 234: ith_unlock(thread); ! 235: ! 236: if (reply != IP_NULL) ! 237: ipc_port_dealloc_reply(reply); ! 238: } ! 239: ! 240: /* ! 241: * Routine: mach_msg ! 242: * Purpose: ! 243: * Like mach_msg_trap except that message buffers ! 244: * live in kernel space. Doesn't handle any options. ! 245: * ! 246: * This is used by in-kernel server threads to make ! 247: * kernel calls, to receive request messages, and ! 248: * to send reply messages. ! 249: * Conditions: ! 250: * Nothing locked. ! 251: * Returns: ! 252: */ ! 253: ! 254: mach_msg_return_t ! 255: mach_msg(msg, option, send_size, rcv_size, rcv_name, time_out, notify) ! 256: mach_msg_header_t *msg; ! 257: mach_msg_option_t option; ! 258: mach_msg_size_t send_size; ! 259: mach_msg_size_t rcv_size; ! 260: mach_port_t rcv_name; ! 261: mach_msg_timeout_t time_out; ! 262: mach_port_t notify; ! 263: { ! 264: ipc_space_t space = current_space(); ! 265: vm_map_t map = current_map(); ! 266: ipc_kmsg_t kmsg; ! 267: mach_port_seqno_t seqno; ! 268: mach_msg_return_t mr; ! 269: ! 270: if (option & MACH_SEND_MSG) { ! 271: mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg); ! 272: if (mr != MACH_MSG_SUCCESS) ! 273: panic("mach_msg"); ! 274: ! 275: mr = ipc_kmsg_copyin(kmsg, space, map, MACH_PORT_NULL); ! 276: if (mr != MACH_MSG_SUCCESS) { ! 277: ikm_free(kmsg); ! 278: return mr; ! 279: } ! 280: ! 281: do ! 282: mr = ipc_mqueue_send(kmsg, MACH_MSG_OPTION_NONE, ! 283: MACH_MSG_TIMEOUT_NONE); ! 284: while (mr == MACH_SEND_INTERRUPTED); ! 285: assert(mr == MACH_MSG_SUCCESS); ! 286: } ! 287: ! 288: if (option & MACH_RCV_MSG) { ! 289: do { ! 290: ipc_object_t object; ! 291: ipc_mqueue_t mqueue; ! 292: ! 293: mr = ipc_mqueue_copyin(space, rcv_name, ! 294: &mqueue, &object); ! 295: if (mr != MACH_MSG_SUCCESS) ! 296: return mr; ! 297: /* hold ref for object; mqueue is locked */ ! 298: ! 299: mr = ipc_mqueue_receive(mqueue, MACH_MSG_OPTION_NONE, ! 300: MACH_MSG_SIZE_MAX, ! 301: MACH_MSG_TIMEOUT_NONE, ! 302: FALSE, IMQ_NULL_CONTINUE, ! 303: &kmsg, &seqno); ! 304: /* mqueue is unlocked */ ! 305: ipc_object_release(object); ! 306: } while (mr == MACH_RCV_INTERRUPTED); ! 307: if (mr != MACH_MSG_SUCCESS) ! 308: return mr; ! 309: ! 310: kmsg->ikm_header.msgh_seqno = seqno; ! 311: ! 312: if (rcv_size < kmsg->ikm_header.msgh_size) { ! 313: ipc_kmsg_copyout_dest(kmsg, space); ! 314: ipc_kmsg_put_to_kernel(msg, kmsg, sizeof *msg); ! 315: return MACH_RCV_TOO_LARGE; ! 316: } ! 317: ! 318: mr = ipc_kmsg_copyout(kmsg, space, map, MACH_PORT_NULL); ! 319: if (mr != MACH_MSG_SUCCESS) { ! 320: if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) { ! 321: ipc_kmsg_put_to_kernel(msg, kmsg, ! 322: kmsg->ikm_header.msgh_size); ! 323: } else { ! 324: ipc_kmsg_copyout_dest(kmsg, space); ! 325: ipc_kmsg_put_to_kernel(msg, kmsg, sizeof *msg); ! 326: } ! 327: ! 328: return mr; ! 329: } ! 330: ! 331: ipc_kmsg_put_to_kernel(msg, kmsg, kmsg->ikm_header.msgh_size); ! 332: } ! 333: ! 334: return MACH_MSG_SUCCESS; ! 335: } ! 336: ! 337: /* ! 338: * Routine: mig_get_reply_port ! 339: * Purpose: ! 340: * Called by client side interfaces living in the kernel ! 341: * to get a reply port. This port is used for ! 342: * mach_msg() calls which are kernel calls. ! 343: */ ! 344: ! 345: mach_port_t ! 346: mig_get_reply_port(void) ! 347: { ! 348: ipc_thread_t self = current_thread(); ! 349: ! 350: if (self->ith_mig_reply == MACH_PORT_NULL) ! 351: self->ith_mig_reply = mach_reply_port(); ! 352: ! 353: return self->ith_mig_reply; ! 354: } ! 355: ! 356: /* ! 357: * Routine: mig_dealloc_reply_port ! 358: * Purpose: ! 359: * Called by client side interfaces to get rid of a reply port. ! 360: * Shouldn't ever be called inside the kernel, because ! 361: * kernel calls shouldn't prompt Mig to call it. ! 362: */ ! 363: ! 364: void ! 365: mig_dealloc_reply_port( ! 366: mach_port_t reply_port) ! 367: { ! 368: panic("mig_dealloc_reply_port"); ! 369: } ! 370: ! 371: /* ! 372: * Routine: mig_put_reply_port ! 373: * Purpose: ! 374: * Called by client side interfaces after each RPC to ! 375: * let the client recycle the reply port if it wishes. ! 376: */ ! 377: void ! 378: mig_put_reply_port( ! 379: mach_port_t reply_port) ! 380: { ! 381: } ! 382: ! 383: /* ! 384: * mig_strncpy.c - by Joshua Block ! 385: * ! 386: * mig_strncp -- Bounded string copy. Does what the library routine strncpy ! 387: * OUGHT to do: Copies the (null terminated) string in src into dest, a ! 388: * buffer of length len. Assures that the copy is still null terminated ! 389: * and doesn't overflow the buffer, truncating the copy if necessary. ! 390: * ! 391: * Parameters: ! 392: * ! 393: * dest - Pointer to destination buffer. ! 394: * ! 395: * src - Pointer to source string. ! 396: * ! 397: * len - Length of destination buffer. ! 398: */ ! 399: void mig_strncpy(dest, src, len) ! 400: char *dest, *src; ! 401: int len; ! 402: { ! 403: int i; ! 404: ! 405: if (len <= 0) ! 406: return; ! 407: ! 408: for (i=1; i<len; i++) ! 409: if (! (*dest++ = *src++)) ! 410: return; ! 411: ! 412: *dest = '\0'; ! 413: return; ! 414: } ! 415: ! 416: #define fast_send_right_lookup(name, port, abort) \ ! 417: MACRO_BEGIN \ ! 418: register ipc_space_t space = current_space(); \ ! 419: register ipc_entry_t entry; \ ! 420: register mach_port_index_t index = MACH_PORT_INDEX(name); \ ! 421: \ ! 422: is_read_lock(space); \ ! 423: assert(space->is_active); \ ! 424: \ ! 425: if ((index >= space->is_table_size) || \ ! 426: (((entry = &space->is_table[index])->ie_bits & \ ! 427: (IE_BITS_GEN_MASK|MACH_PORT_TYPE_SEND)) != \ ! 428: (MACH_PORT_GEN(name) | MACH_PORT_TYPE_SEND))) { \ ! 429: is_read_unlock(space); \ ! 430: abort; \ ! 431: } \ ! 432: \ ! 433: port = (ipc_port_t) entry->ie_object; \ ! 434: assert(port != IP_NULL); \ ! 435: \ ! 436: ip_lock(port); \ ! 437: /* can safely unlock space now that port is locked */ \ ! 438: is_read_unlock(space); \ ! 439: MACRO_END ! 440: ! 441: device_t ! 442: port_name_to_device(name) ! 443: mach_port_t name; ! 444: { ! 445: register ipc_port_t port; ! 446: register device_t device; ! 447: ! 448: fast_send_right_lookup(name, port, goto abort); ! 449: /* port is locked */ ! 450: ! 451: /* ! 452: * Now map the port object to a device object. ! 453: * This is an inline version of dev_port_lookup(). ! 454: */ ! 455: if (ip_active(port) && (ip_kotype(port) == IKOT_DEVICE)) { ! 456: device = (device_t) port->ip_kobject; ! 457: device_reference(device); ! 458: ip_unlock(port); ! 459: return device; ! 460: } ! 461: ! 462: ip_unlock(port); ! 463: return DEVICE_NULL; ! 464: ! 465: /* ! 466: * The slow case. The port wasn't easily accessible. ! 467: */ ! 468: abort: { ! 469: ipc_port_t kern_port; ! 470: kern_return_t kr; ! 471: ! 472: kr = ipc_object_copyin(current_space(), name, ! 473: MACH_MSG_TYPE_COPY_SEND, ! 474: (ipc_object_t *) &kern_port); ! 475: if (kr != KERN_SUCCESS) ! 476: return DEVICE_NULL; ! 477: ! 478: device = dev_port_lookup(kern_port); ! 479: if (IP_VALID(kern_port)) ! 480: ipc_port_release_send(kern_port); ! 481: return device; ! 482: } ! 483: } ! 484: ! 485: thread_t ! 486: port_name_to_thread(name) ! 487: mach_port_t name; ! 488: { ! 489: register ipc_port_t port; ! 490: ! 491: fast_send_right_lookup(name, port, goto abort); ! 492: /* port is locked */ ! 493: ! 494: if (ip_active(port) && ! 495: (ip_kotype(port) == IKOT_THREAD)) { ! 496: register thread_t thread; ! 497: ! 498: thread = (thread_t) port->ip_kobject; ! 499: assert(thread != THREAD_NULL); ! 500: ! 501: /* thread referencing is a bit complicated, ! 502: so don't bother to expand inline */ ! 503: thread_reference(thread); ! 504: ip_unlock(port); ! 505: ! 506: return thread; ! 507: } ! 508: ! 509: ip_unlock(port); ! 510: return THREAD_NULL; ! 511: ! 512: abort: { ! 513: thread_t thread; ! 514: ipc_port_t kern_port; ! 515: kern_return_t kr; ! 516: ! 517: kr = ipc_object_copyin(current_space(), name, ! 518: MACH_MSG_TYPE_COPY_SEND, ! 519: (ipc_object_t *) &kern_port); ! 520: if (kr != KERN_SUCCESS) ! 521: return THREAD_NULL; ! 522: ! 523: thread = convert_port_to_thread(kern_port); ! 524: if (IP_VALID(kern_port)) ! 525: ipc_port_release_send(kern_port); ! 526: ! 527: return thread; ! 528: } ! 529: } ! 530: ! 531: task_t ! 532: port_name_to_task(name) ! 533: mach_port_t name; ! 534: { ! 535: register ipc_port_t port; ! 536: ! 537: fast_send_right_lookup(name, port, goto abort); ! 538: /* port is locked */ ! 539: ! 540: if (ip_active(port) && ! 541: (ip_kotype(port) == IKOT_TASK)) { ! 542: register task_t task; ! 543: ! 544: task = (task_t) port->ip_kobject; ! 545: assert(task != TASK_NULL); ! 546: ! 547: task_lock(task); ! 548: /* can safely unlock port now that task is locked */ ! 549: ip_unlock(port); ! 550: ! 551: task->ref_count++; ! 552: task_unlock(task); ! 553: ! 554: return task; ! 555: } ! 556: ! 557: ip_unlock(port); ! 558: return TASK_NULL; ! 559: ! 560: abort: { ! 561: task_t task; ! 562: ipc_port_t kern_port; ! 563: kern_return_t kr; ! 564: ! 565: kr = ipc_object_copyin(current_space(), name, ! 566: MACH_MSG_TYPE_COPY_SEND, ! 567: (ipc_object_t *) &kern_port); ! 568: if (kr != KERN_SUCCESS) ! 569: return TASK_NULL; ! 570: ! 571: task = convert_port_to_task(kern_port); ! 572: if (IP_VALID(kern_port)) ! 573: ipc_port_release_send(kern_port); ! 574: ! 575: return task; ! 576: } ! 577: } ! 578: ! 579: vm_map_t ! 580: port_name_to_map( ! 581: mach_port_t name) ! 582: { ! 583: register ipc_port_t port; ! 584: ! 585: fast_send_right_lookup(name, port, goto abort); ! 586: /* port is locked */ ! 587: ! 588: if (ip_active(port) && ! 589: (ip_kotype(port) == IKOT_TASK)) { ! 590: register vm_map_t map; ! 591: ! 592: map = ((task_t) port->ip_kobject)->map; ! 593: assert(map != VM_MAP_NULL); ! 594: ! 595: simple_lock(&map->ref_lock); ! 596: /* can safely unlock port now that map is locked */ ! 597: ip_unlock(port); ! 598: ! 599: map->ref_count++; ! 600: simple_unlock(&map->ref_lock); ! 601: ! 602: return map; ! 603: } ! 604: ! 605: ip_unlock(port); ! 606: return VM_MAP_NULL; ! 607: ! 608: abort: { ! 609: vm_map_t map; ! 610: ipc_port_t kern_port; ! 611: kern_return_t kr; ! 612: ! 613: kr = ipc_object_copyin(current_space(), name, ! 614: MACH_MSG_TYPE_COPY_SEND, ! 615: (ipc_object_t *) &kern_port); ! 616: if (kr != KERN_SUCCESS) ! 617: return VM_MAP_NULL; ! 618: ! 619: map = convert_port_to_map(kern_port); ! 620: if (IP_VALID(kern_port)) ! 621: ipc_port_release_send(kern_port); ! 622: ! 623: return map; ! 624: } ! 625: } ! 626: ! 627: ipc_space_t ! 628: port_name_to_space(name) ! 629: mach_port_t name; ! 630: { ! 631: register ipc_port_t port; ! 632: ! 633: fast_send_right_lookup(name, port, goto abort); ! 634: /* port is locked */ ! 635: ! 636: if (ip_active(port) && ! 637: (ip_kotype(port) == IKOT_TASK)) { ! 638: register ipc_space_t space; ! 639: ! 640: space = ((task_t) port->ip_kobject)->itk_space; ! 641: assert(space != IS_NULL); ! 642: ! 643: simple_lock(&space->is_ref_lock_data); ! 644: /* can safely unlock port now that space is locked */ ! 645: ip_unlock(port); ! 646: ! 647: space->is_references++; ! 648: simple_unlock(&space->is_ref_lock_data); ! 649: ! 650: return space; ! 651: } ! 652: ! 653: ip_unlock(port); ! 654: return IS_NULL; ! 655: ! 656: abort: { ! 657: ipc_space_t space; ! 658: ipc_port_t kern_port; ! 659: kern_return_t kr; ! 660: ! 661: kr = ipc_object_copyin(current_space(), name, ! 662: MACH_MSG_TYPE_COPY_SEND, ! 663: (ipc_object_t *) &kern_port); ! 664: if (kr != KERN_SUCCESS) ! 665: return IS_NULL; ! 666: ! 667: space = convert_port_to_space(kern_port); ! 668: if (IP_VALID(kern_port)) ! 669: ipc_port_release_send(kern_port); ! 670: ! 671: return space; ! 672: } ! 673: } ! 674: ! 675: /* ! 676: * Hack to translate a thread port to a thread pointer for calling ! 677: * thread_get_state and thread_set_state. This is only necessary ! 678: * because the IPC message for these two operations overflows the ! 679: * kernel stack. ! 680: * ! 681: * AARGH! ! 682: */ ! 683: ! 684: kern_return_t thread_get_state_KERNEL(thread_port, flavor, ! 685: old_state, old_state_count) ! 686: mach_port_t thread_port; /* port right for thread */ ! 687: int flavor; ! 688: thread_state_t old_state; /* pointer to OUT array */ ! 689: natural_t *old_state_count; /* IN/OUT */ ! 690: { ! 691: thread_t thread; ! 692: kern_return_t result; ! 693: ! 694: thread = port_name_to_thread(thread_port); ! 695: result = thread_get_state(thread, flavor, old_state, old_state_count); ! 696: thread_deallocate(thread); ! 697: ! 698: return result; ! 699: } ! 700: ! 701: kern_return_t thread_set_state_KERNEL(thread_port, flavor, ! 702: new_state, new_state_count) ! 703: mach_port_t thread_port; /* port right for thread */ ! 704: int flavor; ! 705: thread_state_t new_state; ! 706: natural_t new_state_count; ! 707: { ! 708: thread_t thread; ! 709: kern_return_t result; ! 710: ! 711: thread = port_name_to_thread(thread_port); ! 712: result = thread_set_state(thread, flavor, new_state, new_state_count); ! 713: thread_deallocate(thread); ! 714: ! 715: return result; ! 716: } ! 717: ! 718: /* ! 719: * Things to keep in mind: ! 720: * ! 721: * The idea here is to duplicate the semantics of the true kernel RPC. ! 722: * The destination port/object should be checked first, before anything ! 723: * that the user might notice (like ipc_object_copyin). Return ! 724: * MACH_SEND_INTERRUPTED if it isn't correct, so that the user stub ! 725: * knows to fall back on an RPC. For other return values, it won't ! 726: * retry with an RPC. The retry might get a different (incorrect) rc. ! 727: * Return values are only set (and should only be set, with copyout) ! 728: * on successfull calls. ! 729: */ ! 730: ! 731: kern_return_t ! 732: syscall_vm_map( ! 733: mach_port_t target_map, ! 734: vm_offset_t *address, ! 735: vm_size_t size, ! 736: vm_offset_t mask, ! 737: boolean_t anywhere, ! 738: mach_port_t memory_object, ! 739: vm_offset_t offset, ! 740: boolean_t copy, ! 741: vm_prot_t cur_protection, ! 742: vm_prot_t max_protection, ! 743: vm_inherit_t inheritance) ! 744: { ! 745: vm_map_t map; ! 746: ipc_port_t port; ! 747: vm_offset_t addr; ! 748: kern_return_t result; ! 749: ! 750: map = port_name_to_map(target_map); ! 751: if (map == VM_MAP_NULL) ! 752: return MACH_SEND_INTERRUPTED; ! 753: ! 754: if (MACH_PORT_VALID(memory_object)) { ! 755: result = ipc_object_copyin(current_space(), memory_object, ! 756: MACH_MSG_TYPE_COPY_SEND, ! 757: (ipc_object_t *) &port); ! 758: if (result != KERN_SUCCESS) { ! 759: vm_map_deallocate(map); ! 760: return result; ! 761: } ! 762: } else ! 763: port = (ipc_port_t) memory_object; ! 764: ! 765: copyin((char *)address, (char *)&addr, sizeof(vm_offset_t)); ! 766: result = vm_map(map, &addr, size, mask, anywhere, ! 767: port, offset, copy, ! 768: cur_protection, max_protection, inheritance); ! 769: if (result == KERN_SUCCESS) ! 770: copyout((char *)&addr, (char *)address, sizeof(vm_offset_t)); ! 771: if (IP_VALID(port)) ! 772: ipc_port_release_send(port); ! 773: vm_map_deallocate(map); ! 774: ! 775: return result; ! 776: } ! 777: ! 778: kern_return_t syscall_vm_allocate(target_map, address, size, anywhere) ! 779: mach_port_t target_map; ! 780: vm_offset_t *address; ! 781: vm_size_t size; ! 782: boolean_t anywhere; ! 783: { ! 784: vm_map_t map; ! 785: vm_offset_t addr; ! 786: kern_return_t result; ! 787: ! 788: map = port_name_to_map(target_map); ! 789: if (map == VM_MAP_NULL) ! 790: return MACH_SEND_INTERRUPTED; ! 791: ! 792: copyin((char *)address, (char *)&addr, sizeof(vm_offset_t)); ! 793: result = vm_allocate(map, &addr, size, anywhere); ! 794: if (result == KERN_SUCCESS) ! 795: copyout((char *)&addr, (char *)address, sizeof(vm_offset_t)); ! 796: vm_map_deallocate(map); ! 797: ! 798: return result; ! 799: } ! 800: ! 801: kern_return_t syscall_vm_deallocate(target_map, start, size) ! 802: mach_port_t target_map; ! 803: vm_offset_t start; ! 804: vm_size_t size; ! 805: { ! 806: vm_map_t map; ! 807: kern_return_t result; ! 808: ! 809: map = port_name_to_map(target_map); ! 810: if (map == VM_MAP_NULL) ! 811: return MACH_SEND_INTERRUPTED; ! 812: ! 813: result = vm_deallocate(map, start, size); ! 814: vm_map_deallocate(map); ! 815: ! 816: return result; ! 817: } ! 818: ! 819: kern_return_t syscall_task_create(parent_task, inherit_memory, child_task) ! 820: mach_port_t parent_task; ! 821: boolean_t inherit_memory; ! 822: mach_port_t *child_task; /* OUT */ ! 823: { ! 824: task_t t, c; ! 825: ipc_port_t port; ! 826: mach_port_t name; ! 827: kern_return_t result; ! 828: ! 829: t = port_name_to_task(parent_task); ! 830: if (t == TASK_NULL) ! 831: return MACH_SEND_INTERRUPTED; ! 832: ! 833: result = task_create(t, inherit_memory, &c); ! 834: if (result == KERN_SUCCESS) { ! 835: port = (ipc_port_t) convert_task_to_port(c); ! 836: /* always returns a name, even for non-success return codes */ ! 837: (void) ipc_kmsg_copyout_object(current_space(), ! 838: (ipc_object_t) port, ! 839: MACH_MSG_TYPE_PORT_SEND, &name); ! 840: copyout((char *)&name, (char *)child_task, ! 841: sizeof(mach_port_t)); ! 842: } ! 843: task_deallocate(t); ! 844: ! 845: return result; ! 846: } ! 847: ! 848: kern_return_t syscall_task_terminate(task) ! 849: mach_port_t task; ! 850: { ! 851: task_t t; ! 852: kern_return_t result; ! 853: ! 854: t = port_name_to_task(task); ! 855: if (t == TASK_NULL) ! 856: return MACH_SEND_INTERRUPTED; ! 857: ! 858: result = task_terminate(t); ! 859: task_deallocate(t); ! 860: ! 861: return result; ! 862: } ! 863: ! 864: kern_return_t syscall_task_suspend(task) ! 865: mach_port_t task; ! 866: { ! 867: task_t t; ! 868: kern_return_t result; ! 869: ! 870: t = port_name_to_task(task); ! 871: if (t == TASK_NULL) ! 872: return MACH_SEND_INTERRUPTED; ! 873: ! 874: result = task_suspend(t); ! 875: task_deallocate(t); ! 876: ! 877: return result; ! 878: } ! 879: ! 880: kern_return_t syscall_task_set_special_port(task, which_port, port_name) ! 881: mach_port_t task; ! 882: int which_port; ! 883: mach_port_t port_name; ! 884: { ! 885: task_t t; ! 886: ipc_port_t port; ! 887: kern_return_t result; ! 888: ! 889: t = port_name_to_task(task); ! 890: if (t == TASK_NULL) ! 891: return MACH_SEND_INTERRUPTED; ! 892: ! 893: if (MACH_PORT_VALID(port_name)) { ! 894: result = ipc_object_copyin(current_space(), port_name, ! 895: MACH_MSG_TYPE_COPY_SEND, ! 896: (ipc_object_t *) &port); ! 897: if (result != KERN_SUCCESS) { ! 898: task_deallocate(t); ! 899: return result; ! 900: } ! 901: } else ! 902: port = (ipc_port_t) port_name; ! 903: ! 904: result = task_set_special_port(t, which_port, port); ! 905: if ((result != KERN_SUCCESS) && IP_VALID(port)) ! 906: ipc_port_release_send(port); ! 907: task_deallocate(t); ! 908: ! 909: return result; ! 910: } ! 911: ! 912: kern_return_t ! 913: syscall_mach_port_allocate(task, right, namep) ! 914: mach_port_t task; ! 915: mach_port_right_t right; ! 916: mach_port_t *namep; ! 917: { ! 918: ipc_space_t space; ! 919: mach_port_t name; ! 920: kern_return_t kr; ! 921: ! 922: space = port_name_to_space(task); ! 923: if (space == IS_NULL) ! 924: return MACH_SEND_INTERRUPTED; ! 925: ! 926: kr = mach_port_allocate(space, right, &name); ! 927: if (kr == KERN_SUCCESS) ! 928: copyout((char *)&name, (char *)namep, sizeof(mach_port_t)); ! 929: is_release(space); ! 930: ! 931: return kr; ! 932: } ! 933: ! 934: kern_return_t ! 935: syscall_mach_port_allocate_name(task, right, name) ! 936: mach_port_t task; ! 937: mach_port_right_t right; ! 938: mach_port_t name; ! 939: { ! 940: ipc_space_t space; ! 941: kern_return_t kr; ! 942: ! 943: space = port_name_to_space(task); ! 944: if (space == IS_NULL) ! 945: return MACH_SEND_INTERRUPTED; ! 946: ! 947: kr = mach_port_allocate_name(space, right, name); ! 948: is_release(space); ! 949: ! 950: return kr; ! 951: } ! 952: ! 953: kern_return_t ! 954: syscall_mach_port_deallocate(task, name) ! 955: mach_port_t task; ! 956: mach_port_t name; ! 957: { ! 958: ipc_space_t space; ! 959: kern_return_t kr; ! 960: ! 961: space = port_name_to_space(task); ! 962: if (space == IS_NULL) ! 963: return MACH_SEND_INTERRUPTED; ! 964: ! 965: kr = mach_port_deallocate(space, name); ! 966: is_release(space); ! 967: ! 968: return kr; ! 969: } ! 970: ! 971: kern_return_t ! 972: syscall_mach_port_insert_right(task, name, right, rightType) ! 973: mach_port_t task; ! 974: mach_port_t name; ! 975: mach_port_t right; ! 976: mach_msg_type_name_t rightType; ! 977: { ! 978: ipc_space_t space; ! 979: ipc_object_t object; ! 980: mach_msg_type_name_t newtype; ! 981: kern_return_t kr; ! 982: ! 983: space = port_name_to_space(task); ! 984: if (space == IS_NULL) ! 985: return MACH_SEND_INTERRUPTED; ! 986: ! 987: if (!MACH_MSG_TYPE_PORT_ANY(rightType)) { ! 988: is_release(space); ! 989: return KERN_INVALID_VALUE; ! 990: } ! 991: ! 992: if (MACH_PORT_VALID(right)) { ! 993: kr = ipc_object_copyin(current_space(), right, rightType, ! 994: &object); ! 995: if (kr != KERN_SUCCESS) { ! 996: is_release(space); ! 997: return kr; ! 998: } ! 999: } else ! 1000: object = (ipc_object_t) right; ! 1001: newtype = ipc_object_copyin_type(rightType); ! 1002: ! 1003: kr = mach_port_insert_right(space, name, (ipc_port_t) object, newtype); ! 1004: if ((kr != KERN_SUCCESS) && IO_VALID(object)) ! 1005: ipc_object_destroy(object, newtype); ! 1006: is_release(space); ! 1007: ! 1008: return kr; ! 1009: } ! 1010: ! 1011: kern_return_t syscall_thread_depress_abort(thread) ! 1012: mach_port_t thread; ! 1013: { ! 1014: thread_t t; ! 1015: kern_return_t result; ! 1016: ! 1017: t = port_name_to_thread(thread); ! 1018: if (t == THREAD_NULL) ! 1019: return MACH_SEND_INTERRUPTED; ! 1020: ! 1021: result = thread_depress_abort(t); ! 1022: thread_deallocate(t); ! 1023: ! 1024: return result; ! 1025: } ! 1026: ! 1027: /* ! 1028: * Device traps -- these are way experimental. ! 1029: */ ! 1030: ! 1031: extern io_return_t ds_device_write_trap(); ! 1032: extern io_return_t ds_device_writev_trap(); ! 1033: ! 1034: io_return_t ! 1035: syscall_device_write_request(mach_port_t device_name, ! 1036: mach_port_t reply_name, ! 1037: dev_mode_t mode, ! 1038: recnum_t recnum, ! 1039: vm_offset_t data, ! 1040: vm_size_t data_count) ! 1041: { ! 1042: device_t dev; ! 1043: ipc_port_t reply_port; ! 1044: io_return_t res; ! 1045: ! 1046: /* ! 1047: * First try to translate the device name. ! 1048: * ! 1049: * If this fails, return KERN_INVALID_CAPABILITY. ! 1050: * Caller knows that this most likely means that ! 1051: * device is not local to node and IPC should be used. ! 1052: * ! 1053: * If kernel doesn't do device traps, kern_invalid() ! 1054: * will be called instead of this function which will ! 1055: * return KERN_INVALID_ARGUMENT. ! 1056: */ ! 1057: dev = port_name_to_device(device_name); ! 1058: if (dev == DEVICE_NULL) ! 1059: return KERN_INVALID_CAPABILITY; ! 1060: ! 1061: /* ! 1062: * Translate reply port. ! 1063: */ ! 1064: if (reply_name == MACH_PORT_NULL) ! 1065: reply_port = IP_NULL; ! 1066: else { ! 1067: /* Homey don't play that. */ ! 1068: device_deallocate(dev); ! 1069: return KERN_INVALID_RIGHT; ! 1070: } ! 1071: ! 1072: /* note: doesn't take reply_port arg yet. */ ! 1073: res = ds_device_write_trap(dev, /*reply_port,*/ ! 1074: mode, recnum, ! 1075: data, data_count); ! 1076: ! 1077: /* ! 1078: * Give up reference from port_name_to_device. ! 1079: */ ! 1080: device_deallocate(dev); ! 1081: return res; ! 1082: } ! 1083: ! 1084: io_return_t ! 1085: syscall_device_writev_request(mach_port_t device_name, ! 1086: mach_port_t reply_name, ! 1087: dev_mode_t mode, ! 1088: recnum_t recnum, ! 1089: io_buf_vec_t *iovec, ! 1090: vm_size_t iocount) ! 1091: { ! 1092: device_t dev; ! 1093: ipc_port_t reply_port; ! 1094: io_return_t res; ! 1095: ! 1096: /* ! 1097: * First try to translate the device name. ! 1098: * ! 1099: * If this fails, return KERN_INVALID_CAPABILITY. ! 1100: * Caller knows that this most likely means that ! 1101: * device is not local to node and IPC should be used. ! 1102: * ! 1103: * If kernel doesn't do device traps, kern_invalid() ! 1104: * will be called instead of this function which will ! 1105: * return KERN_INVALID_ARGUMENT. ! 1106: */ ! 1107: dev = port_name_to_device(device_name); ! 1108: if (dev == DEVICE_NULL) ! 1109: return KERN_INVALID_CAPABILITY; ! 1110: ! 1111: /* ! 1112: * Translate reply port. ! 1113: */ ! 1114: if (reply_name == MACH_PORT_NULL) ! 1115: reply_port = IP_NULL; ! 1116: else { ! 1117: /* Homey don't play that. */ ! 1118: device_deallocate(dev); ! 1119: return KERN_INVALID_RIGHT; ! 1120: } ! 1121: ! 1122: /* note: doesn't take reply_port arg yet. */ ! 1123: res = ds_device_writev_trap(dev, /*reply_port,*/ ! 1124: mode, recnum, ! 1125: iovec, iocount); ! 1126: ! 1127: /* ! 1128: * Give up reference from port_name_to_device. ! 1129: */ ! 1130: device_deallocate(dev); ! 1131: return res; ! 1132: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.