1 /* 2 * Copyright (c) 1998-2008 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 36 extern "C" { 37 38 #include <pexpert/pexpert.h> 39 #include <kern/clock.h> 40 #include <uuid/uuid.h> 41 42 // how long to wait for matching root device, secs 43 #if DEBUG 44 #define ROOTDEVICETIMEOUT 120 45 #else 46 #define ROOTDEVICETIMEOUT 60 47 #endif 48 49 extern dev_t mdevadd(int devid, uint64_t base, unsigned int size, int phys); 50 extern dev_t mdevlookup(int devid); 51 extern void mdevremoveall(void); 52 extern void di_root_ramfile(IORegistryEntry * entry); 53 54 kern_return_t 55 IOKitBSDInit( void ) 56 { 57 IOService::publishResource("IOBSD"); 58 59 return( kIOReturnSuccess ); 60 } 61 62 void 63 IOServicePublishResource( const char * property, boolean_t value ) 64 { 65 if ( value) 66 IOService::publishResource( property, kOSBooleanTrue ); 67 else 68 IOService::getResourceService()->removeProperty( property ); 69 } 70 71 boolean_t 72 IOServiceWaitForMatchingResource( const char * property, uint64_t timeout ) 73 { 74 OSDictionary * dict = 0; 75 IOService * match = 0; 76 boolean_t found = false; 77 78 do { 79 80 dict = IOService::resourceMatching( property ); 81 if( !dict) 82 continue; 83 match = IOService::waitForMatchingService( dict, timeout ); 84 if ( match) 85 found = true; 86 87 } while( false ); 88 89 if( dict) 90 dict->release(); 91 if( match) 92 match->release(); 93 94 return( found ); 95 } 96 97 boolean_t 98 IOCatalogueMatchingDriversPresent( const char * property ) 99 { 100 OSDictionary * dict = 0; 101 OSOrderedSet * set = 0; 102 SInt32 generationCount = 0; 103 boolean_t found = false; 104 105 do { 106 107 dict = OSDictionary::withCapacity(1); 108 if( !dict) 109 continue; 110 dict->setObject( property, kOSBooleanTrue ); 111 set = gIOCatalogue->findDrivers( dict, &generationCount ); 112 if ( set && (set->getCount() > 0)) 113 found = true; 114 115 } while( false ); 116 117 if( dict) 118 dict->release(); 119 if( set) 120 set->release(); 121 122 return( found ); 123 } 124 125 OSDictionary * IOBSDNameMatching( const char * name ) 126 { 127 OSDictionary * dict; 128 const OSSymbol * str = 0; 129 130 do { 131 132 dict = IOService::serviceMatching( gIOServiceKey ); 133 if( !dict) 134 continue; 135 str = OSSymbol::withCString( name ); 136 if( !str) 137 continue; 138 dict->setObject( kIOBSDNameKey, (OSObject *) str ); 139 str->release(); 140 141 return( dict ); 142 143 } while( false ); 144 145 if( dict) 146 dict->release(); 147 if( str) 148 str->release(); 149 150 return( 0 ); 151 } 152 153 OSDictionary * IOUUIDMatching( void ) 154 { 155 return IOService::resourceMatching( "boot-uuid-media" ); 156 } 157 158 159 OSDictionary * IOCDMatching( void ) 160 { 161 OSDictionary * dict; 162 const OSSymbol * str; 163 164 dict = IOService::serviceMatching( "IOMedia" ); 165 if( dict == 0 ) { 166 IOLog("Unable to find IOMedia\n"); 167 return 0; 168 } 169 170 str = OSSymbol::withCString( "CD_ROM_Mode_1" ); 171 if( str == 0 ) { 172 dict->release(); 173 return 0; 174 } 175 176 dict->setObject( "Content Hint", (OSObject *)str ); 177 str->release(); 178 return( dict ); 179 } 180 181 OSDictionary * IONetworkMatching( const char * path, 182 char * buf, int maxLen ) 183 { 184 OSDictionary * matching = 0; 185 OSDictionary * dict; 186 OSString * str; 187 char * comp; 188 const char * skip; 189 int len; 190 191 do { 192 193 len = strlen( kIODeviceTreePlane ":" ); 194 maxLen -= len; 195 if( maxLen <= 0) 196 continue; 197 198 strlcpy( buf, kIODeviceTreePlane ":", len + 1 ); 199 comp = buf + len; 200 201 // remove parameters following ':' from the path 202 skip = strchr( path, ':'); 203 if( !skip) 204 continue; 205 206 len = skip - path; 207 maxLen -= len; 208 if( maxLen <= 0) 209 continue; 210 strlcpy( comp, path, len + 1 ); 211 212 matching = IOService::serviceMatching( "IONetworkInterface" ); 213 if( !matching) 214 continue; 215 dict = IOService::addLocation( matching ); 216 if( !dict) 217 continue; 218 219 str = OSString::withCString( buf ); 220 if( !str) 221 continue; 222 dict->setObject( kIOPathMatchKey, str ); 223 str->release(); 224 225 return( matching ); 226 227 } while( false ); 228 229 if( matching) 230 matching->release(); 231 232 return( 0 ); 233 } 234 235 OSDictionary * IONetworkNamePrefixMatching( const char * prefix ) 236 { 237 OSDictionary * matching; 238 OSDictionary * propDict = 0; 239 const OSSymbol * str = 0; 240 char networkType[128]; 241 242 do { 243 matching = IOService::serviceMatching( "IONetworkInterface" ); 244 if ( matching == 0 ) 245 continue; 246 247 propDict = OSDictionary::withCapacity(1); 248 if ( propDict == 0 ) 249 continue; 250 251 str = OSSymbol::withCString( prefix ); 252 if ( str == 0 ) 253 continue; 254 255 propDict->setObject( "IOInterfaceNamePrefix", (OSObject *) str ); 256 str->release(); 257 str = 0; 258 259 // see if we're contrained to netroot off of specific network type 260 if(PE_parse_boot_argn( "network-type", networkType, 128 )) 261 { 262 str = OSSymbol::withCString( networkType ); 263 if(str) 264 { 265 propDict->setObject( "IONetworkRootType", str); 266 str->release(); 267 str = 0; 268 } 269 } 270 271 if ( matching->setObject( gIOPropertyMatchKey, 272 (OSObject *) propDict ) != true ) 273 continue; 274 275 propDict->release(); 276 propDict = 0; 277 278 return( matching ); 279 280 } while ( false ); 281 282 if ( matching ) matching->release(); 283 if ( propDict ) propDict->release(); 284 if ( str ) str->release(); 285 286 return( 0 ); 287 } 288 289 static bool IORegisterNetworkInterface( IOService * netif ) 290 { 291 // A network interface is typically named and registered 292 // with BSD after receiving a request from a user space 293 // "namer". However, for cases when the system needs to 294 // root from the network, this registration task must be 295 // done inside the kernel and completed before the root 296 // device is handed to BSD. 297 298 IOService * stack; 299 OSNumber * zero = 0; 300 OSString * path = 0; 301 OSDictionary * dict = 0; 302 char * pathBuf = 0; 303 int len; 304 enum { kMaxPathLen = 512 }; 305 306 do { 307 stack = IOService::waitForService( 308 IOService::serviceMatching("IONetworkStack") ); 309 if ( stack == 0 ) break; 310 311 dict = OSDictionary::withCapacity(3); 312 if ( dict == 0 ) break; 313 314 zero = OSNumber::withNumber((UInt64) 0, 32); 315 if ( zero == 0 ) break; 316 317 pathBuf = (char *) IOMalloc( kMaxPathLen ); 318 if ( pathBuf == 0 ) break; 319 320 len = kMaxPathLen; 321 if ( netif->getPath( pathBuf, &len, gIOServicePlane ) 322 == false ) break; 323 324 path = OSString::withCStringNoCopy( pathBuf ); 325 if ( path == 0 ) break; 326 327 dict->setObject( "IOInterfaceUnit", zero ); 328 dict->setObject( kIOPathMatchKey, path ); 329 330 stack->setProperties( dict ); 331 } 332 while ( false ); 333 334 if ( zero ) zero->release(); 335 if ( path ) path->release(); 336 if ( dict ) dict->release(); 337 if ( pathBuf ) IOFree(pathBuf, kMaxPathLen); 338 339 return ( netif->getProperty( kIOBSDNameKey ) != 0 ); 340 } 341 342 OSDictionary * IODiskMatching( const char * path, char * buf, int maxLen ) 343 { 344 const char * look; 345 const char * alias; 346 char * comp; 347 long unit = -1; 348 long partition = -1; 349 long lun = -1; 350 char c; 351 int len; 352 353 // scan the tail of the path for "@unit:partition" 354 do { 355 // Have to get the full path to the controller - an alias may 356 // tell us next to nothing, like "hd:8" 357 alias = IORegistryEntry::dealiasPath( &path, gIODTPlane ); 358 359 look = path + strlen( path); 360 c = ':'; 361 while( look != path) { 362 if( *(--look) == c) { 363 if( c == ':') { 364 partition = strtol( look + 1, 0, 0 ); 365 c = '@'; 366 } else if( c == '@') { 367 unit = strtol( look + 1, &comp, 16 ); 368 369 if( *comp == ',') { 370 lun = strtol( comp + 1, 0, 16 ); 371 } 372 373 c = '/'; 374 } else if( c == '/') { 375 c = 0; 376 break; 377 } 378 } 379 380 if( alias && (look == path)) { 381 path = alias; 382 look = path + strlen( path); 383 alias = 0; 384 } 385 } 386 if( c || unit == -1 || partition == -1) 387 continue; 388 389 len = strlen( "{" kIOPathMatchKey "='" kIODeviceTreePlane ":" ); 390 maxLen -= len; 391 if( maxLen <= 0) 392 continue; 393 394 snprintf( buf, len + 1, "{" kIOPathMatchKey "='" kIODeviceTreePlane ":" ); 395 comp = buf + len; 396 397 if( alias) { 398 len = strlen( alias ); 399 maxLen -= len; 400 if( maxLen <= 0) 401 continue; 402 403 strlcpy( comp, alias, len + 1 ); 404 comp += len; 405 } 406 407 if ( (look - path)) { 408 len = (look - path); 409 maxLen -= len; 410 if( maxLen <= 0) 411 continue; 412 413 strlcpy( comp, path, len + 1 ); 414 comp += len; 415 } 416 417 if ( lun != -1 ) 418 { 419 len = strlen( "/@hhhhhhhh,hhhhhhhh:dddddddddd';}" ); 420 maxLen -= len; 421 if( maxLen <= 0) 422 continue; 423 424 snprintf( comp, len + 1, "/@%lx,%lx:%ld';}", unit, lun, partition ); 425 } 426 else 427 { 428 len = strlen( "/@hhhhhhhh:dddddddddd';}" ); 429 maxLen -= len; 430 if( maxLen <= 0) 431 continue; 432 433 snprintf( comp, len + 1, "/@%lx:%ld';}", unit, partition ); 434 } 435 436 return( OSDynamicCast(OSDictionary, OSUnserialize( buf, 0 )) ); 437 438 } while( false ); 439 440 return( 0 ); 441 } 442 443 OSDictionary * IOOFPathMatching( const char * path, char * buf, int maxLen ) 444 { 445 OSDictionary * matching; 446 OSString * str; 447 char * comp; 448 int len; 449 450 /* need to look up path, get device type, 451 call matching help based on device type */ 452 453 matching = IODiskMatching( path, buf, maxLen ); 454 if( matching) 455 return( matching ); 456 457 do { 458 459 len = strlen( kIODeviceTreePlane ":" ); 460 maxLen -= len; 461 if( maxLen <= 0) 462 continue; 463 464 strlcpy( buf, kIODeviceTreePlane ":", len + 1 ); 465 comp = buf + len; 466 467 len = strlen( path ); 468 maxLen -= len; 469 if( maxLen <= 0) 470 continue; 471 strlcpy( comp, path, len + 1 ); 472 473 matching = OSDictionary::withCapacity( 1 ); 474 if( !matching) 475 continue; 476 477 str = OSString::withCString( buf ); 478 if( !str) 479 continue; 480 matching->setObject( kIOPathMatchKey, str ); 481 str->release(); 482 483 return( matching ); 484 485 } while( false ); 486 487 if( matching) 488 matching->release(); 489 490 return( 0 ); 491 } 492 493 IOService * IOFindMatchingChild( IOService * service ) 494 { 495 // find a matching child service 496 IOService * child = 0; 497 OSIterator * iter = service->getClientIterator(); 498 if ( iter ) { 499 while( ( child = (IOService *) iter->getNextObject() ) ) { 500 OSDictionary * dict = OSDictionary::withCapacity( 1 ); 501 if( dict == 0 ) { 502 iter->release(); 503 return 0; 504 } 505 const OSSymbol * str = OSSymbol::withCString( "Apple_HFS" ); 506 if( str == 0 ) { 507 dict->release(); 508 iter->release(); 509 return 0; 510 } 511 dict->setObject( "Content", (OSObject *)str ); 512 str->release(); 513 if ( child->compareProperty( dict, "Content" ) ) { 514 dict->release(); 515 break; 516 } 517 dict->release(); 518 IOService * subchild = IOFindMatchingChild( child ); 519 if ( subchild ) { 520 child = subchild; 521 break; 522 } 523 } 524 iter->release(); 525 } 526 return child; 527 } 528 529 static int didRam = 0; 530 531 kern_return_t IOFindBSDRoot( char * rootName, unsigned int rootNameSize, 532 dev_t * root, u_int32_t * oflags ) 533 { 534 mach_timespec_t t; 535 IOService * service; 536 IORegistryEntry * regEntry; 537 OSDictionary * matching = 0; 538 OSString * iostr; 539 OSNumber * off; 540 OSData * data = 0; 541 UInt32 *ramdParms = 0; 542 543 UInt32 flags = 0; 544 int mnr, mjr; 545 bool findHFSChild = false; 546 const char * mediaProperty = 0; 547 char * rdBootVar; 548 enum { kMaxPathBuf = 512, kMaxBootVar = 128 }; 549 char * str; 550 const char * look = 0; 551 int len; 552 bool forceNet = false; 553 bool debugInfoPrintedOnce = false; 554 const char * uuidStr = NULL; 555 556 static int mountAttempts = 0; 557 558 int xchar, dchar; 559 560 561 if( mountAttempts++) 562 IOSleep( 5 * 1000 ); 563 564 str = (char *) IOMalloc( kMaxPathBuf + kMaxBootVar ); 565 if( !str) 566 return( kIOReturnNoMemory ); 567 rdBootVar = str + kMaxPathBuf; 568 569 if (!PE_parse_boot_argn("rd", rdBootVar, kMaxBootVar ) 570 && !PE_parse_boot_argn("rootdev", rdBootVar, kMaxBootVar )) 571 rdBootVar[0] = 0; 572 573 do { 574 if( (regEntry = IORegistryEntry::fromPath( "/chosen", gIODTPlane ))) { 575 di_root_ramfile(regEntry); 576 data = OSDynamicCast(OSData, regEntry->getProperty( "root-matching" )); 577 if (data) { 578 matching = OSDynamicCast(OSDictionary, OSUnserializeXML((char *)data->getBytesNoCopy())); 579 if (matching) { 580 continue; 581 } 582 } 583 584 data = (OSData *) regEntry->getProperty( "boot-uuid" ); 585 if( data) { 586 uuidStr = (const char*)data->getBytesNoCopy(); 587 OSString *uuidString = OSString::withCString( uuidStr ); 588 589 // match the boot-args boot-uuid processing below 590 if( uuidString) { 591 IOLog("rooting via boot-uuid from /chosen: %s\n", uuidStr); 592 IOService::publishResource( "boot-uuid", uuidString ); 593 uuidString->release(); 594 matching = IOUUIDMatching(); 595 mediaProperty = "boot-uuid-media"; 596 regEntry->release(); 597 continue; 598 } else { 599 uuidStr = NULL; 600 } 601 } 602 603 // else try for an OF Path 604 data = (OSData *) regEntry->getProperty( "rootpath" ); 605 regEntry->release(); 606 if( data) continue; 607 } 608 if( (regEntry = IORegistryEntry::fromPath( "/options", gIODTPlane ))) { 609 data = (OSData *) regEntry->getProperty( "boot-file" ); 610 regEntry->release(); 611 if( data) continue; 612 } 613 } while( false ); 614 615 if( data && !uuidStr) 616 look = (const char *) data->getBytesNoCopy(); 617 618 if( rdBootVar[0] == '*') { 619 look = rdBootVar + 1; 620 forceNet = false; 621 } else { 622 if( (regEntry = IORegistryEntry::fromPath( "/", gIODTPlane ))) { 623 forceNet = (0 != regEntry->getProperty( "net-boot" )); 624 regEntry->release(); 625 } 626 } 627 628 629 630 // 631 // See if we have a RAMDisk property in /chosen/memory-map. If so, make it into a device. 632 // It will become /dev/mdx, where x is 0-f. 633 // 634 635 if(!didRam) { /* Have we already build this ram disk? */ 636 didRam = 1; /* Remember we did this */ 637 if((regEntry = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane ))) { /* Find the map node */ 638 data = (OSData *)regEntry->getProperty("RAMDisk"); /* Find the ram disk, if there */ 639 if(data) { /* We found one */ 640 641 ramdParms = (UInt32 *)data->getBytesNoCopy(); /* Point to the ram disk base and size */ 642 (void)mdevadd(-1, ml_static_ptovirt(ramdParms[0]) >> 12, ramdParms[1] >> 12, 0); /* Initialize it and pass back the device number */ 643 } 644 regEntry->release(); /* Toss the entry */ 645 } 646 } 647 648 // 649 // Now check if we are trying to root on a memory device 650 // 651 652 if((rdBootVar[0] == 'm') && (rdBootVar[1] == 'd') && (rdBootVar[3] == 0)) { 653 dchar = xchar = rdBootVar[2]; /* Get the actual device */ 654 if((xchar >= '0') && (xchar <= '9')) xchar = xchar - '0'; /* If digit, convert */ 655 else { 656 xchar = xchar & ~' '; /* Fold to upper case */ 657 if((xchar >= 'A') && (xchar <= 'F')) { /* Is this a valid digit? */ 658 xchar = (xchar & 0xF) + 9; /* Convert the hex digit */ 659 dchar = dchar | ' '; /* Fold to lower case */ 660 } 661 else xchar = -1; /* Show bogus */ 662 } 663 if(xchar >= 0) { /* Do we have a valid memory device name? */ 664 *root = mdevlookup(xchar); /* Find the device number */ 665 if(*root >= 0) { /* Did we find one? */ 666 667 rootName[0] = 'm'; /* Build root name */ 668 rootName[1] = 'd'; /* Build root name */ 669 rootName[2] = dchar; /* Build root name */ 670 rootName[3] = 0; /* Build root name */ 671 IOLog("BSD root: %s, major %d, minor %d\n", rootName, major(*root), minor(*root)); 672 *oflags = 0; /* Show that this is not network */ 673 goto iofrootx; /* Join common exit... */ 674 } 675 panic("IOFindBSDRoot: specified root memory device, %s, has not been configured\n", rdBootVar); /* Not there */ 676 } 677 } 678 679 if( look) { 680 // from OpenFirmware path 681 IOLog("From path: \"%s\", ", look); 682 683 if (!matching) { 684 if( forceNet || (0 == strncmp( look, "enet", strlen( "enet" ))) ) { 685 matching = IONetworkMatching( look, str, kMaxPathBuf ); 686 } else { 687 matching = IODiskMatching( look, str, kMaxPathBuf ); 688 } 689 } 690 } 691 692 if( (!matching) && rdBootVar[0] ) { 693 // by BSD name 694 look = rdBootVar; 695 if( look[0] == '*') 696 look++; 697 698 if ( strncmp( look, "en", strlen( "en" )) == 0 ) { 699 matching = IONetworkNamePrefixMatching( "en" ); 700 } else if ( strncmp( look, "cdrom", strlen( "cdrom" )) == 0 ) { 701 matching = IOCDMatching(); 702 findHFSChild = true; 703 } else if ( strncmp( look, "uuid", strlen( "uuid" )) == 0 ) { 704 char *uuid; 705 OSString *uuidString; 706 707 uuid = (char *)IOMalloc( kMaxBootVar ); 708 709 if ( uuid ) { 710 if (!PE_parse_boot_argn( "boot-uuid", uuid, kMaxBootVar )) { 711 panic( "rd=uuid but no boot-uuid=<value> specified" ); 712 } 713 uuidString = OSString::withCString( uuid ); 714 if ( uuidString ) { 715 IOService::publishResource( "boot-uuid", uuidString ); 716 uuidString->release(); 717 IOLog( "\nWaiting for boot volume with UUID %s\n", uuid ); 718 matching = IOUUIDMatching(); 719 mediaProperty = "boot-uuid-media"; 720 } 721 IOFree( uuid, kMaxBootVar ); 722 } 723 } else { 724 matching = IOBSDNameMatching( look ); 725 } 726 } 727 728 if( !matching) { 729 OSString * astring; 730 // Match any HFS media 731 732 matching = IOService::serviceMatching( "IOMedia" ); 733 astring = OSString::withCStringNoCopy("Apple_HFS"); 734 if ( astring ) { 735 matching->setObject("Content", astring); 736 astring->release(); 737 } 738 } 739 740 if( true && matching) { 741 OSSerialize * s = OSSerialize::withCapacity( 5 ); 742 743 if( matching->serialize( s )) { 744 IOLog( "Waiting on %s\n", s->text() ); 745 s->release(); 746 } 747 } 748 749 do { 750 t.tv_sec = ROOTDEVICETIMEOUT; 751 t.tv_nsec = 0; 752 matching->retain(); 753 service = IOService::waitForService( matching, &t ); 754 if( (!service) || (mountAttempts == 10)) { 755 PE_display_icon( 0, "noroot"); 756 IOLog( "Still waiting for root device\n" ); 757 758 if( !debugInfoPrintedOnce) { 759 debugInfoPrintedOnce = true; 760 if( gIOKitDebug & kIOLogDTree) { 761 IOLog("\nDT plane:\n"); 762 IOPrintPlane( gIODTPlane ); 763 } 764 if( gIOKitDebug & kIOLogServiceTree) { 765 IOLog("\nService plane:\n"); 766 IOPrintPlane( gIOServicePlane ); 767 } 768 if( gIOKitDebug & kIOLogMemory) 769 IOPrintMemory(); 770 } 771 } 772 } while( !service); 773 matching->release(); 774 775 if ( service && findHFSChild ) { 776 bool waiting = true; 777 uint64_t timeoutNS; 778 779 // wait for children services to finish registering 780 while ( waiting ) { 781 timeoutNS = ROOTDEVICETIMEOUT; 782 timeoutNS *= kSecondScale; 783 784 if ( (service->waitQuiet(timeoutNS) ) == kIOReturnSuccess) { 785 waiting = false; 786 } else { 787 IOLog( "Waiting for child registration\n" ); 788 } 789 } 790 // look for a subservice with an Apple_HFS child 791 IOService * subservice = IOFindMatchingChild( service ); 792 if ( subservice ) service = subservice; 793 } else if ( service && mediaProperty ) { 794 service = (IOService *)service->getProperty(mediaProperty); 795 } 796 797 mjr = 0; 798 mnr = 0; 799 800 // If the IOService we matched to is a subclass of IONetworkInterface, 801 // then make sure it has been registered with BSD and has a BSD name 802 // assigned. 803 804 if ( service 805 && service->metaCast( "IONetworkInterface" ) 806 && !IORegisterNetworkInterface( service ) ) 807 { 808 service = 0; 809 } 810 811 if( service) { 812 813 len = kMaxPathBuf; 814 service->getPath( str, &len, gIOServicePlane ); 815 IOLog( "Got boot device = %s\n", str ); 816 817 iostr = (OSString *) service->getProperty( kIOBSDNameKey ); 818 if( iostr) 819 strlcpy( rootName, iostr->getCStringNoCopy(), rootNameSize ); 820 off = (OSNumber *) service->getProperty( kIOBSDMajorKey ); 821 if( off) 822 mjr = off->unsigned32BitValue(); 823 off = (OSNumber *) service->getProperty( kIOBSDMinorKey ); 824 if( off) 825 mnr = off->unsigned32BitValue(); 826 827 if( service->metaCast( "IONetworkInterface" )) 828 flags |= 1; 829 830 } else { 831 832 IOLog( "Wait for root failed\n" ); 833 strlcpy( rootName, "en0", rootNameSize ); 834 flags |= 1; 835 } 836 837 IOLog( "BSD root: %s", rootName ); 838 if( mjr) 839 IOLog(", major %d, minor %d\n", mjr, mnr ); 840 else 841 IOLog("\n"); 842 843 *root = makedev( mjr, mnr ); 844 *oflags = flags; 845 846 IOFree( str, kMaxPathBuf + kMaxBootVar ); 847 848 iofrootx: 849 if( (gIOKitDebug & (kIOLogDTree | kIOLogServiceTree | kIOLogMemory)) && !debugInfoPrintedOnce) { 850 851 IOService::getPlatform()->waitQuiet(); 852 if( gIOKitDebug & kIOLogDTree) { 853 IOLog("\nDT plane:\n"); 854 IOPrintPlane( gIODTPlane ); 855 } 856 if( gIOKitDebug & kIOLogServiceTree) { 857 IOLog("\nService plane:\n"); 858 IOPrintPlane( gIOServicePlane ); 859 } 860 if( gIOKitDebug & kIOLogMemory) 861 IOPrintMemory(); 862 } 863 864 return( kIOReturnSuccess ); 865 } 866 867 void IOSecureBSDRoot(const char * rootName) 868 { 869 #if CONFIG_EMBEDDED 870 IOReturn result; 871 IOPlatformExpert *pe; 872 const OSSymbol *functionName = OSSymbol::withCStringNoCopy("SecureRootName"); 873 874 while ((pe = IOService::getPlatform()) == 0) IOSleep(1 * 1000); 875 876 // Returns kIOReturnNotPrivileged is the root device is not secure. 877 // Returns kIOReturnUnsupported if "SecureRootName" is not implemented. 878 result = pe->callPlatformFunction(functionName, false, (void *)rootName, (void *)0, (void *)0, (void *)0); 879 880 functionName->release(); 881 882 if (result == kIOReturnNotPrivileged) mdevremoveall(); 883 #endif 884 } 885 886 void * 887 IOBSDRegistryEntryForDeviceTree(char * path) 888 { 889 return (IORegistryEntry::fromPath(path, gIODTPlane)); 890 } 891 892 void 893 IOBSDRegistryEntryRelease(void * entry) 894 { 895 IORegistryEntry * regEntry = (IORegistryEntry *)entry; 896 897 if (regEntry) 898 regEntry->release(); 899 return; 900 } 901 902 const void * 903 IOBSDRegistryEntryGetData(void * entry, char * property_name, 904 int * packet_length) 905 { 906 OSData * data; 907 IORegistryEntry * regEntry = (IORegistryEntry *)entry; 908 909 data = (OSData *) regEntry->getProperty(property_name); 910 if (data) { 911 *packet_length = data->getLength(); 912 return (data->getBytesNoCopy()); 913 } 914 return (NULL); 915 } 916 917 kern_return_t IOBSDGetPlatformUUID( uuid_t uuid, mach_timespec_t timeout ) 918 { 919 IOService * resources; 920 OSString * string; 921 922 resources = IOService::waitForService( IOService::resourceMatching( kIOPlatformUUIDKey ), ( timeout.tv_sec || timeout.tv_nsec ) ? &timeout : 0 ); 923 if ( resources == 0 ) return KERN_OPERATION_TIMED_OUT; 924 925 string = ( OSString * ) IOService::getPlatform( )->getProvider( )->getProperty( kIOPlatformUUIDKey ); 926 if ( string == 0 ) return KERN_NOT_SUPPORTED; 927 928 uuid_parse( string->getCStringNoCopy( ), uuid ); 929 930 return KERN_SUCCESS; 931 } 932 933 kern_return_t IOBSDGetPlatformSerialNumber( char *serial_number_str, u_int32_t len ) 934 { 935 OSDictionary * platform_dict; 936 IOService *platform; 937 OSString * string; 938 939 if (len < 1) { 940 return 0; 941 } 942 serial_number_str[0] = '\0'; 943 944 platform_dict = IOService::serviceMatching( "IOPlatformExpertDevice" ); 945 if (platform_dict == NULL) { 946 return KERN_NOT_SUPPORTED; 947 } 948 949 platform = IOService::waitForService( platform_dict ); 950 if (platform) { 951 string = ( OSString * ) platform->getProperty( kIOPlatformSerialNumberKey ); 952 if ( string == 0 ) { 953 return KERN_NOT_SUPPORTED; 954 } else { 955 strlcpy( serial_number_str, string->getCStringNoCopy( ), len ); 956 } 957 } 958 959 return KERN_SUCCESS; 960 } 961 962 dev_t IOBSDGetMediaWithUUID( const char *uuid_cstring, char *bsd_name, int bsd_name_len, int timeout) 963 { 964 dev_t dev = 0; 965 OSDictionary *dictionary; 966 OSString *uuid_string; 967 968 if (bsd_name_len < 1) { 969 return 0; 970 } 971 bsd_name[0] = '\0'; 972 973 dictionary = IOService::serviceMatching( "IOMedia" ); 974 if( dictionary ) { 975 uuid_string = OSString::withCString( uuid_cstring ); 976 if( uuid_string ) { 977 IOService *service; 978 mach_timespec_t tv = { timeout, 0 }; // wait up to "timeout" seconds for the device 979 980 dictionary->setObject( "UUID", uuid_string ); 981 dictionary->retain(); 982 service = IOService::waitForService( dictionary, &tv ); 983 if( service ) { 984 OSNumber *dev_major = (OSNumber *) service->getProperty( kIOBSDMajorKey ); 985 OSNumber *dev_minor = (OSNumber *) service->getProperty( kIOBSDMinorKey ); 986 OSString *iostr = (OSString *) service->getProperty( kIOBSDNameKey ); 987 988 if( iostr) 989 strlcpy( bsd_name, iostr->getCStringNoCopy(), bsd_name_len ); 990 991 if ( dev_major && dev_minor ) 992 dev = makedev( dev_major->unsigned32BitValue(), dev_minor->unsigned32BitValue() ); 993 } 994 uuid_string->release(); 995 } 996 dictionary->release(); 997 } 998 999 return dev; 1000 } 1001 1002 1003 void IOBSDIterateMediaWithContent(const char *content_uuid_cstring, int (*func)(const char *bsd_dev_name, const char *uuid_str, void *arg), void *arg) 1004 { 1005 OSDictionary *dictionary; 1006 OSString *content_uuid_string; 1007 1008 dictionary = IOService::serviceMatching( "IOMedia" ); 1009 if( dictionary ) { 1010 content_uuid_string = OSString::withCString( content_uuid_cstring ); 1011 if( content_uuid_string ) { 1012 IOService *service; 1013 OSIterator *iter; 1014 1015 dictionary->setObject( "Content", content_uuid_string ); 1016 dictionary->retain(); 1017 1018 iter = IOService::getMatchingServices(dictionary); 1019 while (iter && (service = (IOService *)iter->getNextObject())) { 1020 if( service ) { 1021 OSString *iostr = (OSString *) service->getProperty( kIOBSDNameKey ); 1022 OSString *uuidstr = (OSString *) service->getProperty( "UUID" ); 1023 const char *uuid; 1024 1025 if( iostr) { 1026 if (uuidstr) { 1027 uuid = uuidstr->getCStringNoCopy(); 1028 } else { 1029 uuid = "00000000-0000-0000-0000-000000000000"; 1030 } 1031 1032 // call the callback 1033 if (func && func(iostr->getCStringNoCopy(), uuid, arg) == 0) { 1034 break; 1035 } 1036 } 1037 } 1038 } 1039 if (iter) 1040 iter->release(); 1041 1042 content_uuid_string->release(); 1043 } 1044 dictionary->release(); 1045 } 1046 } 1047 1048 1049 int IOBSDIsMediaEjectable( const char *cdev_name ) 1050 { 1051 int ret = 0; 1052 OSDictionary *dictionary; 1053 OSString *dev_name; 1054 1055 if (strncmp(cdev_name, "/dev/", 5) == 0) { 1056 cdev_name += 5; 1057 } 1058 1059 dictionary = IOService::serviceMatching( "IOMedia" ); 1060 if( dictionary ) { 1061 dev_name = OSString::withCString( cdev_name ); 1062 if( dev_name ) { 1063 IOService *service; 1064 mach_timespec_t tv = { 5, 0 }; // wait up to "timeout" seconds for the device 1065 1066 dictionary->setObject( kIOBSDNameKey, dev_name ); 1067 dictionary->retain(); 1068 service = IOService::waitForService( dictionary, &tv ); 1069 if( service ) { 1070 OSBoolean *ejectable = (OSBoolean *) service->getProperty( "Ejectable" ); 1071 1072 if( ejectable ) { 1073 ret = (int)ejectable->getValue(); 1074 } 1075 1076 } 1077 dev_name->release(); 1078 } 1079 dictionary->release(); 1080 } 1081 1082 return ret; 1083 } 1084 1085 } /* extern "C" */ 1086