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