1/* 2 * Copyright (c) 2000-2009 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/task.h> 71#include <kern/thread.h> 72#include <kern/ipc_host.h> 73#include <kern/ipc_kobject.h> 74#include <kern/misc_protos.h> 75#include <kern/spl.h> 76#include <ipc/ipc_port.h> 77#include <ipc/ipc_space.h> 78 79/* 80 * Forward declarations 81 */ 82 83boolean_t 84ref_pset_port_locked( 85 ipc_port_t port, boolean_t matchn, processor_set_t *ppset); 86 87/* 88 * ipc_host_init: set up various things. 89 */ 90 91extern lck_grp_t host_notify_lock_grp; 92extern lck_attr_t host_notify_lock_attr; 93 94void ipc_host_init(void) 95{ 96 ipc_port_t port; 97 int i; 98 99 lck_mtx_init(&realhost.lock, &host_notify_lock_grp, &host_notify_lock_attr); 100 101 /* 102 * Allocate and set up the two host ports. 103 */ 104 port = ipc_port_alloc_kernel(); 105 if (port == IP_NULL) 106 panic("ipc_host_init"); 107 108 ipc_kobject_set(port, (ipc_kobject_t) &realhost, IKOT_HOST_SECURITY); 109 kernel_set_special_port(&realhost, HOST_SECURITY_PORT, 110 ipc_port_make_send(port)); 111 112 port = ipc_port_alloc_kernel(); 113 if (port == IP_NULL) 114 panic("ipc_host_init"); 115 116 ipc_kobject_set(port, (ipc_kobject_t) &realhost, IKOT_HOST); 117 kernel_set_special_port(&realhost, HOST_PORT, 118 ipc_port_make_send(port)); 119 120 port = ipc_port_alloc_kernel(); 121 if (port == IP_NULL) 122 panic("ipc_host_init"); 123 124 ipc_kobject_set(port, (ipc_kobject_t) &realhost, IKOT_HOST_PRIV); 125 kernel_set_special_port(&realhost, HOST_PRIV_PORT, 126 ipc_port_make_send(port)); 127 128 /* the rest of the special ports will be set up later */ 129 130 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { 131 realhost.exc_actions[i].port = IP_NULL; 132 }/* for */ 133 134 /* 135 * Set up ipc for default processor set. 136 */ 137 ipc_pset_init(&pset0); 138 ipc_pset_enable(&pset0); 139 140 /* 141 * And for master processor 142 */ 143 ipc_processor_init(master_processor); 144 ipc_processor_enable(master_processor); 145} 146 147/* 148 * Routine: host_self_trap [mach trap] 149 * Purpose: 150 * Give the caller send rights for his own host port. 151 * Conditions: 152 * Nothing locked. 153 * Returns: 154 * MACH_PORT_NULL if there are any resource failures 155 * or other errors. 156 */ 157 158mach_port_name_t 159host_self_trap( 160 __unused struct host_self_trap_args *args) 161{ 162 ipc_port_t sright; 163 mach_port_name_t name; 164 165 sright = ipc_port_copy_send(current_task()->itk_host); 166 name = ipc_port_copyout_send(sright, current_space()); 167 return name; 168} 169 170/* 171 * ipc_processor_init: 172 * 173 * Initialize ipc access to processor by allocating port. 174 */ 175 176void 177ipc_processor_init( 178 processor_t processor) 179{ 180 ipc_port_t port; 181 182 port = ipc_port_alloc_kernel(); 183 if (port == IP_NULL) 184 panic("ipc_processor_init"); 185 processor->processor_self = port; 186} 187 188/* 189 * ipc_processor_enable: 190 * 191 * Enable ipc control of processor by setting port object. 192 */ 193void 194ipc_processor_enable( 195 processor_t processor) 196{ 197 ipc_port_t myport; 198 199 myport = processor->processor_self; 200 ipc_kobject_set(myport, (ipc_kobject_t) processor, IKOT_PROCESSOR); 201} 202 203/* 204 * ipc_pset_init: 205 * 206 * Initialize ipc control of a processor set by allocating its ports. 207 */ 208 209void 210ipc_pset_init( 211 processor_set_t pset) 212{ 213 ipc_port_t port; 214 215 port = ipc_port_alloc_kernel(); 216 if (port == IP_NULL) 217 panic("ipc_pset_init"); 218 pset->pset_self = port; 219 220 port = ipc_port_alloc_kernel(); 221 if (port == IP_NULL) 222 panic("ipc_pset_init"); 223 pset->pset_name_self = port; 224} 225 226/* 227 * ipc_pset_enable: 228 * 229 * Enable ipc access to a processor set. 230 */ 231void 232ipc_pset_enable( 233 processor_set_t pset) 234{ 235 ipc_kobject_set(pset->pset_self, (ipc_kobject_t) pset, IKOT_PSET); 236 ipc_kobject_set(pset->pset_name_self, (ipc_kobject_t) pset, IKOT_PSET_NAME); 237} 238 239/* 240 * processor_set_default: 241 * 242 * Return ports for manipulating default_processor set. 243 */ 244kern_return_t 245processor_set_default( 246 host_t host, 247 processor_set_t *pset) 248{ 249 if (host == HOST_NULL) 250 return(KERN_INVALID_ARGUMENT); 251 252 *pset = &pset0; 253 254 return (KERN_SUCCESS); 255} 256 257/* 258 * Routine: convert_port_to_host 259 * Purpose: 260 * Convert from a port to a host. 261 * Doesn't consume the port ref; the host produced may be null. 262 * Conditions: 263 * Nothing locked. 264 */ 265 266host_t 267convert_port_to_host( 268 ipc_port_t port) 269{ 270 host_t host = HOST_NULL; 271 272 if (IP_VALID(port)) { 273 ip_lock(port); 274 if (ip_active(port) && 275 ((ip_kotype(port) == IKOT_HOST) || 276 (ip_kotype(port) == IKOT_HOST_PRIV) 277 )) 278 host = (host_t) port->ip_kobject; 279 ip_unlock(port); 280 } 281 282 return host; 283} 284 285/* 286 * Routine: convert_port_to_host_priv 287 * Purpose: 288 * Convert from a port to a host. 289 * Doesn't consume the port ref; the host produced may be null. 290 * Conditions: 291 * Nothing locked. 292 */ 293 294host_t 295convert_port_to_host_priv( 296 ipc_port_t port) 297{ 298 host_t host = HOST_NULL; 299 300 if (IP_VALID(port)) { 301 ip_lock(port); 302 if (ip_active(port) && 303 (ip_kotype(port) == IKOT_HOST_PRIV)) 304 host = (host_t) port->ip_kobject; 305 ip_unlock(port); 306 } 307 308 return host; 309} 310 311/* 312 * Routine: convert_port_to_processor 313 * Purpose: 314 * Convert from a port to a processor. 315 * Doesn't consume the port ref; 316 * the processor produced may be null. 317 * Conditions: 318 * Nothing locked. 319 */ 320 321processor_t 322convert_port_to_processor( 323 ipc_port_t port) 324{ 325 processor_t processor = PROCESSOR_NULL; 326 327 if (IP_VALID(port)) { 328 ip_lock(port); 329 if (ip_active(port) && 330 (ip_kotype(port) == IKOT_PROCESSOR)) 331 processor = (processor_t) port->ip_kobject; 332 ip_unlock(port); 333 } 334 335 return processor; 336} 337 338/* 339 * Routine: convert_port_to_pset 340 * Purpose: 341 * Convert from a port to a pset. 342 * Doesn't consume the port ref; produces a pset ref, 343 * which may be null. 344 * Conditions: 345 * Nothing locked. 346 */ 347 348processor_set_t 349convert_port_to_pset( 350 ipc_port_t port) 351{ 352 boolean_t r; 353 processor_set_t pset = PROCESSOR_SET_NULL; 354 355 r = FALSE; 356 while (!r && IP_VALID(port)) { 357 ip_lock(port); 358 r = ref_pset_port_locked(port, FALSE, &pset); 359 /* port unlocked */ 360 } 361 return pset; 362} 363 364/* 365 * Routine: convert_port_to_pset_name 366 * Purpose: 367 * Convert from a port to a pset. 368 * Doesn't consume the port ref; produces a pset ref, 369 * which may be null. 370 * Conditions: 371 * Nothing locked. 372 */ 373 374processor_set_name_t 375convert_port_to_pset_name( 376 ipc_port_t port) 377{ 378 boolean_t r; 379 processor_set_t pset = PROCESSOR_SET_NULL; 380 381 r = FALSE; 382 while (!r && IP_VALID(port)) { 383 ip_lock(port); 384 r = ref_pset_port_locked(port, TRUE, &pset); 385 /* port unlocked */ 386 } 387 return pset; 388} 389 390boolean_t 391ref_pset_port_locked(ipc_port_t port, boolean_t matchn, processor_set_t *ppset) 392{ 393 processor_set_t pset; 394 395 pset = PROCESSOR_SET_NULL; 396 if (ip_active(port) && 397 ((ip_kotype(port) == IKOT_PSET) || 398 (matchn && (ip_kotype(port) == IKOT_PSET_NAME)))) { 399 pset = (processor_set_t) port->ip_kobject; 400 } 401 402 *ppset = pset; 403 ip_unlock(port); 404 405 return (TRUE); 406} 407 408/* 409 * Routine: convert_host_to_port 410 * Purpose: 411 * Convert from a host to a port. 412 * Produces a naked send right which may be invalid. 413 * Conditions: 414 * Nothing locked. 415 */ 416 417ipc_port_t 418convert_host_to_port( 419 host_t host) 420{ 421 ipc_port_t port; 422 423 host_get_host_port(host, &port); 424 return port; 425} 426 427/* 428 * Routine: convert_processor_to_port 429 * Purpose: 430 * Convert from a processor to a port. 431 * Produces a naked send right which may be invalid. 432 * Processors are not reference counted, so nothing to release. 433 * Conditions: 434 * Nothing locked. 435 */ 436 437ipc_port_t 438convert_processor_to_port( 439 processor_t processor) 440{ 441 ipc_port_t port = processor->processor_self; 442 443 if (port != IP_NULL) 444 port = ipc_port_make_send(port); 445 return port; 446} 447 448/* 449 * Routine: convert_pset_to_port 450 * Purpose: 451 * Convert from a pset to a port. 452 * Produces a naked send right which may be invalid. 453 * Processor sets are not reference counted, so nothing to release. 454 * Conditions: 455 * Nothing locked. 456 */ 457 458ipc_port_t 459convert_pset_to_port( 460 processor_set_t pset) 461{ 462 ipc_port_t port = pset->pset_self; 463 464 if (port != IP_NULL) 465 port = ipc_port_make_send(port); 466 467 return port; 468} 469 470/* 471 * Routine: convert_pset_name_to_port 472 * Purpose: 473 * Convert from a pset to a port. 474 * Produces a naked send right which may be invalid. 475 * Processor sets are not reference counted, so nothing to release. 476 * Conditions: 477 * Nothing locked. 478 */ 479 480ipc_port_t 481convert_pset_name_to_port( 482 processor_set_name_t pset) 483{ 484 ipc_port_t port = pset->pset_name_self; 485 486 if (port != IP_NULL) 487 port = ipc_port_make_send(port); 488 489 return port; 490} 491 492/* 493 * Routine: convert_port_to_host_security 494 * Purpose: 495 * Convert from a port to a host security. 496 * Doesn't consume the port ref; the port produced may be null. 497 * Conditions: 498 * Nothing locked. 499 */ 500 501host_t 502convert_port_to_host_security( 503 ipc_port_t port) 504{ 505 host_t host = HOST_NULL; 506 507 if (IP_VALID(port)) { 508 ip_lock(port); 509 if (ip_active(port) && 510 (ip_kotype(port) == IKOT_HOST_SECURITY)) 511 host = (host_t) port->ip_kobject; 512 ip_unlock(port); 513 } 514 515 return host; 516} 517 518/* 519 * Routine: host_set_exception_ports [kernel call] 520 * Purpose: 521 * Sets the host exception port, flavor and 522 * behavior for the exception types specified by the mask. 523 * There will be one send right per exception per valid 524 * port. 525 * Conditions: 526 * Nothing locked. If successful, consumes 527 * the supplied send right. 528 * Returns: 529 * KERN_SUCCESS Changed the special port. 530 * KERN_INVALID_ARGUMENT The host_priv is not valid, 531 * Illegal mask bit set. 532 * Illegal exception behavior 533 */ 534kern_return_t 535host_set_exception_ports( 536 host_priv_t host_priv, 537 exception_mask_t exception_mask, 538 ipc_port_t new_port, 539 exception_behavior_t new_behavior, 540 thread_state_flavor_t new_flavor) 541{ 542 register int i; 543 ipc_port_t old_port[EXC_TYPES_COUNT]; 544 545 if (host_priv == HOST_PRIV_NULL) { 546 return KERN_INVALID_ARGUMENT; 547 } 548 549 assert(host_priv == &realhost); 550 551 if (exception_mask & ~EXC_MASK_VALID) { 552 return KERN_INVALID_ARGUMENT; 553 } 554 555 if (IP_VALID(new_port)) { 556 switch (new_behavior & ~MACH_EXCEPTION_CODES) { 557 case EXCEPTION_DEFAULT: 558 case EXCEPTION_STATE: 559 case EXCEPTION_STATE_IDENTITY: 560 break; 561 default: 562 return KERN_INVALID_ARGUMENT; 563 } 564 } 565 566 /* 567 * Check the validity of the thread_state_flavor by calling the 568 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in 569 * osfmk/mach/ARCHITECTURE/thread_status.h 570 */ 571 if (new_flavor != 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor)) 572 return (KERN_INVALID_ARGUMENT); 573 574 host_lock(host_priv); 575 576 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { 577 if (exception_mask & (1 << i)) { 578 old_port[i] = host_priv->exc_actions[i].port; 579 host_priv->exc_actions[i].port = 580 ipc_port_copy_send(new_port); 581 host_priv->exc_actions[i].behavior = new_behavior; 582 host_priv->exc_actions[i].flavor = new_flavor; 583 } else 584 old_port[i] = IP_NULL; 585 }/* for */ 586 587 /* 588 * Consume send rights without any lock held. 589 */ 590 host_unlock(host_priv); 591 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) 592 if (IP_VALID(old_port[i])) 593 ipc_port_release_send(old_port[i]); 594 if (IP_VALID(new_port)) /* consume send right */ 595 ipc_port_release_send(new_port); 596 597 return KERN_SUCCESS; 598} 599 600/* 601 * Routine: host_get_exception_ports [kernel call] 602 * Purpose: 603 * Clones a send right for each of the host's exception 604 * ports specified in the mask and returns the behaviour 605 * and flavor of said port. 606 * 607 * Returns upto [in} CountCnt elements. 608 * 609 * Conditions: 610 * Nothing locked. 611 * Returns: 612 * KERN_SUCCESS Extracted a send right. 613 * KERN_INVALID_ARGUMENT Invalid host_priv specified, 614 * Invalid special port, 615 * Illegal mask bit set. 616 * KERN_FAILURE The thread is dead. 617 */ 618kern_return_t 619host_get_exception_ports( 620 host_priv_t host_priv, 621 exception_mask_t exception_mask, 622 exception_mask_array_t masks, 623 mach_msg_type_number_t * CountCnt, 624 exception_port_array_t ports, 625 exception_behavior_array_t behaviors, 626 thread_state_flavor_array_t flavors ) 627{ 628 unsigned int i, j, count; 629 630 if (host_priv == HOST_PRIV_NULL) 631 return KERN_INVALID_ARGUMENT; 632 633 if (exception_mask & ~EXC_MASK_VALID) { 634 return KERN_INVALID_ARGUMENT; 635 } 636 637 assert (host_priv == &realhost); 638 639 host_lock(host_priv); 640 641 count = 0; 642 643 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { 644 if (exception_mask & (1 << i)) { 645 for (j = 0; j < count; j++) { 646/* 647 * search for an identical entry, if found 648 * set corresponding mask for this exception. 649 */ 650 if (host_priv->exc_actions[i].port == ports[j] && 651 host_priv->exc_actions[i].behavior == behaviors[j] 652 && host_priv->exc_actions[i].flavor == flavors[j]) 653 { 654 masks[j] |= (1 << i); 655 break; 656 } 657 }/* for */ 658 if (j == count) { 659 masks[j] = (1 << i); 660 ports[j] = 661 ipc_port_copy_send(host_priv->exc_actions[i].port); 662 behaviors[j] = host_priv->exc_actions[i].behavior; 663 flavors[j] = host_priv->exc_actions[i].flavor; 664 count++; 665 if (count > *CountCnt) { 666 break; 667 } 668 } 669 } 670 }/* for */ 671 host_unlock(host_priv); 672 673 *CountCnt = count; 674 return KERN_SUCCESS; 675} 676 677kern_return_t 678host_swap_exception_ports( 679 host_priv_t host_priv, 680 exception_mask_t exception_mask, 681 ipc_port_t new_port, 682 exception_behavior_t new_behavior, 683 thread_state_flavor_t new_flavor, 684 exception_mask_array_t masks, 685 mach_msg_type_number_t * CountCnt, 686 exception_port_array_t ports, 687 exception_behavior_array_t behaviors, 688 thread_state_flavor_array_t flavors ) 689{ 690 unsigned int i, 691 j, 692 count; 693 ipc_port_t old_port[EXC_TYPES_COUNT]; 694 695 if (host_priv == HOST_PRIV_NULL) 696 return KERN_INVALID_ARGUMENT; 697 698 if (exception_mask & ~EXC_MASK_VALID) { 699 return KERN_INVALID_ARGUMENT; 700 } 701 702 if (IP_VALID(new_port)) { 703 switch (new_behavior) { 704 case EXCEPTION_DEFAULT: 705 case EXCEPTION_STATE: 706 case EXCEPTION_STATE_IDENTITY: 707 break; 708 default: 709 return KERN_INVALID_ARGUMENT; 710 } 711 } 712 713 if (new_flavor != 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor)) 714 return (KERN_INVALID_ARGUMENT); 715 716 host_lock(host_priv); 717 718 assert(EXC_TYPES_COUNT > FIRST_EXCEPTION); 719 for (count=0, i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT && count < *CountCnt; i++) { 720 if (exception_mask & (1 << i)) { 721 for (j = 0; j < count; j++) { 722/* 723 * search for an identical entry, if found 724 * set corresponding mask for this exception. 725 */ 726 if (host_priv->exc_actions[i].port == ports[j] && 727 host_priv->exc_actions[i].behavior == behaviors[j] 728 && host_priv->exc_actions[i].flavor == flavors[j]) 729 { 730 masks[j] |= (1 << i); 731 break; 732 } 733 }/* for */ 734 if (j == count) { 735 masks[j] = (1 << i); 736 ports[j] = 737 ipc_port_copy_send(host_priv->exc_actions[i].port); 738 behaviors[j] = host_priv->exc_actions[i].behavior; 739 flavors[j] = host_priv->exc_actions[i].flavor; 740 count++; 741 } 742 old_port[i] = host_priv->exc_actions[i].port; 743 host_priv->exc_actions[i].port = 744 ipc_port_copy_send(new_port); 745 host_priv->exc_actions[i].behavior = new_behavior; 746 host_priv->exc_actions[i].flavor = new_flavor; 747 } else 748 old_port[i] = IP_NULL; 749 }/* for */ 750 host_unlock(host_priv); 751 752 /* 753 * Consume send rights without any lock held. 754 */ 755 while (--i >= FIRST_EXCEPTION) { 756 if (IP_VALID(old_port[i])) 757 ipc_port_release_send(old_port[i]); 758 } 759 760 if (IP_VALID(new_port)) /* consume send right */ 761 ipc_port_release_send(new_port); 762 *CountCnt = count; 763 764 return KERN_SUCCESS; 765} 766