1 /* 2 * Copyright (c) 1998-2011 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 #include <IOKit/IOBSD.h> 29 #include <IOKit/IOLib.h> 30 #include <IOKit/IOService.h> 31 #include <IOKit/IOCatalogue.h> 32 #include <IOKit/IODeviceTreeSupport.h> 33 #include <IOKit/IOKitKeys.h> 34 #include <IOKit/IOPlatformExpert.h> 35 #include <IOKit/IOUserClient.h> 36 37 extern "C" { 38 39 #include <pexpert/pexpert.h> 40 #include <kern/clock.h> 41 #include <mach/machine.h> 42 #include <uuid/uuid.h> 43 #include <sys/vnode_internal.h> 44 #include <sys/mount.h> 45 46 // how long to wait for matching root device, secs 47 #if DEBUG 48 #define ROOTDEVICETIMEOUT 120 49 #else 50 #define ROOTDEVICETIMEOUT 60 51 #endif 52 53 int panic_on_exception_triage = 0; 54 55 extern dev_t mdevadd(int devid, uint64_t base, unsigned int size, int phys); 56 extern dev_t mdevlookup(int devid); 57 extern void mdevremoveall(void); 58 extern int mdevgetrange(int devid, uint64_t *base, uint64_t *size); 59 extern void di_root_ramfile(IORegistryEntry * entry); 60 61 #if CONFIG_EMBEDDED 62 #define IOPOLLED_COREFILE (CONFIG_KDP_INTERACTIVE_DEBUGGING) 63 64 #if defined(XNU_TARGET_OS_BRIDGE) 65 66 #define kIOCoreDumpSize 150ULL*1024ULL*1024ULL 67 // leave free space on volume: 68 #define kIOCoreDumpFreeSize 150ULL*1024ULL*1024ULL 69 #define kIOCoreDumpPath "/private/var/internal/kernelcore" 70 71 #else /* defined(XNU_TARGET_OS_BRIDGE) */ 72 #define kIOCoreDumpMinSize 350ULL*1024ULL*1024ULL 73 #define kIOCoreDumpLargeSize 500ULL*1024ULL*1024ULL 74 // leave free space on volume: 75 #define kIOCoreDumpFreeSize 350ULL*1024ULL*1024ULL 76 #define kIOCoreDumpPath "/private/var/vm/kernelcore" 77 78 #endif /* defined(XNU_TARGET_OS_BRIDGE) */ 79 80 #elif DEVELOPMENT /* CONFIG_EMBEDDED */ 81 #define IOPOLLED_COREFILE 1 82 // no sizing 83 #define kIOCoreDumpSize 0ULL 84 #define kIOCoreDumpFreeSize 0ULL 85 #else /* CONFIG_EMBEDDED */ 86 #define IOPOLLED_COREFILE 0 87 #endif /* CONFIG_EMBEDDED */ 88 89 90 #if IOPOLLED_COREFILE 91 static bool 92 NewKernelCoreMedia(void * target, void * refCon, 93 IOService * newService, 94 IONotifier * notifier); 95 #endif /* IOPOLLED_COREFILE */ 96 97 #if CONFIG_KDP_INTERACTIVE_DEBUGGING 98 /* 99 * Touched by IOFindBSDRoot() if a RAMDisk is used for the root device. 100 */ 101 extern uint64_t kdp_core_ramdisk_addr; 102 extern uint64_t kdp_core_ramdisk_size; 103 #endif 104 105 kern_return_t 106 IOKitBSDInit( void ) 107 { 108 IOService::publishResource("IOBSD"); 109 110 return( kIOReturnSuccess ); 111 } 112 113 void 114 IOServicePublishResource( const char * property, boolean_t value ) 115 { 116 if ( value) 117 IOService::publishResource( property, kOSBooleanTrue ); 118 else 119 IOService::getResourceService()->removeProperty( property ); 120 } 121 122 boolean_t 123 IOServiceWaitForMatchingResource( const char * property, uint64_t timeout ) 124 { 125 OSDictionary * dict = 0; 126 IOService * match = 0; 127 boolean_t found = false; 128 129 do { 130 131 dict = IOService::resourceMatching( property ); 132 if( !dict) 133 continue; 134 match = IOService::waitForMatchingService( dict, timeout ); 135 if ( match) 136 found = true; 137 138 } while( false ); 139 140 if( dict) 141 dict->release(); 142 if( match) 143 match->release(); 144 145 return( found ); 146 } 147 148 boolean_t 149 IOCatalogueMatchingDriversPresent( const char * property ) 150 { 151 OSDictionary * dict = 0; 152 OSOrderedSet * set = 0; 153 SInt32 generationCount = 0; 154 boolean_t found = false; 155 156 do { 157 158 dict = OSDictionary::withCapacity(1); 159 if( !dict) 160 continue; 161 dict->setObject( property, kOSBooleanTrue ); 162 set = gIOCatalogue->findDrivers( dict, &generationCount ); 163 if ( set && (set->getCount() > 0)) 164 found = true; 165 166 } while( false ); 167 168 if( dict) 169 dict->release(); 170 if( set) 171 set->release(); 172 173 return( found ); 174 } 175 176 OSDictionary * IOBSDNameMatching( const char * name ) 177 { 178 OSDictionary * dict; 179 const OSSymbol * str = 0; 180 181 do { 182 183 dict = IOService::serviceMatching( gIOServiceKey ); 184 if( !dict) 185 continue; 186 str = OSSymbol::withCString( name ); 187 if( !str) 188 continue; 189 dict->setObject( kIOBSDNameKey, (OSObject *) str ); 190 str->release(); 191 192 return( dict ); 193 194 } while( false ); 195 196 if( dict) 197 dict->release(); 198 if( str) 199 str->release(); 200 201 return( 0 ); 202 } 203 204 OSDictionary * IOUUIDMatching( void ) 205 { 206 return IOService::resourceMatching( "boot-uuid-media" ); 207 } 208 209 OSDictionary * IONetworkNamePrefixMatching( const char * prefix ) 210 { 211 OSDictionary * matching; 212 OSDictionary * propDict = 0; 213 const OSSymbol * str = 0; 214 char networkType[128]; 215 216 do { 217 matching = IOService::serviceMatching( "IONetworkInterface" ); 218 if ( matching == 0 ) 219 continue; 220 221 propDict = OSDictionary::withCapacity(1); 222 if ( propDict == 0 ) 223 continue; 224 225 str = OSSymbol::withCString( prefix ); 226 if ( str == 0 ) 227 continue; 228 229 propDict->setObject( "IOInterfaceNamePrefix", (OSObject *) str ); 230 str->release(); 231 str = 0; 232 233 // see if we're contrained to netroot off of specific network type 234 if(PE_parse_boot_argn( "network-type", networkType, 128 )) 235 { 236 str = OSSymbol::withCString( networkType ); 237 if(str) 238 { 239 propDict->setObject( "IONetworkRootType", str); 240 str->release(); 241 str = 0; 242 } 243 } 244 245 if ( matching->setObject( gIOPropertyMatchKey, 246 (OSObject *) propDict ) != true ) 247 continue; 248 249 propDict->release(); 250 propDict = 0; 251 252 return( matching ); 253 254 } while ( false ); 255 256 if ( matching ) matching->release(); 257 if ( propDict ) propDict->release(); 258 if ( str ) str->release(); 259 260 return( 0 ); 261 } 262 263 static bool IORegisterNetworkInterface( IOService * netif ) 264 { 265 // A network interface is typically named and registered 266 // with BSD after receiving a request from a user space 267 // "namer". However, for cases when the system needs to 268 // root from the network, this registration task must be 269 // done inside the kernel and completed before the root 270 // device is handed to BSD. 271 272 IOService * stack; 273 OSNumber * zero = 0; 274 OSString * path = 0; 275 OSDictionary * dict = 0; 276 char * pathBuf = 0; 277 int len; 278 enum { kMaxPathLen = 512 }; 279 280 do { 281 stack = IOService::waitForService( 282 IOService::serviceMatching("IONetworkStack") ); 283 if ( stack == 0 ) break; 284 285 dict = OSDictionary::withCapacity(3); 286 if ( dict == 0 ) break; 287 288 zero = OSNumber::withNumber((UInt64) 0, 32); 289 if ( zero == 0 ) break; 290 291 pathBuf = (char *) IOMalloc( kMaxPathLen ); 292 if ( pathBuf == 0 ) break; 293 294 len = kMaxPathLen; 295 if ( netif->getPath( pathBuf, &len, gIOServicePlane ) 296 == false ) break; 297 298 path = OSString::withCStringNoCopy( pathBuf ); 299 if ( path == 0 ) break; 300 301 dict->setObject( "IOInterfaceUnit", zero ); 302 dict->setObject( kIOPathMatchKey, path ); 303 304 stack->setProperties( dict ); 305 } 306 while ( false ); 307 308 if ( zero ) zero->release(); 309 if ( path ) path->release(); 310 if ( dict ) dict->release(); 311 if ( pathBuf ) IOFree(pathBuf, kMaxPathLen); 312 313 return ( netif->getProperty( kIOBSDNameKey ) != 0 ); 314 } 315 316 OSDictionary * IOOFPathMatching( const char * path, char * buf, int maxLen ) 317 { 318 OSDictionary * matching = NULL; 319 OSString * str; 320 char * comp; 321 int len; 322 323 do { 324 325 len = strlen( kIODeviceTreePlane ":" ); 326 maxLen -= len; 327 if( maxLen <= 0) 328 continue; 329 330 strlcpy( buf, kIODeviceTreePlane ":", len + 1 ); 331 comp = buf + len; 332 333 len = strlen( path ); 334 maxLen -= len; 335 if( maxLen <= 0) 336 continue; 337 strlcpy( comp, path, len + 1 ); 338 339 matching = OSDictionary::withCapacity( 1 ); 340 if( !matching) 341 continue; 342 343 str = OSString::withCString( buf ); 344 if( !str) 345 continue; 346 matching->setObject( kIOPathMatchKey, str ); 347 str->release(); 348 349 return( matching ); 350 351 } while( false ); 352 353 if( matching) 354 matching->release(); 355 356 return( 0 ); 357 } 358 359 static int didRam = 0; 360 enum { kMaxPathBuf = 512, kMaxBootVar = 128 }; 361 362 kern_return_t IOFindBSDRoot( char * rootName, unsigned int rootNameSize, 363 dev_t * root, u_int32_t * oflags ) 364 { 365 mach_timespec_t t; 366 IOService * service; 367 IORegistryEntry * regEntry; 368 OSDictionary * matching = 0; 369 OSString * iostr; 370 OSNumber * off; 371 OSData * data = 0; 372 373 UInt32 flags = 0; 374 int mnr, mjr; 375 const char * mediaProperty = 0; 376 char * rdBootVar; 377 char * str; 378 const char * look = 0; 379 int len; 380 bool debugInfoPrintedOnce = false; 381 const char * uuidStr = NULL; 382 383 static int mountAttempts = 0; 384 385 int xchar, dchar; 386 387 // stall here for anyone matching on the IOBSD resource to finish (filesystems) 388 matching = IOService::serviceMatching(gIOResourcesKey); 389 assert(matching); 390 matching->setObject(gIOResourceMatchedKey, gIOBSDKey); 391 392 if ((service = IOService::waitForMatchingService(matching, 30ULL * kSecondScale))) { 393 service->release(); 394 } else { 395 IOLog("!BSD\n"); 396 } 397 matching->release(); 398 matching = NULL; 399 400 if( mountAttempts++) 401 { 402 IOLog("mount(%d) failed\n", mountAttempts); 403 IOSleep( 5 * 1000 ); 404 } 405 406 str = (char *) IOMalloc( kMaxPathBuf + kMaxBootVar ); 407 if( !str) 408 return( kIOReturnNoMemory ); 409 rdBootVar = str + kMaxPathBuf; 410 411 if (!PE_parse_boot_argn("rd", rdBootVar, kMaxBootVar ) 412 && !PE_parse_boot_argn("rootdev", rdBootVar, kMaxBootVar )) 413 rdBootVar[0] = 0; 414 415 do { 416 if( (regEntry = IORegistryEntry::fromPath( "/chosen", gIODTPlane ))) { 417 di_root_ramfile(regEntry); 418 data = OSDynamicCast(OSData, regEntry->getProperty( "root-matching" )); 419 if (data) { 420 matching = OSDynamicCast(OSDictionary, OSUnserializeXML((char *)data->getBytesNoCopy())); 421 if (matching) { 422 continue; 423 } 424 } 425 426 data = (OSData *) regEntry->getProperty( "boot-uuid" ); 427 if( data) { 428 uuidStr = (const char*)data->getBytesNoCopy(); 429 OSString *uuidString = OSString::withCString( uuidStr ); 430 431 // match the boot-args boot-uuid processing below 432 if( uuidString) { 433 IOLog("rooting via boot-uuid from /chosen: %s\n", uuidStr); 434 IOService::publishResource( "boot-uuid", uuidString ); 435 uuidString->release(); 436 matching = IOUUIDMatching(); 437 mediaProperty = "boot-uuid-media"; 438 regEntry->release(); 439 continue; 440 } else { 441 uuidStr = NULL; 442 } 443 } 444 regEntry->release(); 445 } 446 } while( false ); 447 448 // 449 // See if we have a RAMDisk property in /chosen/memory-map. If so, make it into a device. 450 // It will become /dev/mdx, where x is 0-f. 451 // 452 453 if(!didRam) { /* Have we already build this ram disk? */ 454 didRam = 1; /* Remember we did this */ 455 if((regEntry = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane ))) { /* Find the map node */ 456 data = (OSData *)regEntry->getProperty("RAMDisk"); /* Find the ram disk, if there */ 457 if(data) { /* We found one */ 458 uintptr_t *ramdParms; 459 ramdParms = (uintptr_t *)data->getBytesNoCopy(); /* Point to the ram disk base and size */ 460 (void)mdevadd(-1, ml_static_ptovirt(ramdParms[0]) >> 12, ramdParms[1] >> 12, 0); /* Initialize it and pass back the device number */ 461 } 462 regEntry->release(); /* Toss the entry */ 463 } 464 } 465 466 // 467 // Now check if we are trying to root on a memory device 468 // 469 470 if((rdBootVar[0] == 'm') && (rdBootVar[1] == 'd') && (rdBootVar[3] == 0)) { 471 dchar = xchar = rdBootVar[2]; /* Get the actual device */ 472 if((xchar >= '0') && (xchar <= '9')) xchar = xchar - '0'; /* If digit, convert */ 473 else { 474 xchar = xchar & ~' '; /* Fold to upper case */ 475 if((xchar >= 'A') && (xchar <= 'F')) { /* Is this a valid digit? */ 476 xchar = (xchar & 0xF) + 9; /* Convert the hex digit */ 477 dchar = dchar | ' '; /* Fold to lower case */ 478 } 479 else xchar = -1; /* Show bogus */ 480 } 481 if(xchar >= 0) { /* Do we have a valid memory device name? */ 482 *root = mdevlookup(xchar); /* Find the device number */ 483 if(*root >= 0) { /* Did we find one? */ 484 rootName[0] = 'm'; /* Build root name */ 485 rootName[1] = 'd'; /* Build root name */ 486 rootName[2] = dchar; /* Build root name */ 487 rootName[3] = 0; /* Build root name */ 488 IOLog("BSD root: %s, major %d, minor %d\n", rootName, major(*root), minor(*root)); 489 *oflags = 0; /* Show that this is not network */ 490 491 #if CONFIG_KDP_INTERACTIVE_DEBUGGING 492 /* retrieve final ramdisk range and initialize KDP variables */ 493 if (mdevgetrange(xchar, &kdp_core_ramdisk_addr, &kdp_core_ramdisk_size) != 0) { 494 IOLog("Unable to retrieve range for root memory device %d\n", xchar); 495 kdp_core_ramdisk_addr = 0; 496 kdp_core_ramdisk_size = 0; 497 } 498 #endif 499 500 goto iofrootx; /* Join common exit... */ 501 } 502 panic("IOFindBSDRoot: specified root memory device, %s, has not been configured\n", rdBootVar); /* Not there */ 503 } 504 } 505 506 if( (!matching) && rdBootVar[0] ) { 507 // by BSD name 508 look = rdBootVar; 509 if( look[0] == '*') 510 look++; 511 512 if ( strncmp( look, "en", strlen( "en" )) == 0 ) { 513 matching = IONetworkNamePrefixMatching( "en" ); 514 } else if ( strncmp( look, "uuid", strlen( "uuid" )) == 0 ) { 515 char *uuid; 516 OSString *uuidString; 517 518 uuid = (char *)IOMalloc( kMaxBootVar ); 519 520 if ( uuid ) { 521 if (!PE_parse_boot_argn( "boot-uuid", uuid, kMaxBootVar )) { 522 panic( "rd=uuid but no boot-uuid=<value> specified" ); 523 } 524 uuidString = OSString::withCString( uuid ); 525 if ( uuidString ) { 526 IOService::publishResource( "boot-uuid", uuidString ); 527 uuidString->release(); 528 IOLog( "\nWaiting for boot volume with UUID %s\n", uuid ); 529 matching = IOUUIDMatching(); 530 mediaProperty = "boot-uuid-media"; 531 } 532 IOFree( uuid, kMaxBootVar ); 533 } 534 } else { 535 matching = IOBSDNameMatching( look ); 536 } 537 } 538 539 if( !matching) { 540 OSString * astring; 541 // Match any HFS media 542 543 matching = IOService::serviceMatching( "IOMedia" ); 544 astring = OSString::withCStringNoCopy("Apple_HFS"); 545 if ( astring ) { 546 matching->setObject("Content", astring); 547 astring->release(); 548 } 549 } 550 551 if( gIOKitDebug & kIOWaitQuietBeforeRoot ) { 552 IOLog( "Waiting for matching to complete\n" ); 553 IOService::getPlatform()->waitQuiet(); 554 } 555 556 if( true && matching) { 557 OSSerialize * s = OSSerialize::withCapacity( 5 ); 558 559 if( matching->serialize( s )) { 560 IOLog( "Waiting on %s\n", s->text() ); 561 s->release(); 562 } 563 } 564 565 do { 566 t.tv_sec = ROOTDEVICETIMEOUT; 567 t.tv_nsec = 0; 568 matching->retain(); 569 service = IOService::waitForService( matching, &t ); 570 if( (!service) || (mountAttempts == 10)) { 571 PE_display_icon( 0, "noroot"); 572 IOLog( "Still waiting for root device\n" ); 573 574 if( !debugInfoPrintedOnce) { 575 debugInfoPrintedOnce = true; 576 if( gIOKitDebug & kIOLogDTree) { 577 IOLog("\nDT plane:\n"); 578 IOPrintPlane( gIODTPlane ); 579 } 580 if( gIOKitDebug & kIOLogServiceTree) { 581 IOLog("\nService plane:\n"); 582 IOPrintPlane( gIOServicePlane ); 583 } 584 if( gIOKitDebug & kIOLogMemory) 585 IOPrintMemory(); 586 } 587 } 588 } while( !service); 589 matching->release(); 590 591 if ( service && mediaProperty ) { 592 service = (IOService *)service->getProperty(mediaProperty); 593 } 594 595 mjr = 0; 596 mnr = 0; 597 598 // If the IOService we matched to is a subclass of IONetworkInterface, 599 // then make sure it has been registered with BSD and has a BSD name 600 // assigned. 601 602 if ( service 603 && service->metaCast( "IONetworkInterface" ) 604 && !IORegisterNetworkInterface( service ) ) 605 { 606 service = 0; 607 } 608 609 if( service) { 610 611 len = kMaxPathBuf; 612 service->getPath( str, &len, gIOServicePlane ); 613 IOLog( "Got boot device = %s\n", str ); 614 615 iostr = (OSString *) service->getProperty( kIOBSDNameKey ); 616 if( iostr) 617 strlcpy( rootName, iostr->getCStringNoCopy(), rootNameSize ); 618 off = (OSNumber *) service->getProperty( kIOBSDMajorKey ); 619 if( off) 620 mjr = off->unsigned32BitValue(); 621 off = (OSNumber *) service->getProperty( kIOBSDMinorKey ); 622 if( off) 623 mnr = off->unsigned32BitValue(); 624 625 if( service->metaCast( "IONetworkInterface" )) 626 flags |= 1; 627 628 } else { 629 630 IOLog( "Wait for root failed\n" ); 631 strlcpy( rootName, "en0", rootNameSize ); 632 flags |= 1; 633 } 634 635 IOLog( "BSD root: %s", rootName ); 636 if( mjr) 637 IOLog(", major %d, minor %d\n", mjr, mnr ); 638 else 639 IOLog("\n"); 640 641 *root = makedev( mjr, mnr ); 642 *oflags = flags; 643 644 IOFree( str, kMaxPathBuf + kMaxBootVar ); 645 646 iofrootx: 647 if( (gIOKitDebug & (kIOLogDTree | kIOLogServiceTree | kIOLogMemory)) && !debugInfoPrintedOnce) { 648 649 IOService::getPlatform()->waitQuiet(); 650 if( gIOKitDebug & kIOLogDTree) { 651 IOLog("\nDT plane:\n"); 652 IOPrintPlane( gIODTPlane ); 653 } 654 if( gIOKitDebug & kIOLogServiceTree) { 655 IOLog("\nService plane:\n"); 656 IOPrintPlane( gIOServicePlane ); 657 } 658 if( gIOKitDebug & kIOLogMemory) 659 IOPrintMemory(); 660 } 661 662 return( kIOReturnSuccess ); 663 } 664 665 bool IORamDiskBSDRoot(void) 666 { 667 char rdBootVar[kMaxBootVar]; 668 if (PE_parse_boot_argn("rd", rdBootVar, kMaxBootVar ) 669 || PE_parse_boot_argn("rootdev", rdBootVar, kMaxBootVar )) { 670 if((rdBootVar[0] == 'm') && (rdBootVar[1] == 'd') && (rdBootVar[3] == 0)) { 671 return true; 672 } 673 } 674 return false; 675 } 676 677 void IOSecureBSDRoot(const char * rootName) 678 { 679 #if CONFIG_EMBEDDED 680 int tmpInt; 681 IOReturn result; 682 IOPlatformExpert *pe; 683 OSDictionary *matching; 684 const OSSymbol *functionName = OSSymbol::withCStringNoCopy("SecureRootName"); 685 686 matching = IOService::serviceMatching("IOPlatformExpert"); 687 assert(matching); 688 pe = (IOPlatformExpert *) IOService::waitForMatchingService(matching, 30ULL * kSecondScale); 689 matching->release(); 690 assert(pe); 691 // Returns kIOReturnNotPrivileged is the root device is not secure. 692 // Returns kIOReturnUnsupported if "SecureRootName" is not implemented. 693 result = pe->callPlatformFunction(functionName, false, (void *)rootName, (void *)0, (void *)0, (void *)0); 694 functionName->release(); 695 OSSafeReleaseNULL(pe); 696 697 if (result == kIOReturnNotPrivileged) { 698 mdevremoveall(); 699 } else if (result == kIOReturnSuccess) { 700 // If we are booting with a secure root, and we have the right 701 // boot-arg, we will want to panic on exception triage. This 702 // behavior is intended as a debug aid (we can look at why an 703 // exception occured in the kernel debugger). 704 if (PE_parse_boot_argn("-panic_on_exception_triage", &tmpInt, sizeof(tmpInt))) { 705 panic_on_exception_triage = 1; 706 } 707 } 708 709 #endif // CONFIG_EMBEDDED 710 } 711 712 void * 713 IOBSDRegistryEntryForDeviceTree(char * path) 714 { 715 return (IORegistryEntry::fromPath(path, gIODTPlane)); 716 } 717 718 void 719 IOBSDRegistryEntryRelease(void * entry) 720 { 721 IORegistryEntry * regEntry = (IORegistryEntry *)entry; 722 723 if (regEntry) 724 regEntry->release(); 725 return; 726 } 727 728 const void * 729 IOBSDRegistryEntryGetData(void * entry, char * property_name, 730 int * packet_length) 731 { 732 OSData * data; 733 IORegistryEntry * regEntry = (IORegistryEntry *)entry; 734 735 data = (OSData *) regEntry->getProperty(property_name); 736 if (data) { 737 *packet_length = data->getLength(); 738 return (data->getBytesNoCopy()); 739 } 740 return (NULL); 741 } 742 743 kern_return_t IOBSDGetPlatformUUID( uuid_t uuid, mach_timespec_t timeout ) 744 { 745 IOService * resources; 746 OSString * string; 747 748 resources = IOService::waitForService( IOService::resourceMatching( kIOPlatformUUIDKey ), ( timeout.tv_sec || timeout.tv_nsec ) ? &timeout : 0 ); 749 if ( resources == 0 ) return KERN_OPERATION_TIMED_OUT; 750 751 string = ( OSString * ) IOService::getPlatform( )->getProvider( )->getProperty( kIOPlatformUUIDKey ); 752 if ( string == 0 ) return KERN_NOT_SUPPORTED; 753 754 uuid_parse( string->getCStringNoCopy( ), uuid ); 755 756 return KERN_SUCCESS; 757 } 758 759 } /* extern "C" */ 760 761 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 762 763 #include <sys/conf.h> 764 #include <sys/vnode.h> 765 #include <sys/vnode_internal.h> 766 #include <sys/fcntl.h> 767 #include <IOKit/IOPolledInterface.h> 768 #include <IOKit/IOBufferMemoryDescriptor.h> 769 770 IOPolledFileIOVars * gIOPolledCoreFileVars; 771 kern_return_t gIOPolledCoreFileOpenRet = kIOReturnNotReady; 772 #if IOPOLLED_COREFILE 773 774 static IOReturn 775 IOOpenPolledCoreFile(const char * filename) 776 { 777 IOReturn err; 778 unsigned int debug; 779 uint64_t corefile_size_bytes = 0; 780 781 if (gIOPolledCoreFileVars) return (kIOReturnBusy); 782 if (!IOPolledInterface::gMetaClass.getInstanceCount()) return (kIOReturnUnsupported); 783 784 debug = 0; 785 PE_parse_boot_argn("debug", &debug, sizeof (debug)); 786 if (DB_DISABLE_LOCAL_CORE & debug) return (kIOReturnUnsupported); 787 788 #if CONFIG_EMBEDDED 789 unsigned int requested_corefile_size = 0; 790 if (PE_parse_boot_argn("corefile_size_mb", &requested_corefile_size, sizeof(requested_corefile_size))) { 791 IOLog("Boot-args specify %d MB kernel corefile\n", requested_corefile_size); 792 793 corefile_size_bytes = (requested_corefile_size * 1024ULL * 1024ULL); 794 } 795 #endif 796 797 798 do { 799 #if defined(kIOCoreDumpLargeSize) 800 if (0 == corefile_size_bytes) 801 { 802 // If no custom size was requested and we're on a device with >3GB of DRAM, attempt 803 // to allocate a large corefile otherwise use a small file. 804 if (max_mem > (3 * 1024ULL * 1024ULL * 1024ULL)) 805 { 806 corefile_size_bytes = kIOCoreDumpLargeSize; 807 err = IOPolledFileOpen(filename, 808 kIOPolledFileCreate, 809 corefile_size_bytes, kIOCoreDumpFreeSize, 810 NULL, 0, 811 &gIOPolledCoreFileVars, NULL, NULL, 0); 812 if (kIOReturnSuccess == err) 813 { 814 break; 815 } 816 else if (kIOReturnNoSpace == err) 817 { 818 IOLog("Failed to open corefile of size %llu MB (low disk space)", 819 (corefile_size_bytes / (1024ULL * 1024ULL))); 820 if (corefile_size_bytes == kIOCoreDumpMinSize) 821 { 822 gIOPolledCoreFileOpenRet = err; 823 return (err); 824 } 825 // Try to open a smaller corefile (set size and fall-through) 826 corefile_size_bytes = kIOCoreDumpMinSize; 827 } 828 else 829 { 830 IOLog("Failed to open corefile of size %llu MB (returned error 0x%x)\n", 831 (corefile_size_bytes / (1024ULL * 1024ULL)), err); 832 gIOPolledCoreFileOpenRet = err; 833 return (err); 834 } 835 } 836 else 837 { 838 corefile_size_bytes = kIOCoreDumpMinSize; 839 } 840 } 841 #else /* defined(kIOCoreDumpLargeSize) */ 842 if (0 == corefile_size_bytes) 843 { 844 corefile_size_bytes = kIOCoreDumpSize; 845 } 846 #endif /* defined(kIOCoreDumpLargeSize) */ 847 err = IOPolledFileOpen(filename, 848 kIOPolledFileCreate, 849 corefile_size_bytes, kIOCoreDumpFreeSize, 850 NULL, 0, 851 &gIOPolledCoreFileVars, NULL, NULL, 0); 852 if (kIOReturnSuccess != err) 853 { 854 IOLog("Failed to open corefile of size %llu MB (returned error 0x%x)\n", 855 (corefile_size_bytes / (1024ULL * 1024ULL)), err); 856 gIOPolledCoreFileOpenRet = err; 857 return (err); 858 } 859 } while (false); 860 861 err = IOPolledFilePollersSetup(gIOPolledCoreFileVars, kIOPolledPreflightCoreDumpState); 862 if (kIOReturnSuccess != err) 863 { 864 IOPolledFileClose(&gIOPolledCoreFileVars, NULL, NULL, 0, 0, 0); 865 IOLog("IOPolledFilePollersSetup for corefile failed with error: 0x%x\n", err); 866 gIOPolledCoreFileOpenRet = err; 867 } 868 else 869 { 870 IOLog("Opened corefile of size %llu MB\n", (corefile_size_bytes / (1024ULL * 1024ULL))); 871 } 872 873 return (err); 874 } 875 876 static void 877 IOClosePolledCoreFile(void) 878 { 879 gIOPolledCoreFileOpenRet = kIOReturnNotOpen; 880 IOPolledFilePollersClose(gIOPolledCoreFileVars, kIOPolledPostflightCoreDumpState); 881 IOPolledFileClose(&gIOPolledCoreFileVars, NULL, NULL, 0, 0, 0); 882 } 883 884 static thread_call_t gIOOpenPolledCoreFileTC; 885 static IONotifier * gIOPolledCoreFileNotifier; 886 static IONotifier * gIOPolledCoreFileInterestNotifier; 887 888 static IOReturn 889 KernelCoreMediaInterest(void * target, void * refCon, 890 UInt32 messageType, IOService * provider, 891 void * messageArgument, vm_size_t argSize ) 892 { 893 if (kIOMessageServiceIsTerminated == messageType) 894 { 895 gIOPolledCoreFileInterestNotifier->remove(); 896 gIOPolledCoreFileInterestNotifier = 0; 897 IOClosePolledCoreFile(); 898 } 899 900 return (kIOReturnSuccess); 901 } 902 903 static void 904 OpenKernelCoreMedia(thread_call_param_t p0, thread_call_param_t p1) 905 { 906 IOService * newService; 907 OSString * string; 908 char filename[16]; 909 910 newService = (IOService *) p1; 911 do 912 { 913 if (gIOPolledCoreFileVars) break; 914 string = OSDynamicCast(OSString, newService->getProperty(kIOBSDNameKey)); 915 if (!string) break; 916 snprintf(filename, sizeof(filename), "/dev/%s", string->getCStringNoCopy()); 917 if (kIOReturnSuccess != IOOpenPolledCoreFile(filename)) break; 918 gIOPolledCoreFileInterestNotifier = newService->registerInterest( 919 gIOGeneralInterest, &KernelCoreMediaInterest, NULL, 0); 920 } 921 while (false); 922 923 newService->release(); 924 } 925 926 static bool 927 NewKernelCoreMedia(void * target, void * refCon, 928 IOService * newService, 929 IONotifier * notifier) 930 { 931 static volatile UInt32 onlyOneCorePartition = 0; 932 do 933 { 934 if (!OSCompareAndSwap(0, 1, &onlyOneCorePartition)) break; 935 if (gIOPolledCoreFileVars) break; 936 if (!gIOOpenPolledCoreFileTC) break; 937 newService = newService->getProvider(); 938 if (!newService) break; 939 newService->retain(); 940 thread_call_enter1(gIOOpenPolledCoreFileTC, newService); 941 } 942 while (false); 943 944 return (false); 945 } 946 947 #endif /* IOPOLLED_COREFILE */ 948 949 extern "C" void 950 IOBSDMountChange(struct mount * mp, uint32_t op) 951 { 952 #if IOPOLLED_COREFILE 953 954 OSDictionary * bsdMatching; 955 OSDictionary * mediaMatching; 956 OSString * string; 957 958 if (!gIOPolledCoreFileNotifier) do 959 { 960 if (!gIOOpenPolledCoreFileTC) gIOOpenPolledCoreFileTC = thread_call_allocate(&OpenKernelCoreMedia, NULL); 961 bsdMatching = IOService::serviceMatching("IOMediaBSDClient"); 962 if (!bsdMatching) break; 963 mediaMatching = IOService::serviceMatching("IOMedia"); 964 string = OSString::withCStringNoCopy("5361644D-6163-11AA-AA11-00306543ECAC"); 965 if (!string || !mediaMatching) break; 966 mediaMatching->setObject("Content", string); 967 string->release(); 968 bsdMatching->setObject(gIOParentMatchKey, mediaMatching); 969 mediaMatching->release(); 970 971 gIOPolledCoreFileNotifier = IOService::addMatchingNotification( 972 gIOFirstMatchNotification, bsdMatching, 973 &NewKernelCoreMedia, NULL, NULL, -1000); 974 } 975 while (false); 976 977 #if CONFIG_EMBEDDED 978 uint64_t flags; 979 char path[128]; 980 int pathLen; 981 vnode_t vn; 982 int result; 983 984 switch (op) 985 { 986 case kIOMountChangeMount: 987 case kIOMountChangeDidResize: 988 989 if (gIOPolledCoreFileVars) break; 990 flags = vfs_flags(mp); 991 if (MNT_RDONLY & flags) break; 992 if (!(MNT_LOCAL & flags)) break; 993 994 vn = vfs_vnodecovered(mp); 995 if (!vn) break; 996 pathLen = sizeof(path); 997 result = vn_getpath(vn, &path[0], &pathLen); 998 vnode_put(vn); 999 if (0 != result) break; 1000 if (!pathLen) break; 1001 #if defined(XNU_TARGET_OS_BRIDGE) 1002 // on bridgeOS systems we put the core in /private/var/internal. We don't 1003 // want to match with /private/var because /private/var/internal is often mounted 1004 // over /private/var 1005 if ((pathLen - 1) < (int) strlen("/private/var/internal")) break; 1006 #endif 1007 if (0 != strncmp(path, kIOCoreDumpPath, pathLen - 1)) break; 1008 IOOpenPolledCoreFile(kIOCoreDumpPath); 1009 break; 1010 1011 case kIOMountChangeUnmount: 1012 case kIOMountChangeWillResize: 1013 if (gIOPolledCoreFileVars && (mp == kern_file_mount(gIOPolledCoreFileVars->fileRef))) 1014 { 1015 IOClosePolledCoreFile(); 1016 } 1017 break; 1018 } 1019 #endif /* CONFIG_EMBEDDED */ 1020 #endif /* IOPOLLED_COREFILE */ 1021 } 1022 1023 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 1024 1025 extern "C" boolean_t 1026 IOTaskHasEntitlement(task_t task, const char * entitlement) 1027 { 1028 OSObject * obj; 1029 obj = IOUserClient::copyClientEntitlement(task, entitlement); 1030 if (!obj) return (false); 1031 obj->release(); 1032 return (obj != kOSBooleanFalse); 1033 } 1034 1035