1 /* 2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * The contents of this file constitute Original Code as defined in and 7 * are subject to the Apple Public Source License Version 1.1 (the 8 * "License"). You may not use this file except in compliance with the 9 * License. Please obtain a copy of the License at 10 * http://www.apple.com/publicsource and read it before using this file. 11 * 12 * This Original Code and all software distributed under the License are 13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 17 * License for the specific language governing rights and limitations 18 * under the License. 19 * 20 * @APPLE_LICENSE_HEADER_END@ 21 */ 22 #include <IOKit/IOBSD.h> 23 #include <IOKit/IOLib.h> 24 #include <IOKit/IOService.h> 25 #include <IOKit/IODeviceTreeSupport.h> 26 #include <IOKit/IOKitKeys.h> 27 #include <IOKit/storage/IOMedia.h> 28 #include <IOKit/network/IONetworkStack.h> 29 #include <IOKit/network/IONetworkInterface.h> 30 #include <IOKit/IOPlatformExpert.h> 31 32 #include <sys/disklabel.h> 33 34 extern "C" { 35 36 #include <pexpert/pexpert.h> 37 #include <kern/clock.h> 38 39 // how long to wait for matching root device, secs 40 #define ROOTDEVICETIMEOUT 60 41 42 43 kern_return_t 44 IOKitBSDInit( void ) 45 { 46 IOLog("IOKitBSDInit\n"); 47 48 IOService::publishResource("IOBSD"); 49 50 return( kIOReturnSuccess ); 51 } 52 53 OSDictionary * IOBSDNameMatching( const char * name ) 54 { 55 OSDictionary * dict; 56 const OSSymbol * str = 0; 57 58 do { 59 60 dict = IOService::serviceMatching( gIOServiceKey ); 61 if( !dict) 62 continue; 63 str = OSSymbol::withCString( name ); 64 if( !str) 65 continue; 66 dict->setObject( kIOBSDNameKey, (OSObject *) str ); 67 str->release(); 68 69 return( dict ); 70 71 } while( false ); 72 73 if( dict) 74 dict->release(); 75 if( str) 76 str->release(); 77 78 return( 0 ); 79 } 80 81 OSDictionary * IONetworkMatching( const char * path, 82 char * buf, int maxLen ) 83 { 84 OSDictionary * matching = 0; 85 OSDictionary * dict; 86 OSString * str; 87 char * comp; 88 const char * skip; 89 int len; 90 91 do { 92 93 len = strlen( kIODeviceTreePlane ":" ); 94 maxLen -= len; 95 if( maxLen < 0) 96 continue; 97 98 strcpy( buf, kIODeviceTreePlane ":" ); 99 comp = buf + len; 100 101 // remove parameters following ':' from the path 102 skip = strchr( path, ':'); 103 if( !skip) 104 continue; 105 106 len = skip - path; 107 maxLen -= len; 108 if( maxLen < 0) 109 continue; 110 strncpy( comp, path, len ); 111 comp[ len ] = 0; 112 113 matching = IOService::serviceMatching( "IONetworkInterface" ); 114 if( !matching) 115 continue; 116 dict = IOService::addLocation( matching ); 117 if( !dict) 118 continue; 119 120 str = OSString::withCString( buf ); 121 if( !str) 122 continue; 123 dict->setObject( kIOPathMatchKey, str ); 124 str->release(); 125 126 return( matching ); 127 128 } while( false ); 129 130 if( matching) 131 matching->release(); 132 133 return( 0 ); 134 } 135 136 OSDictionary * IONetworkNamePrefixMatching( const char * prefix ) 137 { 138 OSDictionary * matching; 139 OSDictionary * propDict = 0; 140 const OSSymbol * str = 0; 141 142 do { 143 matching = IOService::serviceMatching( "IONetworkInterface" ); 144 if ( matching == 0 ) 145 continue; 146 147 propDict = OSDictionary::withCapacity(1); 148 if ( propDict == 0 ) 149 continue; 150 151 str = OSSymbol::withCString( prefix ); 152 if ( str == 0 ) 153 continue; 154 155 propDict->setObject( kIOInterfaceNamePrefix, (OSObject *) str ); 156 str->release(); 157 str = 0; 158 159 if ( matching->setObject( gIOPropertyMatchKey, 160 (OSObject *) propDict ) != true ) 161 continue; 162 163 propDict->release(); 164 propDict = 0; 165 166 return( matching ); 167 168 } while ( false ); 169 170 if ( matching ) matching->release(); 171 if ( propDict ) propDict->release(); 172 if ( str ) str->release(); 173 174 return( 0 ); 175 } 176 177 static bool IORegisterNetworkInterface( IONetworkInterface * netif ) 178 { 179 IONetworkStack * stack; 180 181 if (( stack = IONetworkStack::getNetworkStack() )) 182 { 183 stack->registerInterface( netif, netif->getNamePrefix() ); 184 } 185 186 return ( netif->getProperty( kIOBSDNameKey ) != 0 ); 187 } 188 189 static void IORegisterPrimaryNetworkInterface() 190 { 191 IONetworkStack * stack; 192 193 if (( stack = IONetworkStack::getNetworkStack() )) 194 { 195 stack->registerPrimaryInterface( true ); 196 } 197 } 198 199 OSDictionary * IODiskMatching( const char * path, char * buf, int maxLen ) 200 { 201 const char * look; 202 const char * alias; 203 char * comp; 204 long unit = -1; 205 long partition = -1; 206 char c; 207 208 // scan the tail of the path for "@unit:partition" 209 do { 210 // Have to get the full path to the controller - an alias may 211 // tell us next to nothing, like "hd:8" 212 alias = IORegistryEntry::dealiasPath( &path, gIODTPlane ); 213 214 look = path + strlen( path); 215 c = ':'; 216 while( look != path) { 217 if( *(--look) == c) { 218 if( c == ':') { 219 partition = strtol( look + 1, 0, 0 ); 220 c = '@'; 221 } else if( c == '@') { 222 unit = strtol( look + 1, 0, 16 ); 223 c = '/'; 224 } else if( c == '/') { 225 c = 0; 226 break; 227 } 228 } 229 230 if( alias && (look == path)) { 231 path = alias; 232 look = path + strlen( path); 233 alias = 0; 234 } 235 } 236 if( c || unit == -1 || partition == -1) 237 continue; 238 239 maxLen -= strlen( "{" kIOPathMatchKey "='" kIODeviceTreePlane ":" ); 240 maxLen -= ( alias ? strlen( alias ) : 0 ) + (look - path); 241 maxLen -= strlen( "/@hhhhhhhh:dddddddddd';}" ); 242 243 if( maxLen > 0) { 244 sprintf( buf, "{" kIOPathMatchKey "='" kIODeviceTreePlane ":" ); 245 comp = buf + strlen( buf ); 246 247 if( alias) { 248 strcpy( comp, alias ); 249 comp += strlen( alias ); 250 } 251 252 if ( (look - path)) { 253 strncpy( comp, path, look - path); 254 comp += look - path; 255 } 256 257 sprintf( comp, "/@%lx:%ld';}", unit, partition ); 258 } else 259 continue; 260 261 return( OSDynamicCast(OSDictionary, OSUnserialize( buf, 0 )) ); 262 263 } while( false ); 264 265 return( 0 ); 266 } 267 268 OSDictionary * IOOFPathMatching( const char * path, char * buf, int maxLen ) 269 { 270 /* need to look up path, get device type, 271 call matching help based on device type */ 272 273 return( IODiskMatching( path, buf, maxLen )); 274 275 } 276 277 kern_return_t IOFindBSDRoot( char * rootName, 278 dev_t * root, u_int32_t * oflags ) 279 { 280 mach_timespec_t t; 281 IOService * service; 282 IORegistryEntry * regEntry; 283 OSDictionary * matching = 0; 284 OSString * iostr; 285 OSNumber * off; 286 OSData * data = 0; 287 288 UInt32 flags = 0; 289 int minor, major; 290 char * rdBootVar; 291 enum { kMaxPathBuf = 512, kMaxBootVar = 128 }; 292 char * str; 293 const char * look = 0; 294 int len; 295 bool forceNet = false; 296 297 static int mountAttempts = 0; 298 299 if( mountAttempts++) 300 IOSleep( 5 * 1000 ); 301 302 str = (char *) IOMalloc( kMaxPathBuf + kMaxBootVar ); 303 if( !str) 304 return( kIOReturnNoMemory ); 305 rdBootVar = str + kMaxPathBuf; 306 307 if (!PE_parse_boot_arg("rd", rdBootVar ) 308 && !PE_parse_boot_arg("rootdev", rdBootVar )) 309 rdBootVar[0] = 0; 310 311 do { 312 if( (regEntry = IORegistryEntry::fromPath( "/chosen", gIODTPlane ))) { 313 data = (OSData *) regEntry->getProperty( "rootpath" ); 314 regEntry->release(); 315 if( data) 316 continue; 317 } 318 if( (regEntry = IORegistryEntry::fromPath( "/options", gIODTPlane ))) { 319 data = (OSData *) regEntry->getProperty( "boot-file" ); 320 regEntry->release(); 321 if( data) 322 continue; 323 } 324 } while( false ); 325 326 if( data) 327 look = (const char *) data->getBytesNoCopy(); 328 329 if( rdBootVar[0] == '*') { 330 look = rdBootVar + 1; 331 forceNet = false; 332 } else { 333 if( (regEntry = IORegistryEntry::fromPath( "/", gIODTPlane ))) { 334 forceNet = (0 != regEntry->getProperty( "net-boot" )); 335 regEntry->release(); 336 } 337 } 338 339 if( look) { 340 // from OpenFirmware path 341 IOLog("From path: \"%s\", ", look); 342 343 if( forceNet || (0 == strncmp( look, "enet", strlen( "enet" ))) ) 344 matching = IONetworkMatching( look, str, kMaxPathBuf ); 345 else 346 matching = IODiskMatching( look, str, kMaxPathBuf ); 347 } 348 349 if( (!matching) && rdBootVar[0] ) { 350 // by BSD name 351 look = rdBootVar; 352 if( look[0] == '*') 353 look++; 354 355 if ( strncmp( look, "en", strlen( "en" )) == 0 ) 356 matching = IONetworkNamePrefixMatching( "en" ); 357 else 358 matching = IOBSDNameMatching( look ); 359 } 360 361 if( !matching) { 362 OSString * astring; 363 // any UFS 364 matching = IOService::serviceMatching( "IOMedia" ); 365 astring = OSString::withCStringNoCopy("Apple_UFS"); 366 if ( astring ) { 367 matching->setObject(kIOMediaContentKey, astring); 368 astring->release(); 369 } 370 } 371 372 if( true && matching) { 373 OSSerialize * s = OSSerialize::withCapacity( 5 ); 374 375 if( matching->serialize( s )) { 376 IOLog( "Waiting on %s\n", s->text() ); 377 s->release(); 378 } 379 } 380 381 IOService::waitForService(IOService::serviceMatching("IOMediaBSDClient")); 382 383 do { 384 t.tv_sec = ROOTDEVICETIMEOUT; 385 t.tv_nsec = 0; 386 matching->retain(); 387 service = IOService::waitForService( matching, &t ); 388 if( (!service) || (mountAttempts == 10)) { 389 PE_display_icon( 0, "noroot"); 390 IOLog( "Still waiting for root device\n" ); 391 } 392 } while( !service); 393 matching->release(); 394 395 major = 0; 396 minor = 0; 397 398 // If the IOService we matched to is a subclass of IONetworkInterface, 399 // then make sure it has been registered with BSD and has a BSD name 400 // assigned. 401 402 if ( service 403 && service->metaCast( "IONetworkInterface" ) 404 && !IORegisterNetworkInterface( (IONetworkInterface *) service ) ) 405 { 406 service = 0; 407 } 408 IORegisterPrimaryNetworkInterface(); 409 410 if( service) { 411 412 len = kMaxPathBuf; 413 service->getPath( str, &len, gIOServicePlane ); 414 IOLog( "Got boot device = %s\n", str ); 415 416 iostr = (OSString *) service->getProperty( kIOBSDNameKey ); 417 if( iostr) 418 strcpy( rootName, iostr->getCStringNoCopy() ); 419 off = (OSNumber *) service->getProperty( kIOBSDMajorKey ); 420 if( off) 421 major = off->unsigned32BitValue(); 422 off = (OSNumber *) service->getProperty( kIOBSDMinorKey ); 423 if( off) 424 minor = off->unsigned32BitValue(); 425 426 if( service->metaCast( "IONetworkInterface" )) 427 flags |= 1; 428 429 } else { 430 431 IOLog( "Wait for root failed\n" ); 432 strcpy( rootName, "en0"); 433 flags |= 1; 434 } 435 436 IOLog( "BSD root: %s", rootName ); 437 if( major) 438 IOLog(", major %d, minor %d\n", major, minor ); 439 else 440 IOLog("\n"); 441 442 *root = makedev( major, minor ); 443 *oflags = flags; 444 445 IOFree( str, kMaxPathBuf + kMaxBootVar ); 446 447 if( gIOKitDebug & (kIOLogDTree | kIOLogServiceTree | kIOLogMemory)) { 448 449 IOSleep(10 * 1000); 450 // IOService::getPlatform()->waitQuiet(); 451 if( gIOKitDebug & kIOLogDTree) { 452 IOLog("\nDT plane:\n"); 453 IOPrintPlane( gIODTPlane ); 454 } 455 if( gIOKitDebug & kIOLogServiceTree) { 456 IOLog("\nService plane:\n"); 457 IOPrintPlane( gIOServicePlane ); 458 } 459 if( gIOKitDebug & kIOLogMemory) 460 IOPrintMemory(); 461 } 462 463 return( kIOReturnSuccess ); 464 } 465 466 } /* extern "C" */ 467