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