0900a09855b7aaded06b573c8e3b574d6442c6d0
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
42 extern dev_t
mdevadd(int devid
, ppnum_t base
, unsigned int size
, int phys
);
43 extern dev_t
mdevlookup(int devid
);
48 IOLog("IOKitBSDInit\n");
50 IOService::publishResource("IOBSD");
52 return( kIOReturnSuccess
);
55 OSDictionary
* IOBSDNameMatching( const char * name
)
58 const OSSymbol
* str
= 0;
62 dict
= IOService::serviceMatching( gIOServiceKey
);
65 str
= OSSymbol::withCString( name
);
68 dict
->setObject( kIOBSDNameKey
, (OSObject
*) str
);
83 OSDictionary
* IOCDMatching( const char * name
)
88 dict
= IOService::serviceMatching( "IOMedia" );
90 IOLog("Unable to find IOMedia\n");
94 str
= OSSymbol::withCString( "CD_ROM_Mode_1" );
100 dict
->setObject( "Content", (OSObject
*)str
);
105 OSDictionary
* IONetworkMatching( const char * path
,
106 char * buf
, int maxLen
)
108 OSDictionary
* matching
= 0;
117 len
= strlen( kIODeviceTreePlane
":" );
122 strcpy( buf
, kIODeviceTreePlane
":" );
125 // remove parameters following ':' from the path
126 skip
= strchr( path
, ':');
134 strncpy( comp
, path
, len
);
137 matching
= IOService::serviceMatching( "IONetworkInterface" );
140 dict
= IOService::addLocation( matching
);
144 str
= OSString::withCString( buf
);
147 dict
->setObject( kIOPathMatchKey
, str
);
160 OSDictionary
* IONetworkNamePrefixMatching( const char * prefix
)
162 OSDictionary
* matching
;
163 OSDictionary
* propDict
= 0;
164 const OSSymbol
* str
= 0;
167 matching
= IOService::serviceMatching( "IONetworkInterface" );
171 propDict
= OSDictionary::withCapacity(1);
175 str
= OSSymbol::withCString( prefix
);
179 propDict
->setObject( "IOInterfaceNamePrefix", (OSObject
*) str
);
183 if ( matching
->setObject( gIOPropertyMatchKey
,
184 (OSObject
*) propDict
) != true )
194 if ( matching
) matching
->release();
195 if ( propDict
) propDict
->release();
196 if ( str
) str
->release();
201 static bool IORegisterNetworkInterface( IOService
* netif
)
203 // A network interface is typically named and registered
204 // with BSD after receiving a request from a user space
205 // "namer". However, for cases when the system needs to
206 // root from the network, this registration task must be
207 // done inside the kernel and completed before the root
208 // device is handed to BSD.
213 OSDictionary
* dict
= 0;
216 enum { kMaxPathLen
= 512 };
219 stack
= IOService::waitForService(
220 IOService::serviceMatching("IONetworkStack") );
221 if ( stack
== 0 ) break;
223 dict
= OSDictionary::withCapacity(3);
224 if ( dict
== 0 ) break;
226 zero
= OSNumber::withNumber((UInt64
) 0, 32);
227 if ( zero
== 0 ) break;
229 pathBuf
= (char *) IOMalloc( kMaxPathLen
);
230 if ( pathBuf
== 0 ) break;
233 if ( netif
->getPath( pathBuf
, &len
, gIOServicePlane
)
236 path
= OSString::withCStringNoCopy( pathBuf
);
237 if ( path
== 0 ) break;
239 dict
->setObject( "IOInterfaceUnit", zero
);
240 dict
->setObject( kIOPathMatchKey
, path
);
242 stack
->setProperties( dict
);
246 if ( zero
) zero
->release();
247 if ( path
) path
->release();
248 if ( dict
) dict
->release();
249 if ( pathBuf
) IOFree(pathBuf
, kMaxPathLen
);
251 return ( netif
->getProperty( kIOBSDNameKey
) != 0 );
254 OSDictionary
* IODiskMatching( const char * path
, char * buf
, int maxLen
)
263 // scan the tail of the path for "@unit:partition"
265 // Have to get the full path to the controller - an alias may
266 // tell us next to nothing, like "hd:8"
267 alias
= IORegistryEntry::dealiasPath( &path
, gIODTPlane
);
269 look
= path
+ strlen( path
);
271 while( look
!= path
) {
272 if( *(--look
) == c
) {
274 partition
= strtol( look
+ 1, 0, 0 );
276 } else if( c
== '@') {
277 unit
= strtol( look
+ 1, 0, 16 );
279 } else if( c
== '/') {
285 if( alias
&& (look
== path
)) {
287 look
= path
+ strlen( path
);
291 if( c
|| unit
== -1 || partition
== -1)
294 maxLen
-= strlen( "{" kIOPathMatchKey
"='" kIODeviceTreePlane
":" );
295 maxLen
-= ( alias
? strlen( alias
) : 0 ) + (look
- path
);
296 maxLen
-= strlen( "/@hhhhhhhh:dddddddddd';}" );
299 sprintf( buf
, "{" kIOPathMatchKey
"='" kIODeviceTreePlane
":" );
300 comp
= buf
+ strlen( buf
);
303 strcpy( comp
, alias
);
304 comp
+= strlen( alias
);
307 if ( (look
- path
)) {
308 strncpy( comp
, path
, look
- path
);
312 sprintf( comp
, "/@%lx:%ld';}", unit
, partition
);
316 return( OSDynamicCast(OSDictionary
, OSUnserialize( buf
, 0 )) );
323 OSDictionary
* IOOFPathMatching( const char * path
, char * buf
, int maxLen
)
325 /* need to look up path, get device type,
326 call matching help based on device type */
328 return( IODiskMatching( path
, buf
, maxLen
));
332 static int didRam
= 0;
334 kern_return_t
IOFindBSDRoot( char * rootName
,
335 dev_t
* root
, u_int32_t
* oflags
)
339 IORegistryEntry
* regEntry
;
340 OSDictionary
* matching
= 0;
344 UInt32
*ramdParms
= 0;
349 enum { kMaxPathBuf
= 512, kMaxBootVar
= 128 };
351 const char * look
= 0;
353 bool forceNet
= false;
354 bool debugInfoPrintedOnce
= false;
356 static int mountAttempts
= 0;
364 str
= (char *) IOMalloc( kMaxPathBuf
+ kMaxBootVar
);
366 return( kIOReturnNoMemory
);
367 rdBootVar
= str
+ kMaxPathBuf
;
369 if (!PE_parse_boot_arg("rd", rdBootVar
)
370 && !PE_parse_boot_arg("rootdev", rdBootVar
))
374 if( (regEntry
= IORegistryEntry::fromPath( "/chosen", gIODTPlane
))) {
375 data
= (OSData
*) regEntry
->getProperty( "rootpath" );
379 if( (regEntry
= IORegistryEntry::fromPath( "/options", gIODTPlane
))) {
380 data
= (OSData
*) regEntry
->getProperty( "boot-file" );
387 look
= (const char *) data
->getBytesNoCopy();
389 if( rdBootVar
[0] == '*') {
390 look
= rdBootVar
+ 1;
393 if( (regEntry
= IORegistryEntry::fromPath( "/", gIODTPlane
))) {
394 forceNet
= (0 != regEntry
->getProperty( "net-boot" ));
402 // See if we have a RAMDisk property in /chosen/memory-map. If so, make it into a device.
403 // It will become /dev/mdx, where x is 0-f.
406 if(!didRam
) { /* Have we already build this ram disk? */
407 didRam
= 1; /* Remember we did this */
408 if((regEntry
= IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane
))) { /* Find the map node */
409 data
= (OSData
*)regEntry
->getProperty("RAMDisk"); /* Find the ram disk, if there */
410 if(data
) { /* We found one */
412 ramdParms
= (UInt32
*)data
->getBytesNoCopy(); /* Point to the ram disk base and size */
413 (void)mdevadd(-1, ramdParms
[0] >> 12, ramdParms
[1] >> 12, 0); /* Initialize it and pass back the device number */
415 regEntry
->release(); /* Toss the entry */
420 // Now check if we are trying to root on a memory device
423 if((rdBootVar
[0] == 'm') && (rdBootVar
[1] == 'd') && (rdBootVar
[3] == 0)) {
424 dchar
= xchar
= rdBootVar
[2]; /* Get the actual device */
425 if((xchar
>= '0') && (xchar
<= '9')) xchar
= xchar
- '0'; /* If digit, convert */
427 xchar
= xchar
& ~' '; /* Fold to upper case */
428 if((xchar
>= 'A') && (xchar
<= 'F')) { /* Is this a valid digit? */
429 xchar
= (xchar
& 0xF) + 9; /* Convert the hex digit */
430 dchar
= dchar
| ' '; /* Fold to lower case */
432 else xchar
= -1; /* Show bogus */
434 if(xchar
>= 0) { /* Do we have a valid memory device name? */
435 *root
= mdevlookup(xchar
); /* Find the device number */
436 if(*root
>= 0) { /* Did we find one? */
438 rootName
[0] = 'm'; /* Build root name */
439 rootName
[1] = 'd'; /* Build root name */
440 rootName
[2] = dchar
; /* Build root name */
441 rootName
[3] = 0; /* Build root name */
442 IOLog("BSD root: %s, major %d, minor %d\n", rootName
, major(*root
), minor(*root
));
443 *oflags
= 0; /* Show that this is not network */
444 goto iofrootx
; /* Join common exit... */
446 panic("IOFindBSDRoot: specified root memory device, %s, has not been configured\n", rdBootVar
); /* Not there */
451 // from OpenFirmware path
452 IOLog("From path: \"%s\", ", look
);
454 if( forceNet
|| (0 == strncmp( look
, "enet", strlen( "enet" ))) ) {
455 matching
= IONetworkMatching( look
, str
, kMaxPathBuf
);
457 matching
= IODiskMatching( look
, str
, kMaxPathBuf
);
461 if( (!matching
) && rdBootVar
[0] ) {
467 if ( strncmp( look
, "en", strlen( "en" )) == 0 ) {
468 matching
= IONetworkNamePrefixMatching( "en" );
469 } else if ( strncmp( look
, "cdrom", strlen( "cdrom" )) == 0 ) {
470 matching
= IOCDMatching( look
);
472 matching
= IOBSDNameMatching( look
);
479 matching
= IOService::serviceMatching( "IOMedia" );
480 astring
= OSString::withCStringNoCopy("Apple_UFS");
482 matching
->setObject("Content", astring
);
487 if( true && matching
) {
488 OSSerialize
* s
= OSSerialize::withCapacity( 5 );
490 if( matching
->serialize( s
)) {
491 IOLog( "Waiting on %s\n", s
->text() );
497 t
.tv_sec
= ROOTDEVICETIMEOUT
;
500 service
= IOService::waitForService( matching
, &t
);
501 if( (!service
) || (mountAttempts
== 10)) {
502 PE_display_icon( 0, "noroot");
503 IOLog( "Still waiting for root device\n" );
505 if( !debugInfoPrintedOnce
) {
506 debugInfoPrintedOnce
= true;
507 if( gIOKitDebug
& kIOLogDTree
) {
508 IOLog("\nDT plane:\n");
509 IOPrintPlane( gIODTPlane
);
511 if( gIOKitDebug
& kIOLogServiceTree
) {
512 IOLog("\nService plane:\n");
513 IOPrintPlane( gIOServicePlane
);
515 if( gIOKitDebug
& kIOLogMemory
)
525 // If the IOService we matched to is a subclass of IONetworkInterface,
526 // then make sure it has been registered with BSD and has a BSD name
530 && service
->metaCast( "IONetworkInterface" )
531 && !IORegisterNetworkInterface( service
) )
539 service
->getPath( str
, &len
, gIOServicePlane
);
540 IOLog( "Got boot device = %s\n", str
);
542 iostr
= (OSString
*) service
->getProperty( kIOBSDNameKey
);
544 strcpy( rootName
, iostr
->getCStringNoCopy() );
545 off
= (OSNumber
*) service
->getProperty( kIOBSDMajorKey
);
547 major
= off
->unsigned32BitValue();
548 off
= (OSNumber
*) service
->getProperty( kIOBSDMinorKey
);
550 minor
= off
->unsigned32BitValue();
552 if( service
->metaCast( "IONetworkInterface" ))
557 IOLog( "Wait for root failed\n" );
558 strcpy( rootName
, "en0");
562 IOLog( "BSD root: %s", rootName
);
564 IOLog(", major %d, minor %d\n", major
, minor
);
568 *root
= makedev( major
, minor
);
571 IOFree( str
, kMaxPathBuf
+ kMaxBootVar
);
574 if( (gIOKitDebug
& (kIOLogDTree
| kIOLogServiceTree
| kIOLogMemory
)) && !debugInfoPrintedOnce
) {
576 IOService::getPlatform()->waitQuiet();
577 if( gIOKitDebug
& kIOLogDTree
) {
578 IOLog("\nDT plane:\n");
579 IOPrintPlane( gIODTPlane
);
581 if( gIOKitDebug
& kIOLogServiceTree
) {
582 IOLog("\nService plane:\n");
583 IOPrintPlane( gIOServicePlane
);
585 if( gIOKitDebug
& kIOLogMemory
)
589 return( kIOReturnSuccess
);
593 IOBSDRegistryEntryForDeviceTree(char * path
)
595 return (IORegistryEntry::fromPath(path
, gIODTPlane
));
599 IOBSDRegistryEntryRelease(void * entry
)
601 IORegistryEntry
* regEntry
= (IORegistryEntry
*)entry
;
609 IOBSDRegistryEntryGetData(void * entry
, char * property_name
,
613 IORegistryEntry
* regEntry
= (IORegistryEntry
*)entry
;
615 data
= (OSData
*) regEntry
->getProperty(property_name
);
617 *packet_length
= data
->getLength();
618 return (data
->getBytesNoCopy());