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