1/* 2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* 29 * @OSF_COPYRIGHT@ 30 */ 31/* 32 * Mach Operating System 33 * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University 34 * All Rights Reserved. 35 * 36 * Permission to use, copy, modify and distribute this software and its 37 * documentation is hereby granted, provided that both the copyright 38 * notice and this permission notice appear in all copies of the 39 * software, derivative works or modified versions, and any portions 40 * thereof, and that both notices appear in supporting documentation. 41 * 42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 45 * 46 * Carnegie Mellon requests users of this software to return to 47 * 48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 49 * School of Computer Science 50 * Carnegie Mellon University 51 * Pittsburgh PA 15213-3890 52 * 53 * any improvements or extensions that they make and grant Carnegie Mellon 54 * the rights to redistribute these changes. 55 */ 56/* 57 */ 58 59/* 60 * kern/ipc_host.c 61 * 62 * Routines to implement host ports. 63 */ 64#include <mach/message.h> 65#include <mach/mach_traps.h> 66#include <mach/mach_host_server.h> 67#include <mach/host_priv_server.h> 68#include <kern/host.h> 69#include <kern/processor.h> 70#include <kern/lock.h> 71#include <kern/task.h> 72#include <kern/thread.h> 73#include <kern/ipc_host.h> 74#include <kern/ipc_kobject.h> 75#include <kern/misc_protos.h> 76#include <kern/spl.h> 77#include <ipc/ipc_port.h> 78#include <ipc/ipc_space.h> 79 80/* 81 * Forward declarations 82 */ 83 84void 85ipc_processor_terminate( 86 processor_t processor); 87 88void 89ipc_processor_disable( 90 processor_t processor); 91 92boolean_t 93ref_pset_port_locked( 94 ipc_port_t port, boolean_t matchn, processor_set_t *ppset); 95 96/* 97 * ipc_host_init: set up various things. 98 */ 99 100void ipc_host_init(void) 101{ 102 ipc_port_t port; 103 int i; 104 105 mutex_init(&realhost.lock, 0); 106 107 /* 108 * Allocate and set up the two host ports. 109 */ 110 port = ipc_port_alloc_kernel(); 111 if (port == IP_NULL) 112 panic("ipc_host_init"); 113 114 ipc_kobject_set(port, (ipc_kobject_t) &realhost, IKOT_HOST_SECURITY); 115 kernel_set_special_port(&realhost, HOST_SECURITY_PORT, 116 ipc_port_make_send(port)); 117 118 port = ipc_port_alloc_kernel(); 119 if (port == IP_NULL) 120 panic("ipc_host_init"); 121 122 ipc_kobject_set(port, (ipc_kobject_t) &realhost, IKOT_HOST); 123 kernel_set_special_port(&realhost, HOST_PORT, 124 ipc_port_make_send(port)); 125 126 port = ipc_port_alloc_kernel(); 127 if (port == IP_NULL) 128 panic("ipc_host_init"); 129 130 ipc_kobject_set(port, (ipc_kobject_t) &realhost, IKOT_HOST_PRIV); 131 kernel_set_special_port(&realhost, HOST_PRIV_PORT, 132 ipc_port_make_send(port)); 133 134 /* the rest of the special ports will be set up later */ 135 136 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { 137 realhost.exc_actions[i].port = IP_NULL; 138 }/* for */ 139 140 /* 141 * Set up ipc for default processor set. 142 */ 143 ipc_pset_init(&pset0); 144 ipc_pset_enable(&pset0); 145 146 /* 147 * And for master processor 148 */ 149 ipc_processor_init(master_processor); 150 ipc_processor_enable(master_processor); 151} 152 153/* 154 * Routine: host_self_trap [mach trap] 155 * Purpose: 156 * Give the caller send rights for his own host port. 157 * Conditions: 158 * Nothing locked. 159 * Returns: 160 * MACH_PORT_NULL if there are any resource failures 161 * or other errors. 162 */ 163 164mach_port_name_t 165host_self_trap( 166 __unused struct host_self_trap_args *args) 167{ 168 ipc_port_t sright; 169 mach_port_name_t name; 170 171 sright = ipc_port_copy_send(current_task()->itk_host); 172 name = ipc_port_copyout_send(sright, current_space()); 173 return name; 174} 175 176/* 177 * ipc_processor_init: 178 * 179 * Initialize ipc access to processor by allocating port. 180 */ 181 182void 183ipc_processor_init( 184 processor_t processor) 185{ 186 ipc_port_t port; 187 188 port = ipc_port_alloc_kernel(); 189 if (port == IP_NULL) 190 panic("ipc_processor_init"); 191 processor->processor_self = port; 192} 193 194/* 195 * ipc_processor_enable: 196 * 197 * Enable ipc control of processor by setting port object. 198 */ 199void 200ipc_processor_enable( 201 processor_t processor) 202{ 203 ipc_port_t myport; 204 205 myport = processor->processor_self; 206 ipc_kobject_set(myport, (ipc_kobject_t) processor, IKOT_PROCESSOR); 207} 208 209/* 210 * ipc_processor_disable: 211 * 212 * Disable ipc control of processor by clearing port object. 213 */ 214void 215ipc_processor_disable( 216 processor_t processor) 217{ 218 ipc_port_t myport; 219 220 myport = processor->processor_self; 221 if (myport == IP_NULL) 222 return; 223 ipc_kobject_set(myport, IKO_NULL, IKOT_NONE); 224} 225 226/* 227 * ipc_processor_terminate: 228 * 229 * Processor is off-line. Destroy ipc control port. 230 */ 231void 232ipc_processor_terminate( 233 processor_t processor) 234{ 235 ipc_port_t myport; 236 spl_t s; 237 238 s = splsched(); 239 processor_lock(processor); 240 myport = processor->processor_self; 241 if (myport == IP_NULL) { 242 processor_unlock(processor); 243 splx(s); 244 return; 245 } 246 247 processor->processor_self = IP_NULL; 248 processor_unlock(processor); 249 splx(s); 250 251 ipc_port_dealloc_kernel(myport); 252} 253 254/* 255 * ipc_pset_init: 256 * 257 * Initialize ipc control of a processor set by allocating its ports. 258 */ 259 260void 261ipc_pset_init( 262 processor_set_t pset) 263{ 264 ipc_port_t port; 265 266 port = ipc_port_alloc_kernel(); 267 if (port == IP_NULL) 268 panic("ipc_pset_init"); 269 pset->pset_self = port; 270 271 port = ipc_port_alloc_kernel(); 272 if (port == IP_NULL) 273 panic("ipc_pset_init"); 274 pset->pset_name_self = port; 275} 276 277/* 278 * ipc_pset_enable: 279 * 280 * Enable ipc access to a processor set. 281 */ 282void 283ipc_pset_enable( 284 processor_set_t pset) 285{ 286 ipc_kobject_set(pset->pset_self, (ipc_kobject_t) pset, IKOT_PSET); 287 ipc_kobject_set(pset->pset_name_self, (ipc_kobject_t) pset, IKOT_PSET_NAME); 288} 289 290/* 291 * processor_set_default: 292 * 293 * Return ports for manipulating default_processor set. 294 */ 295kern_return_t 296processor_set_default( 297 host_t host, 298 processor_set_t *pset) 299{ 300 if (host == HOST_NULL) 301 return(KERN_INVALID_ARGUMENT); 302 303 *pset = &pset0; 304 305 return (KERN_SUCCESS); 306} 307 308/* 309 * Routine: convert_port_to_host 310 * Purpose: 311 * Convert from a port to a host. 312 * Doesn't consume the port ref; the host produced may be null. 313 * Conditions: 314 * Nothing locked. 315 */ 316 317host_t 318convert_port_to_host( 319 ipc_port_t port) 320{ 321 host_t host = HOST_NULL; 322 323 if (IP_VALID(port)) { 324 ip_lock(port); 325 if (ip_active(port) && 326 ((ip_kotype(port) == IKOT_HOST) || 327 (ip_kotype(port) == IKOT_HOST_PRIV) 328 )) 329 host = (host_t) port->ip_kobject; 330 ip_unlock(port); 331 } 332 333 return host; 334} 335 336/* 337 * Routine: convert_port_to_host_priv 338 * Purpose: 339 * Convert from a port to a host. 340 * Doesn't consume the port ref; the host produced may be null. 341 * Conditions: 342 * Nothing locked. 343 */ 344 345host_t 346convert_port_to_host_priv( 347 ipc_port_t port) 348{ 349 host_t host = HOST_NULL; 350 351 if (IP_VALID(port)) { 352 ip_lock(port); 353 if (ip_active(port) && 354 (ip_kotype(port) == IKOT_HOST_PRIV)) 355 host = (host_t) port->ip_kobject; 356 ip_unlock(port); 357 } 358 359 return host; 360} 361 362/* 363 * Routine: convert_port_to_processor 364 * Purpose: 365 * Convert from a port to a processor. 366 * Doesn't consume the port ref; 367 * the processor produced may be null. 368 * Conditions: 369 * Nothing locked. 370 */ 371 372processor_t 373convert_port_to_processor( 374 ipc_port_t port) 375{ 376 processor_t processor = PROCESSOR_NULL; 377 378 if (IP_VALID(port)) { 379 ip_lock(port); 380 if (ip_active(port) && 381 (ip_kotype(port) == IKOT_PROCESSOR)) 382 processor = (processor_t) port->ip_kobject; 383 ip_unlock(port); 384 } 385 386 return processor; 387} 388 389/* 390 * Routine: convert_port_to_pset 391 * Purpose: 392 * Convert from a port to a pset. 393 * Doesn't consume the port ref; produces a pset ref, 394 * which may be null. 395 * Conditions: 396 * Nothing locked. 397 */ 398 399processor_set_t 400convert_port_to_pset( 401 ipc_port_t port) 402{ 403 boolean_t r; 404 processor_set_t pset = PROCESSOR_SET_NULL; 405 406 r = FALSE; 407 while (!r && IP_VALID(port)) { 408 ip_lock(port); 409 r = ref_pset_port_locked(port, FALSE, &pset); 410 /* port unlocked */ 411 } 412 return pset; 413} 414 415/* 416 * Routine: convert_port_to_pset_name 417 * Purpose: 418 * Convert from a port to a pset. 419 * Doesn't consume the port ref; produces a pset ref, 420 * which may be null. 421 * Conditions: 422 * Nothing locked. 423 */ 424 425processor_set_name_t 426convert_port_to_pset_name( 427 ipc_port_t port) 428{ 429 boolean_t r; 430 processor_set_t pset = PROCESSOR_SET_NULL; 431 432 r = FALSE; 433 while (!r && IP_VALID(port)) { 434 ip_lock(port); 435 r = ref_pset_port_locked(port, TRUE, &pset); 436 /* port unlocked */ 437 } 438 return pset; 439} 440 441boolean_t 442ref_pset_port_locked(ipc_port_t port, boolean_t matchn, processor_set_t *ppset) 443{ 444 processor_set_t pset; 445 446 pset = PROCESSOR_SET_NULL; 447 if (ip_active(port) && 448 ((ip_kotype(port) == IKOT_PSET) || 449 (matchn && (ip_kotype(port) == IKOT_PSET_NAME)))) { 450 pset = (processor_set_t) port->ip_kobject; 451 } 452 453 *ppset = pset; 454 ip_unlock(port); 455 456 return (TRUE); 457} 458 459/* 460 * Routine: convert_host_to_port 461 * Purpose: 462 * Convert from a host to a port. 463 * Produces a naked send right which may be invalid. 464 * Conditions: 465 * Nothing locked. 466 */ 467 468ipc_port_t 469convert_host_to_port( 470 host_t host) 471{ 472 ipc_port_t port; 473 474 host_get_host_port(host, &port); 475 return port; 476} 477 478/* 479 * Routine: convert_processor_to_port 480 * Purpose: 481 * Convert from a processor to a port. 482 * Produces a naked send right which may be invalid. 483 * Conditions: 484 * Nothing locked. 485 */ 486 487ipc_port_t 488convert_processor_to_port( 489 processor_t processor) 490{ 491 ipc_port_t port; 492 spl_t s; 493 494 s = splsched(); 495 processor_lock(processor); 496 497 if (processor->processor_self != IP_NULL) 498 port = ipc_port_make_send(processor->processor_self); 499 else 500 port = IP_NULL; 501 502 processor_unlock(processor); 503 splx(s); 504 505 return port; 506} 507 508/* 509 * Routine: convert_pset_to_port 510 * Purpose: 511 * Convert from a pset to a port. 512 * Produces a naked send right 513 * which may be invalid. 514 * Conditions: 515 * Nothing locked. 516 */ 517 518ipc_port_t 519convert_pset_to_port( 520 processor_set_t pset) 521{ 522 ipc_port_t port = pset->pset_self; 523 524 if (port != IP_NULL) 525 port = ipc_port_make_send(port); 526 527 return port; 528} 529 530/* 531 * Routine: convert_pset_name_to_port 532 * Purpose: 533 * Convert from a pset to a port. 534 * Produces a naked send right 535 * which may be invalid. 536 * Conditions: 537 * Nothing locked. 538 */ 539 540ipc_port_t 541convert_pset_name_to_port( 542 processor_set_name_t pset) 543{ 544 ipc_port_t port = pset->pset_name_self; 545 546 if (port != IP_NULL) 547 port = ipc_port_make_send(port); 548 549 return port; 550} 551 552/* 553 * Routine: convert_port_to_host_security 554 * Purpose: 555 * Convert from a port to a host security. 556 * Doesn't consume the port ref; the port produced may be null. 557 * Conditions: 558 * Nothing locked. 559 */ 560 561host_t 562convert_port_to_host_security( 563 ipc_port_t port) 564{ 565 host_t host = HOST_NULL; 566 567 if (IP_VALID(port)) { 568 ip_lock(port); 569 if (ip_active(port) && 570 (ip_kotype(port) == IKOT_HOST_SECURITY)) 571 host = (host_t) port->ip_kobject; 572 ip_unlock(port); 573 } 574 575 return host; 576} 577 578/* 579 * Routine: host_set_exception_ports [kernel call] 580 * Purpose: 581 * Sets the host exception port, flavor and 582 * behavior for the exception types specified by the mask. 583 * There will be one send right per exception per valid 584 * port. 585 * Conditions: 586 * Nothing locked. If successful, consumes 587 * the supplied send right. 588 * Returns: 589 * KERN_SUCCESS Changed the special port. 590 * KERN_INVALID_ARGUMENT The host_priv is not valid, 591 * Illegal mask bit set. 592 * Illegal exception behavior 593 */ 594kern_return_t 595host_set_exception_ports( 596 host_priv_t host_priv, 597 exception_mask_t exception_mask, 598 ipc_port_t new_port, 599 exception_behavior_t new_behavior, 600 thread_state_flavor_t new_flavor) 601{ 602 register int i; 603 ipc_port_t old_port[EXC_TYPES_COUNT]; 604 605 if (host_priv == HOST_PRIV_NULL) { 606 return KERN_INVALID_ARGUMENT; 607 } 608 609 assert(host_priv == &realhost); 610 611 if (exception_mask & ~EXC_MASK_ALL) { 612 return KERN_INVALID_ARGUMENT; 613 } 614 615 if (IP_VALID(new_port)) { 616 switch (new_behavior & ~MACH_EXCEPTION_CODES) { 617 case EXCEPTION_DEFAULT: 618 case EXCEPTION_STATE: 619 case EXCEPTION_STATE_IDENTITY: 620 break; 621 default: 622 return KERN_INVALID_ARGUMENT; 623 } 624 } 625 /* Cannot easily check "new_flavor", but that just means that 626 * the flavor in the generated exception message might be garbage: 627 * GIGO 628 */ 629 host_lock(host_priv); 630 631 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { 632 if (exception_mask & (1 << i)) { 633 old_port[i] = host_priv->exc_actions[i].port; 634 host_priv->exc_actions[i].port = 635 ipc_port_copy_send(new_port); 636 host_priv->exc_actions[i].behavior = new_behavior; 637 host_priv->exc_actions[i].flavor = new_flavor; 638 } else 639 old_port[i] = IP_NULL; 640 }/* for */ 641 642 /* 643 * Consume send rights without any lock held. 644 */ 645 host_unlock(host_priv); 646 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) 647 if (IP_VALID(old_port[i])) 648 ipc_port_release_send(old_port[i]); 649 if (IP_VALID(new_port)) /* consume send right */ 650 ipc_port_release_send(new_port); 651 652 return KERN_SUCCESS; 653} 654 655/* 656 * Routine: host_get_exception_ports [kernel call] 657 * Purpose: 658 * Clones a send right for each of the host's exception 659 * ports specified in the mask and returns the behaviour 660 * and flavor of said port. 661 * 662 * Returns upto [in} CountCnt elements. 663 * 664 * Conditions: 665 * Nothing locked. 666 * Returns: 667 * KERN_SUCCESS Extracted a send right. 668 * KERN_INVALID_ARGUMENT Invalid host_priv specified, 669 * Invalid special port, 670 * Illegal mask bit set. 671 * KERN_FAILURE The thread is dead. 672 */ 673kern_return_t 674host_get_exception_ports( 675 host_priv_t host_priv, 676 exception_mask_t exception_mask, 677 exception_mask_array_t masks, 678 mach_msg_type_number_t * CountCnt, 679 exception_port_array_t ports, 680 exception_behavior_array_t behaviors, 681 thread_state_flavor_array_t flavors ) 682{ 683 unsigned int i, j, count; 684 685 if (host_priv == HOST_PRIV_NULL) 686 return KERN_INVALID_ARGUMENT; 687 688 if (exception_mask & ~EXC_MASK_ALL) { 689 return KERN_INVALID_ARGUMENT; 690 } 691 692 assert (host_priv == &realhost); 693 694 host_lock(host_priv); 695 696 count = 0; 697 698 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { 699 if (exception_mask & (1 << i)) { 700 for (j = 0; j < count; j++) { 701/* 702 * search for an identical entry, if found 703 * set corresponding mask for this exception. 704 */ 705 if (host_priv->exc_actions[i].port == ports[j] && 706 host_priv->exc_actions[i].behavior == behaviors[j] 707 && host_priv->exc_actions[i].flavor == flavors[j]) 708 { 709 masks[j] |= (1 << i); 710 break; 711 } 712 }/* for */ 713 if (j == count) { 714 masks[j] = (1 << i); 715 ports[j] = 716 ipc_port_copy_send(host_priv->exc_actions[i].port); 717 behaviors[j] = host_priv->exc_actions[i].behavior; 718 flavors[j] = host_priv->exc_actions[i].flavor; 719 count++; 720 if (count > *CountCnt) { 721 break; 722 } 723 } 724 } 725 }/* for */ 726 host_unlock(host_priv); 727 728 *CountCnt = count; 729 return KERN_SUCCESS; 730} 731 732kern_return_t 733host_swap_exception_ports( 734 host_priv_t host_priv, 735 exception_mask_t exception_mask, 736 ipc_port_t new_port, 737 exception_behavior_t new_behavior, 738 thread_state_flavor_t new_flavor, 739 exception_mask_array_t masks, 740 mach_msg_type_number_t * CountCnt, 741 exception_port_array_t ports, 742 exception_behavior_array_t behaviors, 743 thread_state_flavor_array_t flavors ) 744{ 745 unsigned int i, 746 j, 747 count; 748 ipc_port_t old_port[EXC_TYPES_COUNT]; 749 750 if (host_priv == HOST_PRIV_NULL) 751 return KERN_INVALID_ARGUMENT; 752 753 if (exception_mask & ~EXC_MASK_ALL) { 754 return KERN_INVALID_ARGUMENT; 755 } 756 757 if (IP_VALID(new_port)) { 758 switch (new_behavior) { 759 case EXCEPTION_DEFAULT: 760 case EXCEPTION_STATE: 761 case EXCEPTION_STATE_IDENTITY: 762 break; 763 default: 764 return KERN_INVALID_ARGUMENT; 765 } 766 } 767 /* Cannot easily check "new_flavor", but that just means that 768 * the flavor in the generated exception message might be garbage: 769 * GIGO */ 770 771 host_lock(host_priv); 772 773 count = 0; 774 775 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { 776 if (exception_mask & (1 << i)) { 777 for (j = 0; j < count; j++) { 778/* 779 * search for an identical entry, if found 780 * set corresponding mask for this exception. 781 */ 782 if (host_priv->exc_actions[i].port == ports[j] && 783 host_priv->exc_actions[i].behavior == behaviors[j] 784 && host_priv->exc_actions[i].flavor == flavors[j]) 785 { 786 masks[j] |= (1 << i); 787 break; 788 } 789 }/* for */ 790 if (j == count) { 791 masks[j] = (1 << i); 792 ports[j] = 793 ipc_port_copy_send(host_priv->exc_actions[i].port); 794 behaviors[j] = host_priv->exc_actions[i].behavior; 795 flavors[j] = host_priv->exc_actions[i].flavor; 796 count++; 797 } 798 old_port[i] = host_priv->exc_actions[i].port; 799 host_priv->exc_actions[i].port = 800 ipc_port_copy_send(new_port); 801 host_priv->exc_actions[i].behavior = new_behavior; 802 host_priv->exc_actions[i].flavor = new_flavor; 803 if (count > *CountCnt) { 804 break; 805 } 806 } else 807 old_port[i] = IP_NULL; 808 }/* for */ 809 host_unlock(host_priv); 810 811 /* 812 * Consume send rights without any lock held. 813 */ 814 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) 815 if (IP_VALID(old_port[i])) 816 ipc_port_release_send(old_port[i]); 817 if (IP_VALID(new_port)) /* consume send right */ 818 ipc_port_release_send(new_port); 819 *CountCnt = count; 820 821 return KERN_SUCCESS; 822} 823