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