]>
git.saurik.com Git - apple/xnu.git/blob - iokit/bsddev/IOKitBSDInit.cpp
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 #include <IOKit/IOBSD.h>
26 #include <IOKit/IOLib.h>
27 #include <IOKit/IOService.h>
28 #include <IOKit/IODeviceTreeSupport.h>
29 #include <IOKit/IOKitKeys.h>
30 #include <IOKit/IOPlatformExpert.h>
32 #include <sys/disklabel.h>
36 #include <pexpert/pexpert.h>
37 #include <kern/clock.h>
39 // how long to wait for matching root device, secs
40 #define ROOTDEVICETIMEOUT 60
46 IOLog("IOKitBSDInit\n");
48 IOService::publishResource("IOBSD");
50 return( kIOReturnSuccess
);
53 OSDictionary
* IOBSDNameMatching( const char * name
)
56 const OSSymbol
* str
= 0;
60 dict
= IOService::serviceMatching( gIOServiceKey
);
63 str
= OSSymbol::withCString( name
);
66 dict
->setObject( kIOBSDNameKey
, (OSObject
*) str
);
81 OSDictionary
* IOCDMatching( const char * name
)
86 dict
= IOService::serviceMatching( "IOMedia" );
88 IOLog("Unable to find IOMedia\n");
92 str
= OSSymbol::withCString( "CD_ROM_Mode_1" );
98 dict
->setObject( "Content", (OSObject
*)str
);
103 OSDictionary
* IONetworkMatching( const char * path
,
104 char * buf
, int maxLen
)
106 OSDictionary
* matching
= 0;
115 len
= strlen( kIODeviceTreePlane
":" );
120 strcpy( buf
, kIODeviceTreePlane
":" );
123 // remove parameters following ':' from the path
124 skip
= strchr( path
, ':');
132 strncpy( comp
, path
, len
);
135 matching
= IOService::serviceMatching( "IONetworkInterface" );
138 dict
= IOService::addLocation( matching
);
142 str
= OSString::withCString( buf
);
145 dict
->setObject( kIOPathMatchKey
, str
);
158 OSDictionary
* IONetworkNamePrefixMatching( const char * prefix
)
160 OSDictionary
* matching
;
161 OSDictionary
* propDict
= 0;
162 const OSSymbol
* str
= 0;
165 matching
= IOService::serviceMatching( "IONetworkInterface" );
169 propDict
= OSDictionary::withCapacity(1);
173 str
= OSSymbol::withCString( prefix
);
177 propDict
->setObject( "IOInterfaceNamePrefix", (OSObject
*) str
);
181 if ( matching
->setObject( gIOPropertyMatchKey
,
182 (OSObject
*) propDict
) != true )
192 if ( matching
) matching
->release();
193 if ( propDict
) propDict
->release();
194 if ( str
) str
->release();
199 static bool IORegisterNetworkInterface( IOService
* netif
)
201 // A network interface is typically named and registered
202 // with BSD after receiving a request from a user space
203 // "namer". However, for cases when the system needs to
204 // root from the network, this registration task must be
205 // done inside the kernel and completed before the root
206 // device is handed to BSD.
211 OSDictionary
* dict
= 0;
214 enum { kMaxPathLen
= 512 };
217 stack
= IOService::waitForService(
218 IOService::serviceMatching("IONetworkStack") );
219 if ( stack
== 0 ) break;
221 dict
= OSDictionary::withCapacity(3);
222 if ( dict
== 0 ) break;
224 zero
= OSNumber::withNumber((UInt64
) 0, 32);
225 if ( zero
== 0 ) break;
227 pathBuf
= (char *) IOMalloc( kMaxPathLen
);
228 if ( pathBuf
== 0 ) break;
231 if ( netif
->getPath( pathBuf
, &len
, gIOServicePlane
)
234 path
= OSString::withCStringNoCopy( pathBuf
);
235 if ( path
== 0 ) break;
237 dict
->setObject( "IOInterfaceUnit", zero
);
238 dict
->setObject( kIOPathMatchKey
, path
);
240 stack
->setProperties( dict
);
244 if ( zero
) zero
->release();
245 if ( path
) path
->release();
246 if ( dict
) dict
->release();
247 if ( pathBuf
) IOFree(pathBuf
, kMaxPathLen
);
249 return ( netif
->getProperty( kIOBSDNameKey
) != 0 );
252 OSDictionary
* IODiskMatching( const char * path
, char * buf
, int maxLen
)
261 // scan the tail of the path for "@unit:partition"
263 // Have to get the full path to the controller - an alias may
264 // tell us next to nothing, like "hd:8"
265 alias
= IORegistryEntry::dealiasPath( &path
, gIODTPlane
);
267 look
= path
+ strlen( path
);
269 while( look
!= path
) {
270 if( *(--look
) == c
) {
272 partition
= strtol( look
+ 1, 0, 0 );
274 } else if( c
== '@') {
275 unit
= strtol( look
+ 1, 0, 16 );
277 } else if( c
== '/') {
283 if( alias
&& (look
== path
)) {
285 look
= path
+ strlen( path
);
289 if( c
|| unit
== -1 || partition
== -1)
292 maxLen
-= strlen( "{" kIOPathMatchKey
"='" kIODeviceTreePlane
":" );
293 maxLen
-= ( alias
? strlen( alias
) : 0 ) + (look
- path
);
294 maxLen
-= strlen( "/@hhhhhhhh:dddddddddd';}" );
297 sprintf( buf
, "{" kIOPathMatchKey
"='" kIODeviceTreePlane
":" );
298 comp
= buf
+ strlen( buf
);
301 strcpy( comp
, alias
);
302 comp
+= strlen( alias
);
305 if ( (look
- path
)) {
306 strncpy( comp
, path
, look
- path
);
310 sprintf( comp
, "/@%lx:%ld';}", unit
, partition
);
314 return( OSDynamicCast(OSDictionary
, OSUnserialize( buf
, 0 )) );
321 OSDictionary
* IOOFPathMatching( const char * path
, char * buf
, int maxLen
)
323 /* need to look up path, get device type,
324 call matching help based on device type */
326 return( IODiskMatching( path
, buf
, maxLen
));
330 kern_return_t
IOFindBSDRoot( char * rootName
,
331 dev_t
* root
, u_int32_t
* oflags
)
335 IORegistryEntry
* regEntry
;
336 OSDictionary
* matching
= 0;
344 enum { kMaxPathBuf
= 512, kMaxBootVar
= 128 };
346 const char * look
= 0;
348 bool forceNet
= false;
349 bool debugInfoPrintedOnce
= false;
351 static int mountAttempts
= 0;
356 str
= (char *) IOMalloc( kMaxPathBuf
+ kMaxBootVar
);
358 return( kIOReturnNoMemory
);
359 rdBootVar
= str
+ kMaxPathBuf
;
361 if (!PE_parse_boot_arg("rd", rdBootVar
)
362 && !PE_parse_boot_arg("rootdev", rdBootVar
))
366 if( (regEntry
= IORegistryEntry::fromPath( "/chosen", gIODTPlane
))) {
367 data
= (OSData
*) regEntry
->getProperty( "rootpath" );
372 if( (regEntry
= IORegistryEntry::fromPath( "/options", gIODTPlane
))) {
373 data
= (OSData
*) regEntry
->getProperty( "boot-file" );
381 look
= (const char *) data
->getBytesNoCopy();
383 if( rdBootVar
[0] == '*') {
384 look
= rdBootVar
+ 1;
387 if( (regEntry
= IORegistryEntry::fromPath( "/", gIODTPlane
))) {
388 forceNet
= (0 != regEntry
->getProperty( "net-boot" ));
394 // from OpenFirmware path
395 IOLog("From path: \"%s\", ", look
);
397 if( forceNet
|| (0 == strncmp( look
, "enet", strlen( "enet" ))) ) {
398 matching
= IONetworkMatching( look
, str
, kMaxPathBuf
);
400 matching
= IODiskMatching( look
, str
, kMaxPathBuf
);
404 if( (!matching
) && rdBootVar
[0] ) {
410 if ( strncmp( look
, "en", strlen( "en" )) == 0 ) {
411 matching
= IONetworkNamePrefixMatching( "en" );
412 } else if ( strncmp( look
, "cdrom", strlen( "cdrom" )) == 0 ) {
413 matching
= IOCDMatching( look
);
415 matching
= IOBSDNameMatching( look
);
422 matching
= IOService::serviceMatching( "IOMedia" );
423 astring
= OSString::withCStringNoCopy("Apple_UFS");
425 matching
->setObject("Content", astring
);
430 if( true && matching
) {
431 OSSerialize
* s
= OSSerialize::withCapacity( 5 );
433 if( matching
->serialize( s
)) {
434 IOLog( "Waiting on %s\n", s
->text() );
440 t
.tv_sec
= ROOTDEVICETIMEOUT
;
443 service
= IOService::waitForService( matching
, &t
);
444 if( (!service
) || (mountAttempts
== 10)) {
445 PE_display_icon( 0, "noroot");
446 IOLog( "Still waiting for root device\n" );
448 if( !debugInfoPrintedOnce
) {
449 debugInfoPrintedOnce
= true;
450 if( gIOKitDebug
& kIOLogDTree
) {
451 IOLog("\nDT plane:\n");
452 IOPrintPlane( gIODTPlane
);
454 if( gIOKitDebug
& kIOLogServiceTree
) {
455 IOLog("\nService plane:\n");
456 IOPrintPlane( gIOServicePlane
);
458 if( gIOKitDebug
& kIOLogMemory
)
468 // If the IOService we matched to is a subclass of IONetworkInterface,
469 // then make sure it has been registered with BSD and has a BSD name
473 && service
->metaCast( "IONetworkInterface" )
474 && !IORegisterNetworkInterface( service
) )
482 service
->getPath( str
, &len
, gIOServicePlane
);
483 IOLog( "Got boot device = %s\n", str
);
485 iostr
= (OSString
*) service
->getProperty( kIOBSDNameKey
);
487 strcpy( rootName
, iostr
->getCStringNoCopy() );
488 off
= (OSNumber
*) service
->getProperty( kIOBSDMajorKey
);
490 major
= off
->unsigned32BitValue();
491 off
= (OSNumber
*) service
->getProperty( kIOBSDMinorKey
);
493 minor
= off
->unsigned32BitValue();
495 if( service
->metaCast( "IONetworkInterface" ))
500 IOLog( "Wait for root failed\n" );
501 strcpy( rootName
, "en0");
505 IOLog( "BSD root: %s", rootName
);
507 IOLog(", major %d, minor %d\n", major
, minor
);
511 *root
= makedev( major
, minor
);
514 IOFree( str
, kMaxPathBuf
+ kMaxBootVar
);
516 if( (gIOKitDebug
& (kIOLogDTree
| kIOLogServiceTree
| kIOLogMemory
)) && !debugInfoPrintedOnce
) {
518 IOService::getPlatform()->waitQuiet();
519 if( gIOKitDebug
& kIOLogDTree
) {
520 IOLog("\nDT plane:\n");
521 IOPrintPlane( gIODTPlane
);
523 if( gIOKitDebug
& kIOLogServiceTree
) {
524 IOLog("\nService plane:\n");
525 IOPrintPlane( gIOServicePlane
);
527 if( gIOKitDebug
& kIOLogMemory
)
531 return( kIOReturnSuccess
);
535 IOBSDRegistryEntryForDeviceTree(char * path
)
537 return (IORegistryEntry::fromPath(path
, gIODTPlane
));
541 IOBSDRegistryEntryRelease(void * entry
)
543 IORegistryEntry
* regEntry
= (IORegistryEntry
*)entry
;
551 IOBSDRegistryEntryGetData(void * entry
, char * property_name
,
555 IORegistryEntry
* regEntry
= (IORegistryEntry
*)entry
;
557 data
= (OSData
*) regEntry
->getProperty(property_name
);
559 *packet_length
= data
->getLength();
560 return (data
->getBytesNoCopy());