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
35extern "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
44extern dev_t mdevadd(int devid, ppnum_t base, unsigned int size, int phys);
45extern dev_t mdevlookup(int devid);
46extern void mdevremoveall(void);
47
48kern_return_t
49IOKitBSDInit( void )
50{
51    IOService::publishResource("IOBSD");
52
53    return( kIOReturnSuccess );
54}
55
56OSDictionary * IOBSDNameMatching( const char * name )
57{
58    OSDictionary *	dict;
59    const OSSymbol *	str = 0;
60
61    do {
62
63	dict = IOService::serviceMatching( gIOServiceKey );
64	if( !dict)
65	    continue;
66        str = OSSymbol::withCString( name );
67	if( !str)
68	    continue;
69        dict->setObject( kIOBSDNameKey, (OSObject *) str );
70        str->release();
71
72        return( dict );
73
74    } while( false );
75
76    if( dict)
77	dict->release();
78    if( str)
79	str->release();
80
81    return( 0 );
82}
83
84OSDictionary * IOUUIDMatching( void )
85{
86    return IOService::resourceMatching( "boot-uuid-media" );
87}
88
89
90OSDictionary * IOCDMatching( void )
91{
92    OSDictionary *	dict;
93    const OSSymbol *	str;
94
95    dict = IOService::serviceMatching( "IOMedia" );
96    if( dict == 0 ) {
97        IOLog("Unable to find IOMedia\n");
98        return 0;
99    }
100
101    str = OSSymbol::withCString( "CD_ROM_Mode_1" );
102    if( str == 0 ) {
103        dict->release();
104        return 0;
105    }
106
107    dict->setObject( "Content Hint", (OSObject *)str );
108    str->release();
109    return( dict );
110}
111
112OSDictionary * IONetworkMatching(  const char * path,
113				   char * buf, int maxLen )
114{
115    OSDictionary *	matching = 0;
116    OSDictionary *	dict;
117    OSString *		str;
118    char *		comp;
119    const char *	skip;
120    int			len;
121
122    do {
123
124	len = strlen( kIODeviceTreePlane ":" );
125	maxLen -= len;
126	if( maxLen <= 0)
127	    continue;
128
129	strlcpy( buf, kIODeviceTreePlane ":", len + 1 );
130	comp = buf + len;
131
132        // remove parameters following ':' from the path
133        skip = strchr( path, ':');
134	if( !skip)
135	    continue;
136
137        len = skip - path;
138	maxLen -= len;
139	if( maxLen <= 0)
140	    continue;
141	strlcpy( comp, path, len + 1 );
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
166OSDictionary * 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
220static 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
273OSDictionary * 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    int          len;
283
284    // scan the tail of the path for "@unit:partition"
285    do {
286        // Have to get the full path to the controller - an alias may
287        // tell us next to nothing, like "hd:8"
288        alias = IORegistryEntry::dealiasPath( &path, gIODTPlane );
289
290        look = path + strlen( path);
291        c = ':';
292        while( look != path) {
293            if( *(--look) == c) {
294                if( c == ':') {
295                    partition = strtol( look + 1, 0, 0 );
296                    c = '@';
297                } else if( c == '@') {
298                    unit = strtol( look + 1, &comp, 16 );
299
300                    if( *comp == ',') {
301                        lun = strtol( comp + 1, 0, 16 );
302                    }
303
304                    c = '/';
305                } else if( c == '/') {
306                    c = 0;
307                    break;
308                }
309            }
310
311	        if( alias && (look == path)) {
312                path = alias;
313                look = path + strlen( path);
314                alias = 0;
315            }
316        }
317        if( c || unit == -1 || partition == -1)
318            continue;
319
320        len = strlen( "{" kIOPathMatchKey "='" kIODeviceTreePlane ":" );
321        maxLen -= len;
322        if( maxLen <= 0)
323            continue;
324
325        snprintf( buf, len + 1, "{" kIOPathMatchKey "='" kIODeviceTreePlane ":" );
326        comp = buf + len;
327
328        if( alias) {
329            len = strlen( alias );
330            maxLen -= len;
331            if( maxLen <= 0)
332                continue;
333
334            strlcpy( comp, alias, len + 1 );
335            comp += len;
336        }
337
338        if ( (look - path)) {
339            len = (look - path);
340            maxLen -= len;
341            if( maxLen <= 0)
342                continue;
343
344            strlcpy( comp, path, len + 1 );
345            comp += len;
346        }
347
348        if ( lun != -1 )
349        {
350            len = strlen( "/@hhhhhhhh,hhhhhhhh:dddddddddd';}" );
351            maxLen -= len;
352            if( maxLen <= 0)
353                continue;
354
355            snprintf( comp, len + 1, "/@%lx,%lx:%ld';}", unit, lun, partition );
356        }
357        else
358        {
359            len = strlen( "/@hhhhhhhh:dddddddddd';}" );
360            maxLen -= len;
361            if( maxLen <= 0)
362                continue;
363
364            snprintf( comp, len + 1, "/@%lx:%ld';}", unit, partition );
365        }
366
367        return( OSDynamicCast(OSDictionary, OSUnserialize( buf, 0 )) );
368
369    } while( false );
370
371    return( 0 );
372}
373
374OSDictionary * IOOFPathMatching( const char * path, char * buf, int maxLen )
375{
376    OSDictionary *	matching;
377    OSString *		str;
378    char *		comp;
379    int			len;
380
381    /* need to look up path, get device type,
382        call matching help based on device type */
383
384    matching = IODiskMatching( path, buf, maxLen );
385    if( matching)
386	return( matching );
387
388    do {
389
390	len = strlen( kIODeviceTreePlane ":" );
391	maxLen -= len;
392	if( maxLen <= 0)
393	    continue;
394
395	strlcpy( buf, kIODeviceTreePlane ":", len + 1 );
396	comp = buf + len;
397
398	len = strlen( path );
399	maxLen -= len;
400	if( maxLen <= 0)
401	    continue;
402	strlcpy( comp, path, len + 1 );
403
404	matching = OSDictionary::withCapacity( 1 );
405	if( !matching)
406	    continue;
407
408	str = OSString::withCString( buf );
409	if( !str)
410	    continue;
411        matching->setObject( kIOPathMatchKey, str );
412	str->release();
413
414	return( matching );
415
416    } while( false );
417
418    if( matching)
419        matching->release();
420
421    return( 0 );
422}
423
424IOService * IOFindMatchingChild( IOService * service )
425{
426    // find a matching child service
427    IOService * child = 0;
428    OSIterator * iter = service->getClientIterator();
429    if ( iter ) {
430        while( ( child = (IOService *) iter->getNextObject() ) ) {
431            OSDictionary * dict = OSDictionary::withCapacity( 1 );
432            if( dict == 0 ) {
433                iter->release();
434                return 0;
435            }
436            const OSSymbol * str = OSSymbol::withCString( "Apple_HFS" );
437            if( str == 0 ) {
438                dict->release();
439                iter->release();
440                return 0;
441            }
442            dict->setObject( "Content", (OSObject *)str );
443            str->release();
444            if ( child->compareProperty( dict, "Content" ) ) {
445                dict->release();
446                break;
447            }
448            dict->release();
449            IOService * subchild = IOFindMatchingChild( child );
450            if ( subchild ) {
451                child = subchild;
452                break;
453            }
454        }
455        iter->release();
456    }
457    return child;
458}
459
460static int didRam = 0;
461
462kern_return_t IOFindBSDRoot( char * rootName, unsigned int rootNameSize,
463				dev_t * root, u_int32_t * oflags )
464{
465    mach_timespec_t	t;
466    IOService *		service;
467    IORegistryEntry *	regEntry;
468    OSDictionary *	matching = 0;
469    OSString *		iostr;
470    OSNumber *		off;
471    OSData *		data = 0;
472    UInt32		*ramdParms = 0;
473
474    UInt32		flags = 0;
475    int			mnr, mjr;
476    bool		findHFSChild = false;
477    char *              mediaProperty = 0;
478    char *		rdBootVar;
479    enum {		kMaxPathBuf = 512, kMaxBootVar = 128 };
480    char *		str;
481    const char *	look = 0;
482    int			len;
483    bool		forceNet = false;
484    bool		debugInfoPrintedOnce = false;
485    const char * 	uuidStr = NULL;
486
487    static int		mountAttempts = 0;
488
489    int xchar, dchar;
490
491
492    if( mountAttempts++)
493	IOSleep( 5 * 1000 );
494
495    str = (char *) IOMalloc( kMaxPathBuf + kMaxBootVar );
496    if( !str)
497	return( kIOReturnNoMemory );
498    rdBootVar = str + kMaxPathBuf;
499
500    if (!PE_parse_boot_argn("rd", rdBootVar, kMaxBootVar )
501     && !PE_parse_boot_argn("rootdev", rdBootVar, kMaxBootVar ))
502	rdBootVar[0] = 0;
503
504    do {
505	if( (regEntry = IORegistryEntry::fromPath( "/chosen", gIODTPlane ))) {
506            data = OSDynamicCast(OSData, regEntry->getProperty( "root-matching" ));
507            if (data) {
508               matching = OSDynamicCast(OSDictionary, OSUnserializeXML((char *)data->getBytesNoCopy()));
509                if (matching) {
510                    continue;
511                }
512            }
513
514	    data = (OSData *) regEntry->getProperty( "boot-uuid" );
515	    if( data) {
516		uuidStr = (const char*)data->getBytesNoCopy();
517		OSString *uuidString = OSString::withCString( uuidStr );
518
519		// match the boot-args boot-uuid processing below
520		if( uuidString) {
521		    IOLog("rooting via boot-uuid from /chosen: %s\n", uuidStr);
522		    IOService::publishResource( "boot-uuid", uuidString );
523		    uuidString->release();
524		    matching = IOUUIDMatching();
525		    mediaProperty = "boot-uuid-media";
526		    regEntry->release();
527		    continue;
528		} else {
529		    uuidStr = NULL;
530		}
531	    }
532
533	    // else try for an OF Path
534	    data = (OSData *) regEntry->getProperty( "rootpath" );
535	    regEntry->release();
536	    if( data) continue;
537	}
538        if( (regEntry = IORegistryEntry::fromPath( "/options", gIODTPlane ))) {
539	    data = (OSData *) regEntry->getProperty( "boot-file" );
540	    regEntry->release();
541	    if( data) continue;
542	}
543    } while( false );
544
545    if( data && !uuidStr)
546        look = (const char *) data->getBytesNoCopy();
547
548    if( rdBootVar[0] == '*') {
549        look = rdBootVar + 1;
550		forceNet = false;
551    } else {
552        if( (regEntry = IORegistryEntry::fromPath( "/", gIODTPlane ))) {
553            forceNet = (0 != regEntry->getProperty( "net-boot" ));
554	    	regEntry->release();
555		}
556    }
557
558
559
560//
561//	See if we have a RAMDisk property in /chosen/memory-map.  If so, make it into a device.
562//	It will become /dev/mdx, where x is 0-f.
563//
564
565	if(!didRam) {												/* Have we already build this ram disk? */
566		didRam = 1;												/* Remember we did this */
567		if((regEntry = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane ))) {	/* Find the map node */
568			data = (OSData *)regEntry->getProperty("RAMDisk");	/* Find the ram disk, if there */
569			if(data) {											/* We found one */
570
571				ramdParms = (UInt32 *)data->getBytesNoCopy();	/* Point to the ram disk base and size */
572				(void)mdevadd(-1, ramdParms[0] >> 12, ramdParms[1] >> 12, 0);	/* Initialize it and pass back the device number */
573			}
574			regEntry->release();								/* Toss the entry */
575		}
576	}
577
578//
579//	Now check if we are trying to root on a memory device
580//
581
582	if((rdBootVar[0] == 'm') && (rdBootVar[1] == 'd') && (rdBootVar[3] == 0)) {
583		dchar = xchar = rdBootVar[2];							/* Get the actual device */
584		if((xchar >= '0') && (xchar <= '9')) xchar = xchar - '0';	/* If digit, convert */
585		else {
586			xchar = xchar & ~' ';								/* Fold to upper case */
587			if((xchar >= 'A') && (xchar <= 'F')) {				/* Is this a valid digit? */
588				xchar = (xchar & 0xF) + 9;						/* Convert the hex digit */
589				dchar = dchar | ' ';							/* Fold to lower case */
590			}
591			else xchar = -1;									/* Show bogus */
592		}
593		if(xchar >= 0) {										/* Do we have a valid memory device name? */
594			*root = mdevlookup(xchar);							/* Find the device number */
595			if(*root >= 0) {									/* Did we find one? */
596
597				rootName[0] = 'm';								/* Build root name */
598				rootName[1] = 'd';								/* Build root name */
599				rootName[2] = dchar;							/* Build root name */
600				rootName[3] = 0;								/* Build root name */
601				IOLog("BSD root: %s, major %d, minor %d\n", rootName, major(*root), minor(*root));
602				*oflags = 0;									/* Show that this is not network */
603				goto iofrootx;									/* Join common exit... */
604			}
605			panic("IOFindBSDRoot: specified root memory device, %s, has not been configured\n", rdBootVar);	/* Not there */
606		}
607	}
608
609    if( look) {
610	// from OpenFirmware path
611	IOLog("From path: \"%s\", ", look);
612
613        if (!matching) {
614            if( forceNet || (0 == strncmp( look, "enet", strlen( "enet" ))) ) {
615                matching = IONetworkMatching( look, str, kMaxPathBuf );
616            } else {
617                matching = IODiskMatching( look, str, kMaxPathBuf );
618            }
619        }
620    }
621
622      if( (!matching) && rdBootVar[0] ) {
623	// by BSD name
624	look = rdBootVar;
625	if( look[0] == '*')
626	    look++;
627
628	if ( strncmp( look, "en", strlen( "en" )) == 0 ) {
629	    matching = IONetworkNamePrefixMatching( "en" );
630	} else if ( strncmp( look, "cdrom", strlen( "cdrom" )) == 0 ) {
631            matching = IOCDMatching();
632            findHFSChild = true;
633        } else if ( strncmp( look, "uuid", strlen( "uuid" )) == 0 ) {
634            char *uuid;
635            OSString *uuidString;
636
637            uuid = (char *)IOMalloc( kMaxBootVar );
638
639            if ( uuid ) {
640                if (!PE_parse_boot_argn( "boot-uuid", uuid, kMaxBootVar )) {
641                    panic( "rd=uuid but no boot-uuid=<value> specified" );
642                }
643                uuidString = OSString::withCString( uuid );
644                if ( uuidString ) {
645                    IOService::publishResource( "boot-uuid", uuidString );
646                    uuidString->release();
647                    IOLog( "\nWaiting for boot volume with UUID %s\n", uuid );
648                    matching = IOUUIDMatching();
649                    mediaProperty = "boot-uuid-media";
650                }
651                IOFree( uuid, kMaxBootVar );
652            }
653	} else {
654	    matching = IOBSDNameMatching( look );
655	}
656    }
657
658    if( !matching) {
659	OSString * astring;
660	// Match any HFS media
661
662        matching = IOService::serviceMatching( "IOMedia" );
663        astring = OSString::withCStringNoCopy("Apple_HFS");
664        if ( astring ) {
665            matching->setObject("Content", astring);
666            astring->release();
667        }
668    }
669
670    if( true && matching) {
671        OSSerialize * s = OSSerialize::withCapacity( 5 );
672
673        if( matching->serialize( s )) {
674            IOLog( "Waiting on %s\n", s->text() );
675            s->release();
676        }
677    }
678
679    do {
680        t.tv_sec = ROOTDEVICETIMEOUT;
681        t.tv_nsec = 0;
682	matching->retain();
683        service = IOService::waitForService( matching, &t );
684	if( (!service) || (mountAttempts == 10)) {
685            PE_display_icon( 0, "noroot");
686            IOLog( "Still waiting for root device\n" );
687
688            if( !debugInfoPrintedOnce) {
689                debugInfoPrintedOnce = true;
690                if( gIOKitDebug & kIOLogDTree) {
691                    IOLog("\nDT plane:\n");
692                    IOPrintPlane( gIODTPlane );
693                }
694                if( gIOKitDebug & kIOLogServiceTree) {
695                    IOLog("\nService plane:\n");
696                    IOPrintPlane( gIOServicePlane );
697                }
698                if( gIOKitDebug & kIOLogMemory)
699                    IOPrintMemory();
700            }
701	}
702    } while( !service);
703    matching->release();
704
705    if ( service && findHFSChild ) {
706        bool waiting = true;
707        // wait for children services to finish registering
708        while ( waiting ) {
709            t.tv_sec = ROOTDEVICETIMEOUT;
710            t.tv_nsec = 0;
711            if ( service->waitQuiet( &t ) == kIOReturnSuccess ) {
712                waiting = false;
713            } else {
714                IOLog( "Waiting for child registration\n" );
715            }
716        }
717        // look for a subservice with an Apple_HFS child
718        IOService * subservice = IOFindMatchingChild( service );
719        if ( subservice ) service = subservice;
720    } else if ( service && mediaProperty ) {
721        service = (IOService *)service->getProperty(mediaProperty);
722    }
723
724    mjr = 0;
725    mnr = 0;
726
727    // If the IOService we matched to is a subclass of IONetworkInterface,
728    // then make sure it has been registered with BSD and has a BSD name
729    // assigned.
730
731    if ( service
732    &&   service->metaCast( "IONetworkInterface" )
733    &&   !IORegisterNetworkInterface( service ) )
734    {
735        service = 0;
736    }
737
738    if( service) {
739
740	len = kMaxPathBuf;
741	service->getPath( str, &len, gIOServicePlane );
742	IOLog( "Got boot device = %s\n", str );
743
744	iostr = (OSString *) service->getProperty( kIOBSDNameKey );
745	if( iostr)
746	    strlcpy( rootName, iostr->getCStringNoCopy(), rootNameSize );
747	off = (OSNumber *) service->getProperty( kIOBSDMajorKey );
748	if( off)
749	    mjr = off->unsigned32BitValue();
750	off = (OSNumber *) service->getProperty( kIOBSDMinorKey );
751	if( off)
752	    mnr = off->unsigned32BitValue();
753
754	if( service->metaCast( "IONetworkInterface" ))
755	    flags |= 1;
756
757    } else {
758
759	IOLog( "Wait for root failed\n" );
760        strlcpy( rootName, "en0", rootNameSize );
761        flags |= 1;
762    }
763
764    IOLog( "BSD root: %s", rootName );
765    if( mjr)
766	IOLog(", major %d, minor %d\n", mjr, mnr );
767    else
768	IOLog("\n");
769
770    *root = makedev( mjr, mnr );
771    *oflags = flags;
772
773    IOFree( str,  kMaxPathBuf + kMaxBootVar );
774
775iofrootx:
776    if( (gIOKitDebug & (kIOLogDTree | kIOLogServiceTree | kIOLogMemory)) && !debugInfoPrintedOnce) {
777
778	IOService::getPlatform()->waitQuiet();
779        if( gIOKitDebug & kIOLogDTree) {
780            IOLog("\nDT plane:\n");
781            IOPrintPlane( gIODTPlane );
782        }
783        if( gIOKitDebug & kIOLogServiceTree) {
784            IOLog("\nService plane:\n");
785            IOPrintPlane( gIOServicePlane );
786        }
787        if( gIOKitDebug & kIOLogMemory)
788            IOPrintMemory();
789    }
790
791    return( kIOReturnSuccess );
792}
793
794void IOSecureBSDRoot(const char * rootName)
795{
796#if CONFIG_EMBEDDED
797    IOReturn         result;
798    IOPlatformExpert *pe;
799    const OSSymbol   *functionName = OSSymbol::withCStringNoCopy("SecureRootName");
800
801    while ((pe = IOService::getPlatform()) == 0) IOSleep(1 * 1000);
802
803    // Returns kIOReturnNotPrivileged is the root device is not secure.
804    // Returns kIOReturnUnsupported if "SecureRootName" is not implemented.
805    result = pe->callPlatformFunction(functionName, false, (void *)rootName, (void *)0, (void *)0, (void *)0);
806
807    functionName->release();
808
809    if (result == kIOReturnNotPrivileged) mdevremoveall();
810#endif
811}
812
813void *
814IOBSDRegistryEntryForDeviceTree(char * path)
815{
816    return (IORegistryEntry::fromPath(path, gIODTPlane));
817}
818
819void
820IOBSDRegistryEntryRelease(void * entry)
821{
822    IORegistryEntry * regEntry = (IORegistryEntry *)entry;
823
824    if (regEntry)
825	regEntry->release();
826    return;
827}
828
829const void *
830IOBSDRegistryEntryGetData(void * entry, char * property_name,
831			  int * packet_length)
832{
833    OSData *		data;
834    IORegistryEntry * 	regEntry = (IORegistryEntry *)entry;
835
836    data = (OSData *) regEntry->getProperty(property_name);
837    if (data) {
838	*packet_length = data->getLength();
839        return (data->getBytesNoCopy());
840    }
841    return (NULL);
842}
843
844kern_return_t IOBSDGetPlatformUUID( uuid_t uuid, mach_timespec_t timeout )
845{
846    IOService * resources;
847    OSString *  string;
848
849    resources = IOService::waitForService( IOService::resourceMatching( kIOPlatformUUIDKey ), &timeout );
850    if ( resources == 0 ) return KERN_OPERATION_TIMED_OUT;
851
852    string = ( OSString * ) IOService::getPlatform( )->getProvider( )->getProperty( kIOPlatformUUIDKey );
853    if ( string == 0 ) return KERN_NOT_SUPPORTED;
854
855    uuid_parse( string->getCStringNoCopy( ), uuid );
856
857    return KERN_SUCCESS;
858}
859
860
861int IOBSDIsMediaEjectable( const char *cdev_name )
862{
863    int ret = 0;
864    OSDictionary *dictionary;
865    OSString *dev_name;
866
867    if (strncmp(cdev_name, "/dev/", 5) == 0) {
868	    cdev_name += 5;
869    }
870
871    dictionary = IOService::serviceMatching( "IOMedia" );
872    if( dictionary ) {
873	dev_name = OSString::withCString( cdev_name );
874	if( dev_name ) {
875	    IOService *service;
876	    mach_timespec_t tv = { 5, 0 };    // wait up to "timeout" seconds for the device
877
878	    dictionary->setObject( kIOBSDNameKey, dev_name );
879	    dictionary->retain();
880	    service = IOService::waitForService( dictionary, &tv );
881	    if( service ) {
882		OSBoolean *ejectable = (OSBoolean *) service->getProperty( "Ejectable" );
883
884		if( ejectable ) {
885			ret = (int)ejectable->getValue();
886		}
887
888	    }
889	    dev_name->release();
890	}
891	dictionary->release();
892    }
893
894    return ret;
895}
896
897} /* extern "C" */
898