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