|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * @OSF_COPYRIGHT@ ! 24: */ ! 25: /* ! 26: * Mach Operating System ! 27: * Copyright (c) 1991,1990,1989,1988,1987 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: */ ! 52: ! 53: /* ! 54: * File: ipc_tt.c ! 55: * Purpose: ! 56: * Task and thread related IPC functions. ! 57: */ ! 58: ! 59: #include <mach/boolean.h> ! 60: #include <mach_rt.h> ! 61: #include <mach/kern_return.h> ! 62: #include <mach/mach_param.h> ! 63: #include <mach/task_special_ports.h> ! 64: #include <mach/thread_special_ports.h> ! 65: #include <mach/thread_status.h> ! 66: #include <mach/exception_types.h> ! 67: #include <mach/mach_traps.h> ! 68: #include <mach/task_server.h> ! 69: #include <mach/thread_act_server.h> ! 70: #include <mach/mach_host_server.h> ! 71: #include <mach/vm_task_server.h> ! 72: #include <kern/ipc_tt.h> ! 73: #include <kern/thread_act.h> ! 74: #include <kern/misc_protos.h> ! 75: #include <vm/vm_pageout.h> ! 76: ! 77: /* ! 78: * Routine: ipc_task_init ! 79: * Purpose: ! 80: * Initialize a task's IPC state. ! 81: * ! 82: * If non-null, some state will be inherited from the parent. ! 83: * The parent must be appropriately initialized. ! 84: * Conditions: ! 85: * Nothing locked. ! 86: */ ! 87: ! 88: void ! 89: ipc_task_init( ! 90: task_t task, ! 91: task_t parent) ! 92: { ! 93: ipc_space_t space; ! 94: ipc_port_t kport; ! 95: kern_return_t kr; ! 96: int i; ! 97: ! 98: ! 99: kr = ipc_space_create(&ipc_table_entries[0], &space); ! 100: if (kr != KERN_SUCCESS) ! 101: panic("ipc_task_init"); ! 102: ! 103: ! 104: kport = ipc_port_alloc_kernel(); ! 105: if (kport == IP_NULL) ! 106: panic("ipc_task_init"); ! 107: ! 108: itk_lock_init(task); ! 109: task->itk_self = kport; ! 110: task->itk_sself = ipc_port_make_send(kport); ! 111: task->itk_space = space; ! 112: space->is_fast = task->kernel_loaded; ! 113: ! 114: if (parent == TASK_NULL) { ! 115: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { ! 116: task->exc_actions[i].port = IP_NULL; ! 117: }/* for */ ! 118: task->exc_actions[EXC_MACH_SYSCALL].port = ! 119: ipc_port_make_send(realhost.host_self); ! 120: task->itk_bootstrap = IP_NULL; ! 121: for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) ! 122: task->itk_registered[i] = IP_NULL; ! 123: } else { ! 124: itk_lock(parent); ! 125: assert(parent->itk_self != IP_NULL); ! 126: ! 127: /* inherit registered ports */ ! 128: ! 129: for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) ! 130: task->itk_registered[i] = ! 131: ipc_port_copy_send(parent->itk_registered[i]); ! 132: ! 133: /* inherit exception and bootstrap ports */ ! 134: ! 135: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { ! 136: task->exc_actions[i].port = ! 137: ipc_port_copy_send(parent->exc_actions[i].port); ! 138: task->exc_actions[i].flavor = ! 139: parent->exc_actions[i].flavor; ! 140: task->exc_actions[i].behavior = ! 141: parent->exc_actions[i].behavior; ! 142: }/* for */ ! 143: task->itk_bootstrap = ! 144: ipc_port_copy_send(parent->itk_bootstrap); ! 145: ! 146: itk_unlock(parent); ! 147: } ! 148: } ! 149: ! 150: /* ! 151: * Routine: ipc_task_enable ! 152: * Purpose: ! 153: * Enable a task for IPC access. ! 154: * Conditions: ! 155: * Nothing locked. ! 156: */ ! 157: ! 158: void ! 159: ipc_task_enable( ! 160: task_t task) ! 161: { ! 162: ipc_port_t kport; ! 163: ! 164: itk_lock(task); ! 165: kport = task->itk_self; ! 166: if (kport != IP_NULL) ! 167: ipc_kobject_set(kport, (ipc_kobject_t) task, IKOT_TASK); ! 168: itk_unlock(task); ! 169: } ! 170: ! 171: /* ! 172: * Routine: ipc_task_disable ! 173: * Purpose: ! 174: * Disable IPC access to a task. ! 175: * Conditions: ! 176: * Nothing locked. ! 177: */ ! 178: ! 179: void ! 180: ipc_task_disable( ! 181: task_t task) ! 182: { ! 183: ipc_port_t kport; ! 184: ! 185: itk_lock(task); ! 186: kport = task->itk_self; ! 187: if (kport != IP_NULL) ! 188: ipc_kobject_set(kport, IKO_NULL, IKOT_NONE); ! 189: itk_unlock(task); ! 190: } ! 191: ! 192: /* ! 193: * Routine: ipc_task_terminate ! 194: * Purpose: ! 195: * Clean up and destroy a task's IPC state. ! 196: * Conditions: ! 197: * Nothing locked. The task must be suspended. ! 198: * (Or the current thread must be in the task.) ! 199: */ ! 200: ! 201: void ! 202: ipc_task_terminate( ! 203: task_t task) ! 204: { ! 205: ipc_port_t kport; ! 206: int i; ! 207: ! 208: itk_lock(task); ! 209: kport = task->itk_self; ! 210: ! 211: if (kport == IP_NULL) { ! 212: /* the task is already terminated (can this happen?) */ ! 213: itk_unlock(task); ! 214: return; ! 215: } ! 216: ! 217: task->itk_self = IP_NULL; ! 218: itk_unlock(task); ! 219: ! 220: /* release the naked send rights */ ! 221: ! 222: if (IP_VALID(task->itk_sself)) ! 223: ipc_port_release_send(task->itk_sself); ! 224: ! 225: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { ! 226: if (IP_VALID(task->exc_actions[i].port)) { ! 227: ipc_port_release_send(task->exc_actions[i].port); ! 228: } ! 229: }/* for */ ! 230: if (IP_VALID(task->itk_bootstrap)) ! 231: ipc_port_release_send(task->itk_bootstrap); ! 232: ! 233: for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) ! 234: if (IP_VALID(task->itk_registered[i])) ! 235: ipc_port_release_send(task->itk_registered[i]); ! 236: ! 237: /* destroy the space, leaving just a reference for it */ ! 238: ! 239: if (!task->kernel_loaded) ! 240: ipc_space_destroy(task->itk_space); ! 241: ! 242: /* destroy the kernel port */ ! 243: ! 244: ipc_port_dealloc_kernel(kport); ! 245: } ! 246: ! 247: /* ! 248: * Routine: ipc_thread_init ! 249: * Purpose: ! 250: * Initialize a thread's IPC state. ! 251: * Conditions: ! 252: * Nothing locked. ! 253: */ ! 254: ! 255: void ! 256: ipc_thread_init( ! 257: thread_t thread) ! 258: { ! 259: ipc_kmsg_queue_init(&thread->ith_messages); ! 260: thread->ith_mig_reply = MACH_PORT_NULL; ! 261: thread->ith_rpc_reply = IP_NULL; ! 262: } ! 263: ! 264: /* ! 265: * Routine: ipc_thread_terminate ! 266: * Purpose: ! 267: * Clean up and destroy a thread's IPC state. ! 268: * Conditions: ! 269: * Nothing locked. The thread must be suspended. ! 270: * (Or be the current thread.) ! 271: */ ! 272: ! 273: void ! 274: ipc_thread_terminate( ! 275: thread_t thread) ! 276: { ! 277: assert(ipc_kmsg_queue_empty(&thread->ith_messages)); ! 278: ! 279: if (thread->ith_rpc_reply != IP_NULL) ! 280: ipc_port_dealloc_reply(thread->ith_rpc_reply); ! 281: thread->ith_rpc_reply = IP_NULL; ! 282: } ! 283: ! 284: /* ! 285: * Routine: ipc_thr_act_init ! 286: * Purpose: ! 287: * Initialize an thr_act's IPC state. ! 288: * Conditions: ! 289: * Nothing locked. ! 290: */ ! 291: ! 292: void ! 293: ipc_thr_act_init(task_t task, thread_act_t thr_act) ! 294: { ! 295: ipc_port_t kport; int i; ! 296: ! 297: kport = ipc_port_alloc_kernel(); ! 298: if (kport == IP_NULL) ! 299: panic("ipc_thr_act_init"); ! 300: ! 301: thr_act->ith_self = kport; ! 302: thr_act->ith_sself = ipc_port_make_send(kport); ! 303: ! 304: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) ! 305: thr_act->exc_actions[i].port = IP_NULL; ! 306: ! 307: thr_act->exc_actions[EXC_MACH_SYSCALL].port = ! 308: ipc_port_make_send(realhost.host_self); ! 309: ! 310: ipc_kobject_set(kport, (ipc_kobject_t) thr_act, IKOT_ACT); ! 311: } ! 312: ! 313: void ! 314: ipc_thr_act_disable(thread_act_t thr_act) ! 315: { ! 316: int i; ! 317: ipc_port_t kport; ! 318: ! 319: act_lock(thr_act); ! 320: kport = thr_act->ith_self; ! 321: ! 322: if (kport != IP_NULL) ! 323: ipc_kobject_set(kport, IKO_NULL, IKOT_NONE); ! 324: act_unlock(thr_act); ! 325: } ! 326: ! 327: void ! 328: ipc_thr_act_disable_act_locked(thread_act_t thr_act) ! 329: { ! 330: int i; ! 331: ipc_port_t kport; ! 332: ! 333: kport = thr_act->ith_self; ! 334: ! 335: if (kport != IP_NULL) ! 336: ipc_kobject_set(kport, IKO_NULL, IKOT_NONE); ! 337: } ! 338: ! 339: void ! 340: ipc_thr_act_terminate(thread_act_t thr_act) ! 341: { ! 342: ipc_port_t kport; int i; ! 343: ! 344: act_lock(thr_act); ! 345: kport = thr_act->ith_self; ! 346: ! 347: if (kport == IP_NULL) { ! 348: /* the thread is already terminated (can this happen?) */ ! 349: act_unlock(thr_act); ! 350: return; ! 351: } ! 352: ! 353: thr_act->ith_self = IP_NULL; ! 354: act_unlock(thr_act); ! 355: ! 356: /* release the naked send rights */ ! 357: ! 358: if (IP_VALID(thr_act->ith_sself)) ! 359: ipc_port_release_send(thr_act->ith_sself); ! 360: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { ! 361: if (IP_VALID(thr_act->exc_actions[i].port)) ! 362: ipc_port_release_send(thr_act->exc_actions[i].port); ! 363: } ! 364: ! 365: /* destroy the kernel port */ ! 366: ipc_port_dealloc_kernel(kport); ! 367: } ! 368: ! 369: /* ! 370: * Routine: retrieve_task_self_fast ! 371: * Purpose: ! 372: * Optimized version of retrieve_task_self, ! 373: * that only works for the current task. ! 374: * ! 375: * Return a send right (possibly null/dead) ! 376: * for the task's user-visible self port. ! 377: * Conditions: ! 378: * Nothing locked. ! 379: */ ! 380: ! 381: ipc_port_t ! 382: retrieve_task_self_fast( ! 383: register task_t task) ! 384: { ! 385: register ipc_port_t port; ! 386: ! 387: assert(task == current_task()); ! 388: ! 389: itk_lock(task); ! 390: assert(task->itk_self != IP_NULL); ! 391: ! 392: if ((port = task->itk_sself) == task->itk_self) { ! 393: /* no interposing */ ! 394: ! 395: ip_lock(port); ! 396: assert(ip_active(port)); ! 397: ip_reference(port); ! 398: port->ip_srights++; ! 399: ip_unlock(port); ! 400: } else ! 401: port = ipc_port_copy_send(port); ! 402: itk_unlock(task); ! 403: ! 404: return port; ! 405: } ! 406: ! 407: /* ! 408: * Routine: retrieve_act_self_fast ! 409: * Purpose: ! 410: * Optimized version of retrieve_thread_self, ! 411: * that only works for the current thread. ! 412: * ! 413: * Return a send right (possibly null/dead) ! 414: * for the thread's user-visible self port. ! 415: * Conditions: ! 416: * Nothing locked. ! 417: */ ! 418: ! 419: ipc_port_t ! 420: retrieve_act_self_fast(thread_act_t thr_act) ! 421: { ! 422: register ipc_port_t port; ! 423: ! 424: assert(thr_act == current_act()); ! 425: act_lock(thr_act); ! 426: assert(thr_act->ith_self != IP_NULL); ! 427: ! 428: if ((port = thr_act->ith_sself) == thr_act->ith_self) { ! 429: /* no interposing */ ! 430: ! 431: ip_lock(port); ! 432: assert(ip_active(port)); ! 433: ip_reference(port); ! 434: port->ip_srights++; ! 435: ip_unlock(port); ! 436: } else ! 437: port = ipc_port_copy_send(port); ! 438: act_unlock(thr_act); ! 439: ! 440: return port; ! 441: } ! 442: ! 443: /* ! 444: * Routine: mach_task_self [mach trap] ! 445: * Purpose: ! 446: * Give the caller send rights for his own task port. ! 447: * Conditions: ! 448: * Nothing locked. ! 449: * Returns: ! 450: * MACH_PORT_NULL if there are any resource failures ! 451: * or other errors. ! 452: */ ! 453: ! 454: mach_port_name_t ! 455: mach_task_self(void) ! 456: { ! 457: task_t task = current_task(); ! 458: ipc_port_t sright; ! 459: ! 460: sright = retrieve_task_self_fast(task); ! 461: return ipc_port_copyout_send(sright, task->itk_space); ! 462: } ! 463: ! 464: /* ! 465: * Routine: mach_thread_self [mach trap] ! 466: * Purpose: ! 467: * Give the caller send rights for his own thread port. ! 468: * Conditions: ! 469: * Nothing locked. ! 470: * Returns: ! 471: * MACH_PORT_NULL if there are any resource failures ! 472: * or other errors. ! 473: */ ! 474: ! 475: mach_port_name_t ! 476: mach_thread_self(void) ! 477: { ! 478: thread_act_t thr_act = current_act(); ! 479: task_t task = thr_act->task; ! 480: ipc_port_t sright; ! 481: ! 482: sright = retrieve_act_self_fast(thr_act); ! 483: return ipc_port_copyout_send(sright, task->itk_space); ! 484: } ! 485: ! 486: /* ! 487: * Routine: mach_reply_port [mach trap] ! 488: * Purpose: ! 489: * Allocate a port for the caller. ! 490: * Conditions: ! 491: * Nothing locked. ! 492: * Returns: ! 493: * MACH_PORT_NULL if there are any resource failures ! 494: * or other errors. ! 495: */ ! 496: ! 497: mach_port_name_t ! 498: mach_reply_port(void) ! 499: { ! 500: ipc_port_t port; ! 501: mach_port_name_t name; ! 502: kern_return_t kr; ! 503: ! 504: kr = ipc_port_alloc(current_task()->itk_space, &name, &port); ! 505: if (kr == KERN_SUCCESS) ! 506: ip_unlock(port); ! 507: else ! 508: name = MACH_PORT_NULL; ! 509: ! 510: return name; ! 511: } ! 512: ! 513: /* ! 514: * Routine: task_get_special_port [kernel call] ! 515: * Purpose: ! 516: * Clones a send right for one of the task's ! 517: * special ports. ! 518: * Conditions: ! 519: * Nothing locked. ! 520: * Returns: ! 521: * KERN_SUCCESS Extracted a send right. ! 522: * KERN_INVALID_ARGUMENT The task is null. ! 523: * KERN_FAILURE The task/space is dead. ! 524: * KERN_INVALID_ARGUMENT Invalid special port. ! 525: */ ! 526: ! 527: kern_return_t ! 528: task_get_special_port( ! 529: task_t task, ! 530: int which, ! 531: ipc_port_t *portp) ! 532: { ! 533: ipc_port_t *whichp; ! 534: ipc_port_t port; ! 535: ! 536: if (task == TASK_NULL) ! 537: return KERN_INVALID_ARGUMENT; ! 538: ! 539: switch (which) { ! 540: case TASK_KERNEL_PORT: ! 541: whichp = &task->itk_sself; ! 542: break; ! 543: ! 544: case TASK_BOOTSTRAP_PORT: ! 545: whichp = &task->itk_bootstrap; ! 546: break; ! 547: ! 548: case TASK_WIRED_LEDGER_PORT: ! 549: whichp = &task->wired_ledger_port; ! 550: break; ! 551: ! 552: case TASK_PAGED_LEDGER_PORT: ! 553: whichp = &task->paged_ledger_port; ! 554: break; ! 555: ! 556: default: ! 557: return KERN_INVALID_ARGUMENT; ! 558: } ! 559: ! 560: itk_lock(task); ! 561: if (task->itk_self == IP_NULL) { ! 562: itk_unlock(task); ! 563: return KERN_FAILURE; ! 564: } ! 565: ! 566: port = ipc_port_copy_send(*whichp); ! 567: itk_unlock(task); ! 568: ! 569: *portp = port; ! 570: return KERN_SUCCESS; ! 571: } ! 572: ! 573: /* ! 574: * Routine: task_set_special_port [kernel call] ! 575: * Purpose: ! 576: * Changes one of the task's special ports, ! 577: * setting it to the supplied send right. ! 578: * Conditions: ! 579: * Nothing locked. If successful, consumes ! 580: * the supplied send right. ! 581: * Returns: ! 582: * KERN_SUCCESS Changed the special port. ! 583: * KERN_INVALID_ARGUMENT The task is null. ! 584: * KERN_FAILURE The task/space is dead. ! 585: * KERN_INVALID_ARGUMENT Invalid special port. ! 586: */ ! 587: ! 588: kern_return_t ! 589: task_set_special_port( ! 590: task_t task, ! 591: int which, ! 592: ipc_port_t port) ! 593: { ! 594: ipc_port_t *whichp; ! 595: ipc_port_t old; ! 596: ! 597: if (task == TASK_NULL) ! 598: return KERN_INVALID_ARGUMENT; ! 599: ! 600: switch (which) { ! 601: case TASK_KERNEL_PORT: ! 602: whichp = &task->itk_sself; ! 603: break; ! 604: ! 605: case TASK_BOOTSTRAP_PORT: ! 606: whichp = &task->itk_bootstrap; ! 607: break; ! 608: ! 609: case TASK_WIRED_LEDGER_PORT: ! 610: whichp = &task->wired_ledger_port; ! 611: break; ! 612: ! 613: case TASK_PAGED_LEDGER_PORT: ! 614: whichp = &task->paged_ledger_port; ! 615: break; ! 616: ! 617: default: ! 618: return KERN_INVALID_ARGUMENT; ! 619: }/* switch */ ! 620: ! 621: itk_lock(task); ! 622: if (task->itk_self == IP_NULL) { ! 623: itk_unlock(task); ! 624: return KERN_FAILURE; ! 625: } ! 626: ! 627: old = *whichp; ! 628: *whichp = port; ! 629: itk_unlock(task); ! 630: ! 631: if (IP_VALID(old)) ! 632: ipc_port_release_send(old); ! 633: return KERN_SUCCESS; ! 634: } ! 635: ! 636: ! 637: /* ! 638: * Routine: mach_ports_register [kernel call] ! 639: * Purpose: ! 640: * Stash a handful of port send rights in the task. ! 641: * Child tasks will inherit these rights, but they ! 642: * must use mach_ports_lookup to acquire them. ! 643: * ! 644: * The rights are supplied in a (wired) kalloc'd segment. ! 645: * Rights which aren't supplied are assumed to be null. ! 646: * Conditions: ! 647: * Nothing locked. If successful, consumes ! 648: * the supplied rights and memory. ! 649: * Returns: ! 650: * KERN_SUCCESS Stashed the port rights. ! 651: * KERN_INVALID_ARGUMENT The task is null. ! 652: * KERN_INVALID_ARGUMENT The task is dead. ! 653: * KERN_INVALID_ARGUMENT Too many port rights supplied. ! 654: */ ! 655: ! 656: kern_return_t ! 657: mach_ports_register( ! 658: task_t task, ! 659: mach_port_array_t memory, ! 660: mach_msg_type_number_t portsCnt) ! 661: { ! 662: ipc_port_t ports[TASK_PORT_REGISTER_MAX]; ! 663: int i; ! 664: ! 665: if ((task == TASK_NULL) || ! 666: (portsCnt > TASK_PORT_REGISTER_MAX)) ! 667: return KERN_INVALID_ARGUMENT; ! 668: ! 669: /* ! 670: * Pad the port rights with nulls. ! 671: */ ! 672: ! 673: for (i = 0; i < portsCnt; i++) ! 674: ports[i] = memory[i]; ! 675: for (; i < TASK_PORT_REGISTER_MAX; i++) ! 676: ports[i] = IP_NULL; ! 677: ! 678: itk_lock(task); ! 679: if (task->itk_self == IP_NULL) { ! 680: itk_unlock(task); ! 681: return KERN_INVALID_ARGUMENT; ! 682: } ! 683: ! 684: /* ! 685: * Replace the old send rights with the new. ! 686: * Release the old rights after unlocking. ! 687: */ ! 688: ! 689: for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) { ! 690: ipc_port_t old; ! 691: ! 692: old = task->itk_registered[i]; ! 693: task->itk_registered[i] = ports[i]; ! 694: ports[i] = old; ! 695: } ! 696: ! 697: itk_unlock(task); ! 698: ! 699: for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) ! 700: if (IP_VALID(ports[i])) ! 701: ipc_port_release_send(ports[i]); ! 702: ! 703: /* ! 704: * Now that the operation is known to be successful, ! 705: * we can free the memory. ! 706: */ ! 707: ! 708: if (portsCnt != 0) ! 709: kfree((vm_offset_t) memory, ! 710: (vm_size_t) (portsCnt * sizeof(mach_port_t))); ! 711: ! 712: return KERN_SUCCESS; ! 713: } ! 714: ! 715: /* ! 716: * Routine: mach_ports_lookup [kernel call] ! 717: * Purpose: ! 718: * Retrieves (clones) the stashed port send rights. ! 719: * Conditions: ! 720: * Nothing locked. If successful, the caller gets ! 721: * rights and memory. ! 722: * Returns: ! 723: * KERN_SUCCESS Retrieved the send rights. ! 724: * KERN_INVALID_ARGUMENT The task is null. ! 725: * KERN_INVALID_ARGUMENT The task is dead. ! 726: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. ! 727: */ ! 728: ! 729: kern_return_t ! 730: mach_ports_lookup( ! 731: task_t task, ! 732: mach_port_array_t *portsp, ! 733: mach_msg_type_number_t *portsCnt) ! 734: { ! 735: vm_offset_t memory; ! 736: vm_size_t size; ! 737: ipc_port_t *ports; ! 738: int i; ! 739: ! 740: kern_return_t kr; ! 741: boolean_t rt = FALSE; /* ### This boolean is FALSE, because there ! 742: * currently exists no mechanism to determine ! 743: * whether or not the reply port is an RT port ! 744: */ ! 745: ! 746: if (task == TASK_NULL) ! 747: return KERN_INVALID_ARGUMENT; ! 748: ! 749: size = (vm_size_t) (TASK_PORT_REGISTER_MAX * sizeof(ipc_port_t)); ! 750: ! 751: memory = KALLOC(size, rt); ! 752: if (memory == 0) ! 753: return KERN_RESOURCE_SHORTAGE; ! 754: ! 755: itk_lock(task); ! 756: if (task->itk_self == IP_NULL) { ! 757: itk_unlock(task); ! 758: ! 759: KFREE(memory, size, rt); ! 760: return KERN_INVALID_ARGUMENT; ! 761: } ! 762: ! 763: ports = (ipc_port_t *) memory; ! 764: ! 765: /* ! 766: * Clone port rights. Because kalloc'd memory ! 767: * is wired, we won't fault while holding the task lock. ! 768: */ ! 769: ! 770: for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) ! 771: ports[i] = ipc_port_copy_send(task->itk_registered[i]); ! 772: ! 773: itk_unlock(task); ! 774: ! 775: *portsp = (mach_port_array_t) ports; ! 776: *portsCnt = TASK_PORT_REGISTER_MAX; ! 777: return KERN_SUCCESS; ! 778: } ! 779: ! 780: /* ! 781: * Routine: convert_port_to_locked_task ! 782: * Purpose: ! 783: * Internal helper routine to convert from a port to a locked ! 784: * task. Used by several routines that try to convert from a ! 785: * task port to a reference on some task related object. ! 786: * Conditions: ! 787: * Nothing locked, blocking OK. ! 788: */ ! 789: task_t ! 790: convert_port_to_locked_task(ipc_port_t port) ! 791: { ! 792: while (IP_VALID(port)) { ! 793: task_t task; ! 794: ! 795: ip_lock(port); ! 796: if (!ip_active(port) || (ip_kotype(port) != IKOT_TASK)) { ! 797: ip_unlock(port); ! 798: return TASK_NULL; ! 799: } ! 800: task = (task_t) port->ip_kobject; ! 801: assert(task != TASK_NULL); ! 802: ! 803: /* ! 804: * Normal lock ordering puts task_lock() before ip_lock(). ! 805: * Attempt out-of-order locking here. ! 806: */ ! 807: if (task_lock_try(task)) { ! 808: ip_unlock(port); ! 809: return(task); ! 810: } ! 811: ! 812: ip_unlock(port); ! 813: mutex_pause(); ! 814: } ! 815: return TASK_NULL; ! 816: } ! 817: ! 818: /* ! 819: * Routine: convert_port_to_task ! 820: * Purpose: ! 821: * Convert from a port to a task. ! 822: * Doesn't consume the port ref; produces a task ref, ! 823: * which may be null. ! 824: * Conditions: ! 825: * Nothing locked. ! 826: */ ! 827: task_t ! 828: convert_port_to_task( ! 829: ipc_port_t port) ! 830: { ! 831: task_t task; ! 832: ! 833: task = convert_port_to_locked_task(port); ! 834: if (task) { ! 835: task->ref_count++; ! 836: task_unlock(task); ! 837: } ! 838: return task; ! 839: } ! 840: ! 841: /* ! 842: * Routine: convert_port_to_space ! 843: * Purpose: ! 844: * Convert from a port to a space. ! 845: * Doesn't consume the port ref; produces a space ref, ! 846: * which may be null. ! 847: * Conditions: ! 848: * Nothing locked. ! 849: */ ! 850: ipc_space_t ! 851: convert_port_to_space( ! 852: ipc_port_t port) ! 853: { ! 854: ipc_space_t space; ! 855: task_t task; ! 856: ! 857: task = convert_port_to_locked_task(port); ! 858: ! 859: if (task == TASK_NULL) ! 860: return IPC_SPACE_NULL; ! 861: ! 862: if (!task->active) { ! 863: task_unlock(task); ! 864: return IPC_SPACE_NULL; ! 865: } ! 866: ! 867: space = task->itk_space; ! 868: is_reference(space); ! 869: task_unlock(task); ! 870: return (space); ! 871: } ! 872: ! 873: upl_t ! 874: convert_port_to_upl( ! 875: ipc_port_t port) ! 876: { ! 877: upl_t upl; ! 878: ! 879: ip_lock(port); ! 880: if (!ip_active(port) || (ip_kotype(port) != IKOT_UPL)) { ! 881: ip_unlock(port); ! 882: return (upl_t)NULL; ! 883: } ! 884: upl = (upl_t) port->ip_kobject; ! 885: ip_unlock(port); ! 886: upl_lock(upl); ! 887: upl->ref_count+=1; ! 888: upl_unlock(upl); ! 889: return upl; ! 890: } ! 891: ! 892: /* ! 893: * Routine: convert_port_entry_to_map ! 894: * Purpose: ! 895: * Convert from a port specifying an entry or a task ! 896: * to a map. Doesn't consume the port ref; produces a map ref, ! 897: * which may be null. Unlike convert_port_to_map, the ! 898: * port may be task or a named entry backed. ! 899: * Conditions: ! 900: * Nothing locked. ! 901: */ ! 902: ! 903: ! 904: vm_map_t ! 905: convert_port_entry_to_map( ! 906: ipc_port_t port) ! 907: { ! 908: task_t task; ! 909: vm_map_t map; ! 910: vm_named_entry_t named_entry; ! 911: ! 912: if(IP_VALID(port) && (ip_kotype(port) == IKOT_NAMED_ENTRY)) { ! 913: while(TRUE) { ! 914: ip_lock(port); ! 915: if(ip_active(port) && (ip_kotype(port) ! 916: == IKOT_NAMED_ENTRY)) { ! 917: named_entry = ! 918: (vm_named_entry_t)port->ip_kobject; ! 919: if (!(mutex_try(&(named_entry)->Lock))) { ! 920: ip_unlock(port); ! 921: mutex_pause(); ! 922: continue; ! 923: } ! 924: named_entry->ref_count++; ! 925: mutex_unlock(&(named_entry)->Lock); ! 926: ip_unlock(port); ! 927: if ((named_entry->is_sub_map) && ! 928: (named_entry->protection ! 929: & VM_PROT_WRITE)) { ! 930: map = named_entry->backing.map; ! 931: } else { ! 932: mach_destroy_memory_entry(port); ! 933: return VM_MAP_NULL; ! 934: } ! 935: vm_map_reference_swap(map); ! 936: mach_destroy_memory_entry(port); ! 937: break; ! 938: } ! 939: else ! 940: return VM_MAP_NULL; ! 941: } ! 942: } else { ! 943: task_t task; ! 944: ! 945: task = convert_port_to_locked_task(port); ! 946: ! 947: if (task == TASK_NULL) ! 948: return VM_MAP_NULL; ! 949: ! 950: if (!task->active) { ! 951: task_unlock(task); ! 952: return VM_MAP_NULL; ! 953: } ! 954: ! 955: map = task->map; ! 956: vm_map_reference_swap(map); ! 957: task_unlock(task); ! 958: } ! 959: ! 960: return map; ! 961: } ! 962: ! 963: /* ! 964: * Routine: convert_port_entry_to_object ! 965: * Purpose: ! 966: * Convert from a port specifying a named entry to an ! 967: * object. Doesn't consume the port ref; produces a map ref, ! 968: * which may be null. ! 969: * Conditions: ! 970: * Nothing locked. ! 971: */ ! 972: ! 973: ! 974: vm_object_t ! 975: convert_port_entry_to_object( ! 976: ipc_port_t port) ! 977: { ! 978: vm_object_t object; ! 979: vm_named_entry_t named_entry; ! 980: ! 981: if(IP_VALID(port) && (ip_kotype(port) == IKOT_NAMED_ENTRY)) { ! 982: while(TRUE) { ! 983: ip_lock(port); ! 984: if(ip_active(port) && (ip_kotype(port) ! 985: == IKOT_NAMED_ENTRY)) { ! 986: named_entry = ! 987: (vm_named_entry_t)port->ip_kobject; ! 988: if (!(mutex_try(&(named_entry)->Lock))) { ! 989: ip_unlock(port); ! 990: mutex_pause(); ! 991: continue; ! 992: } ! 993: named_entry->ref_count++; ! 994: mutex_unlock(&(named_entry)->Lock); ! 995: ip_unlock(port); ! 996: if ((!named_entry->is_sub_map) && ! 997: (named_entry->protection ! 998: & VM_PROT_WRITE)) { ! 999: object = named_entry->object; ! 1000: } else { ! 1001: mach_destroy_memory_entry(port); ! 1002: return (vm_object_t)NULL; ! 1003: } ! 1004: vm_object_reference(named_entry->object); ! 1005: mach_destroy_memory_entry(port); ! 1006: break; ! 1007: } ! 1008: else ! 1009: return (vm_object_t)NULL; ! 1010: } ! 1011: } else { ! 1012: return (vm_object_t)NULL; ! 1013: } ! 1014: ! 1015: return object; ! 1016: } ! 1017: ! 1018: /* ! 1019: * Routine: convert_port_to_map ! 1020: * Purpose: ! 1021: * Convert from a port to a map. ! 1022: * Doesn't consume the port ref; produces a map ref, ! 1023: * which may be null. ! 1024: * Conditions: ! 1025: * Nothing locked. ! 1026: */ ! 1027: ! 1028: vm_map_t ! 1029: convert_port_to_map( ! 1030: ipc_port_t port) ! 1031: { ! 1032: task_t task; ! 1033: vm_map_t map; ! 1034: ! 1035: task = convert_port_to_locked_task(port); ! 1036: ! 1037: if (task == TASK_NULL) ! 1038: return VM_MAP_NULL; ! 1039: ! 1040: if (!task->active) { ! 1041: task_unlock(task); ! 1042: return VM_MAP_NULL; ! 1043: } ! 1044: ! 1045: map = task->map; ! 1046: vm_map_reference_swap(map); ! 1047: task_unlock(task); ! 1048: return map; ! 1049: } ! 1050: ! 1051: ! 1052: /* ! 1053: * Routine: convert_port_to_act ! 1054: * Purpose: ! 1055: * Convert from a port to a thr_act. ! 1056: * Doesn't consume the port ref; produces an thr_act ref, ! 1057: * which may be null. ! 1058: * Conditions: ! 1059: * Nothing locked. ! 1060: */ ! 1061: ! 1062: thread_act_t ! 1063: convert_port_to_act( ipc_port_t port ) ! 1064: { ! 1065: boolean_t r; ! 1066: thread_act_t thr_act = 0; ! 1067: ! 1068: r = FALSE; ! 1069: while (!r && IP_VALID(port)) { ! 1070: ip_lock(port); ! 1071: r = ref_act_port_locked(port, &thr_act); ! 1072: /* port unlocked */ ! 1073: } ! 1074: return (thr_act); ! 1075: } ! 1076: ! 1077: boolean_t ! 1078: ref_act_port_locked( ipc_port_t port, thread_act_t *pthr_act ) ! 1079: { ! 1080: thread_act_t thr_act; ! 1081: ! 1082: thr_act = 0; ! 1083: if (ip_active(port) && ! 1084: (ip_kotype(port) == IKOT_ACT)) { ! 1085: thr_act = (thread_act_t) port->ip_kobject; ! 1086: assert(thr_act != THR_ACT_NULL); ! 1087: ! 1088: /* ! 1089: * Normal lock ordering is act_lock(), then ip_lock(). ! 1090: * Allow out-of-order locking here, using ! 1091: * act_reference_act_locked() to accomodate it. ! 1092: */ ! 1093: if (!act_lock_try(thr_act)) { ! 1094: ip_unlock(port); ! 1095: mutex_pause(); ! 1096: return (FALSE); ! 1097: } ! 1098: act_locked_act_reference(thr_act); ! 1099: act_unlock(thr_act); ! 1100: } ! 1101: *pthr_act = thr_act; ! 1102: ip_unlock(port); ! 1103: return (TRUE); ! 1104: } ! 1105: ! 1106: /* ! 1107: * Routine: convert_task_to_port ! 1108: * Purpose: ! 1109: * Convert from a task to a port. ! 1110: * Consumes a task ref; produces a naked send right ! 1111: * which may be invalid. ! 1112: * Conditions: ! 1113: * Nothing locked. ! 1114: */ ! 1115: ! 1116: ipc_port_t ! 1117: convert_task_to_port( ! 1118: task_t task) ! 1119: { ! 1120: ipc_port_t port; ! 1121: ! 1122: itk_lock(task); ! 1123: if (task->itk_self != IP_NULL) ! 1124: #if NORMA_TASK ! 1125: if (task->map == VM_MAP_NULL) ! 1126: /* norma placeholder task */ ! 1127: port = ipc_port_copy_send(task->itk_self); ! 1128: else ! 1129: #endif /* NORMA_TASK */ ! 1130: port = ipc_port_make_send(task->itk_self); ! 1131: else ! 1132: port = IP_NULL; ! 1133: itk_unlock(task); ! 1134: ! 1135: task_deallocate(task); ! 1136: return port; ! 1137: } ! 1138: ! 1139: /* ! 1140: * Routine: convert_act_to_port ! 1141: * Purpose: ! 1142: * Convert from a thr_act to a port. ! 1143: * Consumes an thr_act ref; produces a naked send right ! 1144: * which may be invalid. ! 1145: * Conditions: ! 1146: * Nothing locked. ! 1147: */ ! 1148: ! 1149: ipc_port_t ! 1150: convert_act_to_port(thr_act) ! 1151: thread_act_t thr_act; ! 1152: { ! 1153: ipc_port_t port; ! 1154: ! 1155: act_lock(thr_act); ! 1156: if (thr_act->ith_self != IP_NULL) ! 1157: port = ipc_port_make_send(thr_act->ith_self); ! 1158: else ! 1159: port = IP_NULL; ! 1160: act_unlock(thr_act); ! 1161: ! 1162: act_deallocate(thr_act); ! 1163: return port; ! 1164: } ! 1165: ! 1166: /* ! 1167: * Routine: space_deallocate ! 1168: * Purpose: ! 1169: * Deallocate a space ref produced by convert_port_to_space. ! 1170: * Conditions: ! 1171: * Nothing locked. ! 1172: */ ! 1173: ! 1174: void ! 1175: space_deallocate( ! 1176: ipc_space_t space) ! 1177: { ! 1178: if (space != IS_NULL) ! 1179: is_release(space); ! 1180: } ! 1181: ! 1182: /* ! 1183: * Routine: thread/task_set_exception_ports [kernel call] ! 1184: * Purpose: ! 1185: * Sets the thread/task exception port, flavor and ! 1186: * behavior for the exception types specified by the mask. ! 1187: * There will be one send right per exception per valid ! 1188: * port. ! 1189: * Conditions: ! 1190: * Nothing locked. If successful, consumes ! 1191: * the supplied send right. ! 1192: * Returns: ! 1193: * KERN_SUCCESS Changed the special port. ! 1194: * KERN_INVALID_ARGUMENT The thread is null, ! 1195: * Illegal mask bit set. ! 1196: * Illegal exception behavior ! 1197: * KERN_FAILURE The thread is dead. ! 1198: */ ! 1199: ! 1200: kern_return_t ! 1201: thread_set_exception_ports( ! 1202: thread_act_t thr_act, ! 1203: exception_mask_t exception_mask, ! 1204: ipc_port_t new_port, ! 1205: exception_behavior_t new_behavior, ! 1206: thread_state_flavor_t new_flavor) ! 1207: { ! 1208: register int i; ! 1209: ipc_port_t old_port[EXC_TYPES_COUNT]; ! 1210: ! 1211: if (!thr_act) ! 1212: return KERN_INVALID_ARGUMENT; ! 1213: ! 1214: if (exception_mask & ~EXC_MASK_ALL) ! 1215: return KERN_INVALID_ARGUMENT; ! 1216: ! 1217: if (IP_VALID(new_port)) { ! 1218: switch (new_behavior) { ! 1219: case EXCEPTION_DEFAULT: ! 1220: case EXCEPTION_STATE: ! 1221: case EXCEPTION_STATE_IDENTITY: ! 1222: break; ! 1223: default: ! 1224: return KERN_INVALID_ARGUMENT; ! 1225: } ! 1226: } ! 1227: /* Cannot easily check "flavor", but that just means that the flavor ! 1228: * in the generated exception message might be garbage. GIGO */ ! 1229: ! 1230: act_lock(thr_act); ! 1231: if (!thr_act->active) { ! 1232: act_unlock(thr_act); ! 1233: return KERN_FAILURE; ! 1234: } ! 1235: ! 1236: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { ! 1237: if (exception_mask & (1 << i)) { ! 1238: old_port[i] = thr_act->exc_actions[i].port; ! 1239: thr_act->exc_actions[i].port = ! 1240: ipc_port_copy_send(new_port); ! 1241: thr_act->exc_actions[i].behavior = new_behavior; ! 1242: thr_act->exc_actions[i].flavor = new_flavor; ! 1243: } else ! 1244: old_port[i] = IP_NULL; ! 1245: }/* for */ ! 1246: /* ! 1247: * Consume send rights without any lock held. ! 1248: */ ! 1249: act_unlock(thr_act); ! 1250: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) ! 1251: if (IP_VALID(old_port[i])) ! 1252: ipc_port_release_send(old_port[i]); ! 1253: if (IP_VALID(new_port)) /* consume send right */ ! 1254: ipc_port_release_send(new_port); ! 1255: ! 1256: return KERN_SUCCESS; ! 1257: }/* thread_set_exception_port */ ! 1258: ! 1259: kern_return_t ! 1260: task_set_exception_ports( ! 1261: task_t task, ! 1262: exception_mask_t exception_mask, ! 1263: ipc_port_t new_port, ! 1264: exception_behavior_t new_behavior, ! 1265: thread_state_flavor_t new_flavor) ! 1266: { ! 1267: register int i; ! 1268: ipc_port_t old_port[EXC_TYPES_COUNT]; ! 1269: ! 1270: if (task == TASK_NULL) { ! 1271: return KERN_INVALID_ARGUMENT; ! 1272: } ! 1273: ! 1274: if (exception_mask & ~EXC_MASK_ALL) { ! 1275: return KERN_INVALID_ARGUMENT; ! 1276: } ! 1277: ! 1278: if (IP_VALID(new_port)) { ! 1279: switch (new_behavior) { ! 1280: case EXCEPTION_DEFAULT: ! 1281: case EXCEPTION_STATE: ! 1282: case EXCEPTION_STATE_IDENTITY: ! 1283: break; ! 1284: default: ! 1285: return KERN_INVALID_ARGUMENT; ! 1286: } ! 1287: } ! 1288: /* Cannot easily check "new_flavor", but that just means that ! 1289: * the flavor in the generated exception message might be garbage: ! 1290: * GIGO */ ! 1291: ! 1292: itk_lock(task); ! 1293: if (task->itk_self == IP_NULL) { ! 1294: itk_unlock(task); ! 1295: return KERN_FAILURE; ! 1296: } ! 1297: ! 1298: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { ! 1299: if (exception_mask & (1 << i)) { ! 1300: old_port[i] = task->exc_actions[i].port; ! 1301: task->exc_actions[i].port = ! 1302: ipc_port_copy_send(new_port); ! 1303: task->exc_actions[i].behavior = new_behavior; ! 1304: task->exc_actions[i].flavor = new_flavor; ! 1305: } else ! 1306: old_port[i] = IP_NULL; ! 1307: }/* for */ ! 1308: ! 1309: /* ! 1310: * Consume send rights without any lock held. ! 1311: */ ! 1312: itk_unlock(task); ! 1313: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) ! 1314: if (IP_VALID(old_port[i])) ! 1315: ipc_port_release_send(old_port[i]); ! 1316: if (IP_VALID(new_port)) /* consume send right */ ! 1317: ipc_port_release_send(new_port); ! 1318: ! 1319: return KERN_SUCCESS; ! 1320: }/* task_set_exception_port */ ! 1321: ! 1322: /* ! 1323: * Routine: thread/task_swap_exception_ports [kernel call] ! 1324: * Purpose: ! 1325: * Sets the thread/task exception port, flavor and ! 1326: * behavior for the exception types specified by the ! 1327: * mask. ! 1328: * ! 1329: * The old ports, behavior and flavors are returned ! 1330: * Count specifies the array sizes on input and ! 1331: * the number of returned ports etc. on output. The ! 1332: * arrays must be large enough to hold all the returned ! 1333: * data, MIG returnes an error otherwise. The masks ! 1334: * array specifies the corresponding exception type(s). ! 1335: * ! 1336: * Conditions: ! 1337: * Nothing locked. If successful, consumes ! 1338: * the supplied send right. ! 1339: * ! 1340: * Returns upto [in} CountCnt elements. ! 1341: * Returns: ! 1342: * KERN_SUCCESS Changed the special port. ! 1343: * KERN_INVALID_ARGUMENT The thread is null, ! 1344: * Illegal mask bit set. ! 1345: * Illegal exception behavior ! 1346: * KERN_FAILURE The thread is dead. ! 1347: */ ! 1348: ! 1349: kern_return_t ! 1350: thread_swap_exception_ports( ! 1351: thread_act_t thr_act, ! 1352: exception_mask_t exception_mask, ! 1353: ipc_port_t new_port, ! 1354: exception_behavior_t new_behavior, ! 1355: thread_state_flavor_t new_flavor, ! 1356: exception_mask_array_t masks, ! 1357: mach_msg_type_number_t * CountCnt, ! 1358: exception_port_array_t ports, ! 1359: exception_behavior_array_t behaviors, ! 1360: thread_state_flavor_array_t flavors ) ! 1361: { ! 1362: register int i, ! 1363: j, ! 1364: count; ! 1365: ipc_port_t old_port[EXC_TYPES_COUNT]; ! 1366: ! 1367: if (!thr_act) ! 1368: return KERN_INVALID_ARGUMENT; ! 1369: ! 1370: if (exception_mask & ~EXC_MASK_ALL) { ! 1371: return KERN_INVALID_ARGUMENT; ! 1372: } ! 1373: ! 1374: if (IP_VALID(new_port)) { ! 1375: switch (new_behavior) { ! 1376: case EXCEPTION_DEFAULT: ! 1377: case EXCEPTION_STATE: ! 1378: case EXCEPTION_STATE_IDENTITY: ! 1379: break; ! 1380: default: ! 1381: return KERN_INVALID_ARGUMENT; ! 1382: } ! 1383: } ! 1384: /* Cannot easily check "new_flavor", but that just means that ! 1385: * the flavor in the generated exception message might be garbage: ! 1386: * GIGO */ ! 1387: ! 1388: act_lock(thr_act); ! 1389: if (!thr_act->active) { ! 1390: act_unlock(thr_act); ! 1391: return KERN_FAILURE; ! 1392: } ! 1393: ! 1394: count = 0; ! 1395: ! 1396: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { ! 1397: if (exception_mask & (1 << i)) { ! 1398: for (j = 0; j < count; j++) { ! 1399: /* ! 1400: * search for an identical entry, if found ! 1401: * set corresponding mask for this exception. ! 1402: */ ! 1403: if (thr_act->exc_actions[i].port == ports[j] && ! 1404: thr_act->exc_actions[i].behavior ==behaviors[j] ! 1405: && thr_act->exc_actions[i].flavor ==flavors[j]) ! 1406: { ! 1407: masks[j] |= (1 << i); ! 1408: break; ! 1409: } ! 1410: }/* for */ ! 1411: if (j == count) { ! 1412: masks[j] = (1 << i); ! 1413: ports[j] = ! 1414: ipc_port_copy_send(thr_act->exc_actions[i].port); ! 1415: ! 1416: behaviors[j] = thr_act->exc_actions[i].behavior; ! 1417: flavors[j] = thr_act->exc_actions[i].flavor; ! 1418: count++; ! 1419: } ! 1420: ! 1421: old_port[i] = thr_act->exc_actions[i].port; ! 1422: thr_act->exc_actions[i].port = ! 1423: ipc_port_copy_send(new_port); ! 1424: thr_act->exc_actions[i].behavior = new_behavior; ! 1425: thr_act->exc_actions[i].flavor = new_flavor; ! 1426: if (count > *CountCnt) { ! 1427: break; ! 1428: } ! 1429: } else ! 1430: old_port[i] = IP_NULL; ! 1431: }/* for */ ! 1432: ! 1433: /* ! 1434: * Consume send rights without any lock held. ! 1435: */ ! 1436: act_unlock(thr_act); ! 1437: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) ! 1438: if (IP_VALID(old_port[i])) ! 1439: ipc_port_release_send(old_port[i]); ! 1440: if (IP_VALID(new_port)) /* consume send right */ ! 1441: ipc_port_release_send(new_port); ! 1442: *CountCnt = count; ! 1443: return KERN_SUCCESS; ! 1444: }/* thread_swap_exception_ports */ ! 1445: ! 1446: kern_return_t ! 1447: task_swap_exception_ports( ! 1448: task_t task, ! 1449: exception_mask_t exception_mask, ! 1450: ipc_port_t new_port, ! 1451: exception_behavior_t new_behavior, ! 1452: thread_state_flavor_t new_flavor, ! 1453: exception_mask_array_t masks, ! 1454: mach_msg_type_number_t * CountCnt, ! 1455: exception_port_array_t ports, ! 1456: exception_behavior_array_t behaviors, ! 1457: thread_state_flavor_array_t flavors ) ! 1458: { ! 1459: register int i, ! 1460: j, ! 1461: count; ! 1462: ipc_port_t old_port[EXC_TYPES_COUNT]; ! 1463: ! 1464: if (task == TASK_NULL) ! 1465: return KERN_INVALID_ARGUMENT; ! 1466: ! 1467: if (exception_mask & ~EXC_MASK_ALL) { ! 1468: return KERN_INVALID_ARGUMENT; ! 1469: } ! 1470: ! 1471: if (IP_VALID(new_port)) { ! 1472: switch (new_behavior) { ! 1473: case EXCEPTION_DEFAULT: ! 1474: case EXCEPTION_STATE: ! 1475: case EXCEPTION_STATE_IDENTITY: ! 1476: break; ! 1477: default: ! 1478: return KERN_INVALID_ARGUMENT; ! 1479: } ! 1480: } ! 1481: /* Cannot easily check "new_flavor", but that just means that ! 1482: * the flavor in the generated exception message might be garbage: ! 1483: * GIGO */ ! 1484: ! 1485: itk_lock(task); ! 1486: if (task->itk_self == IP_NULL) { ! 1487: itk_unlock(task); ! 1488: return KERN_FAILURE; ! 1489: } ! 1490: ! 1491: count = 0; ! 1492: ! 1493: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { ! 1494: if (exception_mask & (1 << i)) { ! 1495: for (j = 0; j < count; j++) { ! 1496: /* ! 1497: * search for an identical entry, if found ! 1498: * set corresponding mask for this exception. ! 1499: */ ! 1500: if (task->exc_actions[i].port == ports[j] && ! 1501: task->exc_actions[i].behavior == behaviors[j] ! 1502: && task->exc_actions[i].flavor == flavors[j]) ! 1503: { ! 1504: masks[j] |= (1 << i); ! 1505: break; ! 1506: } ! 1507: }/* for */ ! 1508: if (j == count) { ! 1509: masks[j] = (1 << i); ! 1510: ports[j] = ! 1511: ipc_port_copy_send(task->exc_actions[i].port); ! 1512: behaviors[j] = task->exc_actions[i].behavior; ! 1513: flavors[j] = task->exc_actions[i].flavor; ! 1514: count++; ! 1515: } ! 1516: old_port[i] = task->exc_actions[i].port; ! 1517: task->exc_actions[i].port = ! 1518: ipc_port_copy_send(new_port); ! 1519: task->exc_actions[i].behavior = new_behavior; ! 1520: task->exc_actions[i].flavor = new_flavor; ! 1521: if (count > *CountCnt) { ! 1522: break; ! 1523: } ! 1524: } else ! 1525: old_port[i] = IP_NULL; ! 1526: }/* for */ ! 1527: ! 1528: ! 1529: /* ! 1530: * Consume send rights without any lock held. ! 1531: */ ! 1532: itk_unlock(task); ! 1533: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) ! 1534: if (IP_VALID(old_port[i])) ! 1535: ipc_port_release_send(old_port[i]); ! 1536: if (IP_VALID(new_port)) /* consume send right */ ! 1537: ipc_port_release_send(new_port); ! 1538: *CountCnt = count; ! 1539: ! 1540: return KERN_SUCCESS; ! 1541: }/* task_swap_exception_ports */ ! 1542: ! 1543: /* ! 1544: * Routine: thread/task_get_exception_ports [kernel call] ! 1545: * Purpose: ! 1546: * Clones a send right for each of the thread/task's exception ! 1547: * ports specified in the mask and returns the behaviour ! 1548: * and flavor of said port. ! 1549: * ! 1550: * Returns upto [in} CountCnt elements. ! 1551: * ! 1552: * Conditions: ! 1553: * Nothing locked. ! 1554: * Returns: ! 1555: * KERN_SUCCESS Extracted a send right. ! 1556: * KERN_INVALID_ARGUMENT The thread is null, ! 1557: * Invalid special port, ! 1558: * Illegal mask bit set. ! 1559: * KERN_FAILURE The thread is dead. ! 1560: */ ! 1561: ! 1562: kern_return_t ! 1563: thread_get_exception_ports( ! 1564: thread_act_t thr_act, ! 1565: exception_mask_t exception_mask, ! 1566: exception_mask_array_t masks, ! 1567: mach_msg_type_number_t * CountCnt, ! 1568: exception_port_array_t ports, ! 1569: exception_behavior_array_t behaviors, ! 1570: thread_state_flavor_array_t flavors ) ! 1571: { ! 1572: register int i, ! 1573: j, ! 1574: count; ! 1575: ! 1576: if (!thr_act) ! 1577: return KERN_INVALID_ARGUMENT; ! 1578: ! 1579: if (exception_mask & ~EXC_MASK_ALL) { ! 1580: return KERN_INVALID_ARGUMENT; ! 1581: } ! 1582: ! 1583: act_lock(thr_act); ! 1584: if (!thr_act->active) { ! 1585: act_unlock(thr_act); ! 1586: return KERN_FAILURE; ! 1587: } ! 1588: ! 1589: count = 0; ! 1590: ! 1591: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { ! 1592: if (exception_mask & (1 << i)) { ! 1593: for (j = 0; j < count; j++) { ! 1594: /* ! 1595: * search for an identical entry, if found ! 1596: * set corresponding mask for this exception. ! 1597: */ ! 1598: if (thr_act->exc_actions[i].port == ports[j] && ! 1599: thr_act->exc_actions[i].behavior ==behaviors[j] ! 1600: && thr_act->exc_actions[i].flavor == flavors[j]) ! 1601: { ! 1602: masks[j] |= (1 << i); ! 1603: break; ! 1604: } ! 1605: }/* for */ ! 1606: if (j == count) { ! 1607: masks[j] = (1 << i); ! 1608: ports[j] = ! 1609: ipc_port_copy_send(thr_act->exc_actions[i].port); ! 1610: behaviors[j] = thr_act->exc_actions[i].behavior; ! 1611: flavors[j] = thr_act->exc_actions[i].flavor; ! 1612: count++; ! 1613: if (count >= *CountCnt) { ! 1614: break; ! 1615: } ! 1616: } ! 1617: } ! 1618: }/* for */ ! 1619: ! 1620: act_unlock(thr_act); ! 1621: ! 1622: *CountCnt = count; ! 1623: return KERN_SUCCESS; ! 1624: }/* thread_get_exception_ports */ ! 1625: ! 1626: kern_return_t ! 1627: task_get_exception_ports( ! 1628: task_t task, ! 1629: exception_mask_t exception_mask, ! 1630: exception_mask_array_t masks, ! 1631: mach_msg_type_number_t * CountCnt, ! 1632: exception_port_array_t ports, ! 1633: exception_behavior_array_t behaviors, ! 1634: thread_state_flavor_array_t flavors ) ! 1635: { ! 1636: register int i, ! 1637: j, ! 1638: count; ! 1639: ! 1640: if (task == TASK_NULL) ! 1641: return KERN_INVALID_ARGUMENT; ! 1642: ! 1643: if (exception_mask & ~EXC_MASK_ALL) { ! 1644: return KERN_INVALID_ARGUMENT; ! 1645: } ! 1646: ! 1647: itk_lock(task); ! 1648: if (task->itk_self == IP_NULL) { ! 1649: itk_unlock(task); ! 1650: return KERN_FAILURE; ! 1651: } ! 1652: ! 1653: count = 0; ! 1654: ! 1655: for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { ! 1656: if (exception_mask & (1 << i)) { ! 1657: for (j = 0; j < count; j++) { ! 1658: /* ! 1659: * search for an identical entry, if found ! 1660: * set corresponding mask for this exception. ! 1661: */ ! 1662: if (task->exc_actions[i].port == ports[j] && ! 1663: task->exc_actions[i].behavior == behaviors[j] ! 1664: && task->exc_actions[i].flavor == flavors[j]) ! 1665: { ! 1666: masks[j] |= (1 << i); ! 1667: break; ! 1668: } ! 1669: }/* for */ ! 1670: if (j == count) { ! 1671: masks[j] = (1 << i); ! 1672: ports[j] = ! 1673: ipc_port_copy_send(task->exc_actions[i].port); ! 1674: behaviors[j] = task->exc_actions[i].behavior; ! 1675: flavors[j] = task->exc_actions[i].flavor; ! 1676: count++; ! 1677: if (count > *CountCnt) { ! 1678: break; ! 1679: } ! 1680: } ! 1681: } ! 1682: }/* for */ ! 1683: ! 1684: itk_unlock(task); ! 1685: ! 1686: *CountCnt = count; ! 1687: return KERN_SUCCESS; ! 1688: }/* task_get_exception_ports */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.