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