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