]>
git.saurik.com Git - apple/xnu.git/blob - iokit/bsddev/IOKitBSDInit.cpp
0f75e30626817392a9d79d0da57809525435d780
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
30 #include <IOKit/IOBSD.h>
31 #include <IOKit/IOLib.h>
32 #include <IOKit/IOService.h>
33 #include <IOKit/IODeviceTreeSupport.h>
34 #include <IOKit/IOKitKeys.h>
35 #include <IOKit/IOPlatformExpert.h>
39 #include <pexpert/pexpert.h>
40 #include <kern/clock.h>
42 // how long to wait for matching root device, secs
43 #define ROOTDEVICETIMEOUT 60
45 extern dev_t
mdevadd(int devid
, ppnum_t base
, unsigned int size
, int phys
);
46 extern dev_t
mdevlookup(int devid
);
51 IOService::publishResource("IOBSD");
53 return( kIOReturnSuccess
);
56 OSDictionary
* IOBSDNameMatching( const char * name
)
59 const OSSymbol
* str
= 0;
63 dict
= IOService::serviceMatching( gIOServiceKey
);
66 str
= OSSymbol::withCString( name
);
69 dict
->setObject( kIOBSDNameKey
, (OSObject
*) str
);
84 OSDictionary
* IOUUIDMatching( void )
86 return IOService::resourceMatching( "boot-uuid-media" );
90 OSDictionary
* IOCDMatching( void )
95 dict
= IOService::serviceMatching( "IOMedia" );
97 IOLog("Unable to find IOMedia\n");
101 str
= OSSymbol::withCString( "CD_ROM_Mode_1" );
107 dict
->setObject( "Content Hint", (OSObject
*)str
);
112 OSDictionary
* IONetworkMatching( const char * path
,
113 char * buf
, int maxLen
)
115 OSDictionary
* matching
= 0;
124 len
= strlen( kIODeviceTreePlane
":" );
129 strcpy( buf
, kIODeviceTreePlane
":" );
132 // remove parameters following ':' from the path
133 skip
= strchr( path
, ':');
141 strncpy( comp
, path
, len
);
144 matching
= IOService::serviceMatching( "IONetworkInterface" );
147 dict
= IOService::addLocation( matching
);
151 str
= OSString::withCString( buf
);
154 dict
->setObject( kIOPathMatchKey
, str
);
167 OSDictionary
* IONetworkNamePrefixMatching( const char * prefix
)
169 OSDictionary
* matching
;
170 OSDictionary
* propDict
= 0;
171 const OSSymbol
* str
= 0;
174 matching
= IOService::serviceMatching( "IONetworkInterface" );
178 propDict
= OSDictionary::withCapacity(1);
182 str
= OSSymbol::withCString( prefix
);
186 propDict
->setObject( "IOInterfaceNamePrefix", (OSObject
*) str
);
190 if ( matching
->setObject( gIOPropertyMatchKey
,
191 (OSObject
*) propDict
) != true )
201 if ( matching
) matching
->release();
202 if ( propDict
) propDict
->release();
203 if ( str
) str
->release();
208 static bool IORegisterNetworkInterface( IOService
* netif
)
210 // A network interface is typically named and registered
211 // with BSD after receiving a request from a user space
212 // "namer". However, for cases when the system needs to
213 // root from the network, this registration task must be
214 // done inside the kernel and completed before the root
215 // device is handed to BSD.
220 OSDictionary
* dict
= 0;
223 enum { kMaxPathLen
= 512 };
226 stack
= IOService::waitForService(
227 IOService::serviceMatching("IONetworkStack") );
228 if ( stack
== 0 ) break;
230 dict
= OSDictionary::withCapacity(3);
231 if ( dict
== 0 ) break;
233 zero
= OSNumber::withNumber((UInt64
) 0, 32);
234 if ( zero
== 0 ) break;
236 pathBuf
= (char *) IOMalloc( kMaxPathLen
);
237 if ( pathBuf
== 0 ) break;
240 if ( netif
->getPath( pathBuf
, &len
, gIOServicePlane
)
243 path
= OSString::withCStringNoCopy( pathBuf
);
244 if ( path
== 0 ) break;
246 dict
->setObject( "IOInterfaceUnit", zero
);
247 dict
->setObject( kIOPathMatchKey
, path
);
249 stack
->setProperties( dict
);
253 if ( zero
) zero
->release();
254 if ( path
) path
->release();
255 if ( dict
) dict
->release();
256 if ( pathBuf
) IOFree(pathBuf
, kMaxPathLen
);
258 return ( netif
->getProperty( kIOBSDNameKey
) != 0 );
261 OSDictionary
* IODiskMatching( const char * path
, char * buf
, int maxLen
)
271 // scan the tail of the path for "@unit:partition"
273 // Have to get the full path to the controller - an alias may
274 // tell us next to nothing, like "hd:8"
275 alias
= IORegistryEntry::dealiasPath( &path
, gIODTPlane
);
277 look
= path
+ strlen( path
);
279 while( look
!= path
) {
280 if( *(--look
) == c
) {
282 partition
= strtol( look
+ 1, 0, 0 );
284 } else if( c
== '@') {
285 unit
= strtol( look
+ 1, &comp
, 16 );
288 lun
= strtol( comp
+ 1, 0, 16 );
292 } else if( c
== '/') {
298 if( alias
&& (look
== path
)) {
300 look
= path
+ strlen( path
);
304 if( c
|| unit
== -1 || partition
== -1)
307 maxLen
-= strlen( "{" kIOPathMatchKey
"='" kIODeviceTreePlane
":" );
308 maxLen
-= ( alias
? strlen( alias
) : 0 ) + (look
- path
);
309 maxLen
-= strlen( "/@hhhhhhhh,hhhhhhhh:dddddddddd';}" );
312 sprintf( buf
, "{" kIOPathMatchKey
"='" kIODeviceTreePlane
":" );
313 comp
= buf
+ strlen( buf
);
316 strcpy( comp
, alias
);
317 comp
+= strlen( alias
);
320 if ( (look
- path
)) {
321 strncpy( comp
, path
, look
- path
);
327 sprintf ( comp
, "/@%lx,%lx:%ld';}", unit
, lun
, partition
);
331 sprintf( comp
, "/@%lx:%ld';}", unit
, partition
);
336 return( OSDynamicCast(OSDictionary
, OSUnserialize( buf
, 0 )) );
343 OSDictionary
* IOOFPathMatching( const char * path
, char * buf
, int maxLen
)
345 OSDictionary
* matching
;
350 /* need to look up path, get device type,
351 call matching help based on device type */
353 matching
= IODiskMatching( path
, buf
, maxLen
);
359 len
= strlen( kIODeviceTreePlane
":" );
364 strcpy( buf
, kIODeviceTreePlane
":" );
367 len
= strlen( path
);
371 strncpy( comp
, path
, len
);
374 matching
= OSDictionary::withCapacity( 1 );
378 str
= OSString::withCString( buf
);
381 matching
->setObject( kIOPathMatchKey
, str
);
394 IOService
* IOFindMatchingChild( IOService
* service
)
396 // find a matching child service
397 IOService
* child
= 0;
398 OSIterator
* iter
= service
->getClientIterator();
400 while( ( child
= (IOService
*) iter
->getNextObject() ) ) {
401 OSDictionary
* dict
= OSDictionary::withCapacity( 1 );
406 const OSSymbol
* str
= OSSymbol::withCString( "Apple_HFS" );
412 dict
->setObject( "Content", (OSObject
*)str
);
414 if ( child
->compareProperty( dict
, "Content" ) ) {
419 IOService
* subchild
= IOFindMatchingChild( child
);
430 static int didRam
= 0;
432 kern_return_t
IOFindBSDRoot( char * rootName
,
433 dev_t
* root
, u_int32_t
* oflags
)
437 IORegistryEntry
* regEntry
;
438 OSDictionary
* matching
= 0;
442 UInt32
*ramdParms
= 0;
446 bool findHFSChild
= false;
447 char * mediaProperty
= 0;
449 enum { kMaxPathBuf
= 512, kMaxBootVar
= 128 };
451 const char * look
= 0;
453 bool forceNet
= false;
454 bool debugInfoPrintedOnce
= false;
455 const char * uuidStr
= NULL
;
457 static int mountAttempts
= 0;
465 str
= (char *) IOMalloc( kMaxPathBuf
+ kMaxBootVar
);
467 return( kIOReturnNoMemory
);
468 rdBootVar
= str
+ kMaxPathBuf
;
470 if (!PE_parse_boot_arg("rd", rdBootVar
)
471 && !PE_parse_boot_arg("rootdev", rdBootVar
))
475 if( (regEntry
= IORegistryEntry::fromPath( "/chosen", gIODTPlane
))) {
476 data
= OSDynamicCast(OSData
, regEntry
->getProperty( "root-matching" ));
478 matching
= OSDynamicCast(OSDictionary
, OSUnserializeXML((char *)data
->getBytesNoCopy()));
484 data
= (OSData
*) regEntry
->getProperty( "boot-uuid" );
486 uuidStr
= (const char*)data
->getBytesNoCopy();
487 OSString
*uuidString
= OSString::withCString( uuidStr
);
489 // match the boot-args boot-uuid processing below
491 IOLog("rooting via boot-uuid from /chosen: %s\n", uuidStr
);
492 IOService::publishResource( "boot-uuid", uuidString
);
493 uuidString
->release();
494 matching
= IOUUIDMatching();
495 mediaProperty
= "boot-uuid-media";
503 // else try for an OF Path
504 data
= (OSData
*) regEntry
->getProperty( "rootpath" );
508 if( (regEntry
= IORegistryEntry::fromPath( "/options", gIODTPlane
))) {
509 data
= (OSData
*) regEntry
->getProperty( "boot-file" );
515 if( data
&& !uuidStr
)
516 look
= (const char *) data
->getBytesNoCopy();
518 if( rdBootVar
[0] == '*') {
519 look
= rdBootVar
+ 1;
522 if( (regEntry
= IORegistryEntry::fromPath( "/", gIODTPlane
))) {
523 forceNet
= (0 != regEntry
->getProperty( "net-boot" ));
531 // See if we have a RAMDisk property in /chosen/memory-map. If so, make it into a device.
532 // It will become /dev/mdx, where x is 0-f.
535 if(!didRam
) { /* Have we already build this ram disk? */
536 didRam
= 1; /* Remember we did this */
537 if((regEntry
= IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane
))) { /* Find the map node */
538 data
= (OSData
*)regEntry
->getProperty("RAMDisk"); /* Find the ram disk, if there */
539 if(data
) { /* We found one */
541 ramdParms
= (UInt32
*)data
->getBytesNoCopy(); /* Point to the ram disk base and size */
542 (void)mdevadd(-1, ramdParms
[0] >> 12, ramdParms
[1] >> 12, 0); /* Initialize it and pass back the device number */
544 regEntry
->release(); /* Toss the entry */
549 // Now check if we are trying to root on a memory device
552 if((rdBootVar
[0] == 'm') && (rdBootVar
[1] == 'd') && (rdBootVar
[3] == 0)) {
553 dchar
= xchar
= rdBootVar
[2]; /* Get the actual device */
554 if((xchar
>= '0') && (xchar
<= '9')) xchar
= xchar
- '0'; /* If digit, convert */
556 xchar
= xchar
& ~' '; /* Fold to upper case */
557 if((xchar
>= 'A') && (xchar
<= 'F')) { /* Is this a valid digit? */
558 xchar
= (xchar
& 0xF) + 9; /* Convert the hex digit */
559 dchar
= dchar
| ' '; /* Fold to lower case */
561 else xchar
= -1; /* Show bogus */
563 if(xchar
>= 0) { /* Do we have a valid memory device name? */
564 *root
= mdevlookup(xchar
); /* Find the device number */
565 if(*root
>= 0) { /* Did we find one? */
567 rootName
[0] = 'm'; /* Build root name */
568 rootName
[1] = 'd'; /* Build root name */
569 rootName
[2] = dchar
; /* Build root name */
570 rootName
[3] = 0; /* Build root name */
571 IOLog("BSD root: %s, major %d, minor %d\n", rootName
, major(*root
), minor(*root
));
572 *oflags
= 0; /* Show that this is not network */
573 goto iofrootx
; /* Join common exit... */
575 panic("IOFindBSDRoot: specified root memory device, %s, has not been configured\n", rdBootVar
); /* Not there */
580 // from OpenFirmware path
581 IOLog("From path: \"%s\", ", look
);
584 if( forceNet
|| (0 == strncmp( look
, "enet", strlen( "enet" ))) ) {
585 matching
= IONetworkMatching( look
, str
, kMaxPathBuf
);
587 matching
= IODiskMatching( look
, str
, kMaxPathBuf
);
592 if( (!matching
) && rdBootVar
[0] ) {
598 if ( strncmp( look
, "en", strlen( "en" )) == 0 ) {
599 matching
= IONetworkNamePrefixMatching( "en" );
600 } else if ( strncmp( look
, "cdrom", strlen( "cdrom" )) == 0 ) {
601 matching
= IOCDMatching();
603 } else if ( strncmp( look
, "uuid", strlen( "uuid" )) == 0 ) {
605 OSString
*uuidString
;
607 uuid
= (char *)IOMalloc( kMaxBootVar
);
610 if (!PE_parse_boot_arg( "boot-uuid", uuid
)) {
611 panic( "rd=uuid but no boot-uuid=<value> specified" );
613 uuidString
= OSString::withCString( uuid
);
615 IOService::publishResource( "boot-uuid", uuidString
);
616 uuidString
->release();
617 IOLog( "\nWaiting for boot volume with UUID %s\n", uuid
);
618 matching
= IOUUIDMatching();
619 mediaProperty
= "boot-uuid-media";
621 IOFree( uuid
, kMaxBootVar
);
624 matching
= IOBSDNameMatching( look
);
631 matching
= IOService::serviceMatching( "IOMedia" );
632 astring
= OSString::withCStringNoCopy("Apple_HFS");
634 matching
->setObject("Content", astring
);
639 if( true && matching
) {
640 OSSerialize
* s
= OSSerialize::withCapacity( 5 );
642 if( matching
->serialize( s
)) {
643 IOLog( "Waiting on %s\n", s
->text() );
649 t
.tv_sec
= ROOTDEVICETIMEOUT
;
652 service
= IOService::waitForService( matching
, &t
);
653 if( (!service
) || (mountAttempts
== 10)) {
654 PE_display_icon( 0, "noroot");
655 IOLog( "Still waiting for root device\n" );
657 if( !debugInfoPrintedOnce
) {
658 debugInfoPrintedOnce
= true;
659 if( gIOKitDebug
& kIOLogDTree
) {
660 IOLog("\nDT plane:\n");
661 IOPrintPlane( gIODTPlane
);
663 if( gIOKitDebug
& kIOLogServiceTree
) {
664 IOLog("\nService plane:\n");
665 IOPrintPlane( gIOServicePlane
);
667 if( gIOKitDebug
& kIOLogMemory
)
674 if ( service
&& findHFSChild
) {
676 // wait for children services to finish registering
678 t
.tv_sec
= ROOTDEVICETIMEOUT
;
680 if ( service
->waitQuiet( &t
) == kIOReturnSuccess
) {
683 IOLog( "Waiting for child registration\n" );
686 // look for a subservice with an Apple_HFS child
687 IOService
* subservice
= IOFindMatchingChild( service
);
688 if ( subservice
) service
= subservice
;
689 } else if ( service
&& mediaProperty
) {
690 service
= (IOService
*)service
->getProperty(mediaProperty
);
696 // If the IOService we matched to is a subclass of IONetworkInterface,
697 // then make sure it has been registered with BSD and has a BSD name
701 && service
->metaCast( "IONetworkInterface" )
702 && !IORegisterNetworkInterface( service
) )
710 service
->getPath( str
, &len
, gIOServicePlane
);
711 IOLog( "Got boot device = %s\n", str
);
713 iostr
= (OSString
*) service
->getProperty( kIOBSDNameKey
);
715 strcpy( rootName
, iostr
->getCStringNoCopy() );
716 off
= (OSNumber
*) service
->getProperty( kIOBSDMajorKey
);
718 major
= off
->unsigned32BitValue();
719 off
= (OSNumber
*) service
->getProperty( kIOBSDMinorKey
);
721 minor
= off
->unsigned32BitValue();
723 if( service
->metaCast( "IONetworkInterface" ))
728 IOLog( "Wait for root failed\n" );
729 strcpy( rootName
, "en0");
733 IOLog( "BSD root: %s", rootName
);
735 IOLog(", major %d, minor %d\n", major
, minor
);
739 *root
= makedev( major
, minor
);
742 IOFree( str
, kMaxPathBuf
+ kMaxBootVar
);
745 if( (gIOKitDebug
& (kIOLogDTree
| kIOLogServiceTree
| kIOLogMemory
)) && !debugInfoPrintedOnce
) {
747 IOService::getPlatform()->waitQuiet();
748 if( gIOKitDebug
& kIOLogDTree
) {
749 IOLog("\nDT plane:\n");
750 IOPrintPlane( gIODTPlane
);
752 if( gIOKitDebug
& kIOLogServiceTree
) {
753 IOLog("\nService plane:\n");
754 IOPrintPlane( gIOServicePlane
);
756 if( gIOKitDebug
& kIOLogMemory
)
760 return( kIOReturnSuccess
);
764 IOBSDRegistryEntryForDeviceTree(char * path
)
766 return (IORegistryEntry::fromPath(path
, gIODTPlane
));
770 IOBSDRegistryEntryRelease(void * entry
)
772 IORegistryEntry
* regEntry
= (IORegistryEntry
*)entry
;
780 IOBSDRegistryEntryGetData(void * entry
, char * property_name
,
784 IORegistryEntry
* regEntry
= (IORegistryEntry
*)entry
;
786 data
= (OSData
*) regEntry
->getProperty(property_name
);
788 *packet_length
= data
->getLength();
789 return (data
->getBytesNoCopy());