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