]> git.saurik.com Git - apple/xnu.git/blame - iokit/bsddev/IOKitBSDInit.cpp
xnu-1504.3.12.tar.gz
[apple/xnu.git] / iokit / bsddev / IOKitBSDInit.cpp
CommitLineData
1c79356b 1/*
b0d623f7 2 * Copyright (c) 1998-2008 Apple Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
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.
8f6c56a5 14 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
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>
1c79356b
A
33#include <IOKit/IOPlatformExpert.h>
34
1c79356b
A
35extern "C" {
36
37#include <pexpert/pexpert.h>
38#include <kern/clock.h>
2d21ac55 39#include <uuid/uuid.h>
1c79356b
A
40
41// how long to wait for matching root device, secs
b0d623f7
A
42#if DEBUG
43#define ROOTDEVICETIMEOUT 120
44#else
45#define ROOTDEVICETIMEOUT 60
46#endif
1c79356b 47
55e303ae
A
48extern dev_t mdevadd(int devid, ppnum_t base, unsigned int size, int phys);
49extern dev_t mdevlookup(int devid);
4a3eedf9 50extern void mdevremoveall(void);
1c79356b
A
51
52kern_return_t
53IOKitBSDInit( void )
54{
1c79356b 55 IOService::publishResource("IOBSD");
b0d623f7 56
1c79356b
A
57 return( kIOReturnSuccess );
58}
59
60OSDictionary * 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
91447636
A
88OSDictionary * IOUUIDMatching( void )
89{
90 return IOService::resourceMatching( "boot-uuid-media" );
91}
92
93
55e303ae 94OSDictionary * IOCDMatching( void )
0b4e3aa0
A
95{
96 OSDictionary * dict;
97 const OSSymbol * str;
55e303ae
A
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 );
0b4e3aa0
A
114}
115
1c79356b
A
116OSDictionary * 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;
cf7d32b8 130 if( maxLen <= 0)
1c79356b
A
131 continue;
132
cf7d32b8 133 strlcpy( buf, kIODeviceTreePlane ":", len + 1 );
1c79356b
A
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;
cf7d32b8 143 if( maxLen <= 0)
1c79356b 144 continue;
cf7d32b8 145 strlcpy( comp, path, len + 1 );
1c79356b
A
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
170OSDictionary * IONetworkNamePrefixMatching( const char * prefix )
171{
172 OSDictionary * matching;
173 OSDictionary * propDict = 0;
174 const OSSymbol * str = 0;
2d21ac55
A
175 char networkType[128];
176
1c79356b
A
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
0b4e3aa0 190 propDict->setObject( "IOInterfaceNamePrefix", (OSObject *) str );
1c79356b
A
191 str->release();
192 str = 0;
193
2d21ac55
A
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
1c79356b
A
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
0b4e3aa0 224static bool IORegisterNetworkInterface( IOService * netif )
1c79356b 225{
0b4e3aa0
A
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 };
1c79356b 240
0b4e3aa0
A
241 do {
242 stack = IOService::waitForService(
243 IOService::serviceMatching("IONetworkStack") );
244 if ( stack == 0 ) break;
1c79356b 245
0b4e3aa0
A
246 dict = OSDictionary::withCapacity(3);
247 if ( dict == 0 ) break;
1c79356b 248
0b4e3aa0
A
249 zero = OSNumber::withNumber((UInt64) 0, 32);
250 if ( zero == 0 ) break;
1c79356b 251
0b4e3aa0
A
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 );
1c79356b
A
275}
276
277OSDictionary * 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;
55e303ae 284 long lun = -1;
1c79356b 285 char c;
cf7d32b8 286 int len;
1c79356b
A
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 );
55e303ae 293
1c79356b
A
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 == '@') {
91447636
A
302 unit = strtol( look + 1, &comp, 16 );
303
304 if( *comp == ',') {
305 lun = strtol( comp + 1, 0, 16 );
55e303ae
A
306 }
307
1c79356b
A
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;
55e303ae 323
cf7d32b8
A
324 len = strlen( "{" kIOPathMatchKey "='" kIODeviceTreePlane ":" );
325 maxLen -= len;
326 if( maxLen <= 0)
327 continue;
1c79356b 328
cf7d32b8
A
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 }
55e303ae 351
cf7d32b8
A
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 }
55e303ae 370
1c79356b
A
371 return( OSDynamicCast(OSDictionary, OSUnserialize( buf, 0 )) );
372
373 } while( false );
374
375 return( 0 );
376}
377
378OSDictionary * IOOFPathMatching( const char * path, char * buf, int maxLen )
379{
91447636
A
380 OSDictionary * matching;
381 OSString * str;
382 char * comp;
383 int len;
384
1c79356b
A
385 /* need to look up path, get device type,
386 call matching help based on device type */
387
91447636
A
388 matching = IODiskMatching( path, buf, maxLen );
389 if( matching)
390 return( matching );
391
392 do {
393
394 len = strlen( kIODeviceTreePlane ":" );
395 maxLen -= len;
cf7d32b8 396 if( maxLen <= 0)
91447636
A
397 continue;
398
cf7d32b8 399 strlcpy( buf, kIODeviceTreePlane ":", len + 1 );
91447636
A
400 comp = buf + len;
401
402 len = strlen( path );
403 maxLen -= len;
cf7d32b8 404 if( maxLen <= 0)
91447636 405 continue;
cf7d32b8 406 strlcpy( comp, path, len + 1 );
91447636
A
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 );
1c79356b 421
91447636
A
422 if( matching)
423 matching->release();
424
425 return( 0 );
1c79356b
A
426}
427
55e303ae
A
428IOService * 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
464static int didRam = 0;
465
cf7d32b8 466kern_return_t IOFindBSDRoot( char * rootName, unsigned int rootNameSize,
1c79356b
A
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;
55e303ae 476 UInt32 *ramdParms = 0;
1c79356b
A
477
478 UInt32 flags = 0;
2d21ac55 479 int mnr, mjr;
55e303ae 480 bool findHFSChild = false;
91447636 481 char * mediaProperty = 0;
1c79356b
A
482 char * rdBootVar;
483 enum { kMaxPathBuf = 512, kMaxBootVar = 128 };
484 char * str;
485 const char * look = 0;
486 int len;
487 bool forceNet = false;
0b4e3aa0 488 bool debugInfoPrintedOnce = false;
91447636 489 const char * uuidStr = NULL;
1c79356b
A
490
491 static int mountAttempts = 0;
55e303ae 492
91447636 493 int xchar, dchar;
55e303ae 494
1c79356b
A
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
2d21ac55
A
504 if (!PE_parse_boot_argn("rd", rdBootVar, kMaxBootVar )
505 && !PE_parse_boot_argn("rootdev", rdBootVar, kMaxBootVar ))
1c79356b
A
506 rdBootVar[0] = 0;
507
508 do {
91447636 509 if( (regEntry = IORegistryEntry::fromPath( "/chosen", gIODTPlane ))) {
0c530ab8
A
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
91447636
A
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;
55e303ae 534 }
91447636
A
535 }
536
537 // else try for an OF Path
538 data = (OSData *) regEntry->getProperty( "rootpath" );
539 regEntry->release();
540 if( data) continue;
541 }
1c79356b 542 if( (regEntry = IORegistryEntry::fromPath( "/options", gIODTPlane ))) {
91447636
A
543 data = (OSData *) regEntry->getProperty( "boot-file" );
544 regEntry->release();
545 if( data) continue;
546 }
1c79356b
A
547 } while( false );
548
91447636 549 if( data && !uuidStr)
1c79356b
A
550 look = (const char *) data->getBytesNoCopy();
551
552 if( rdBootVar[0] == '*') {
553 look = rdBootVar + 1;
55e303ae 554 forceNet = false;
1c79356b
A
555 } else {
556 if( (regEntry = IORegistryEntry::fromPath( "/", gIODTPlane ))) {
557 forceNet = (0 != regEntry->getProperty( "net-boot" ));
55e303ae
A
558 regEntry->release();
559 }
de355530 560 }
d7e50217 561
55e303ae
A
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 */
b0d623f7 576 (void)mdevadd(-1, ml_static_ptovirt(ramdParms[0]) >> 12, ramdParms[1] >> 12, 0); /* Initialize it and pass back the device number */
55e303ae
A
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
1c79356b
A
613 if( look) {
614 // from OpenFirmware path
615 IOLog("From path: \"%s\", ", look);
616
0c530ab8
A
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 }
0b4e3aa0 623 }
1c79356b 624 }
55e303ae
A
625
626 if( (!matching) && rdBootVar[0] ) {
1c79356b
A
627 // by BSD name
628 look = rdBootVar;
629 if( look[0] == '*')
630 look++;
631
0b4e3aa0
A
632 if ( strncmp( look, "en", strlen( "en" )) == 0 ) {
633 matching = IONetworkNamePrefixMatching( "en" );
55e303ae
A
634 } else if ( strncmp( look, "cdrom", strlen( "cdrom" )) == 0 ) {
635 matching = IOCDMatching();
636 findHFSChild = true;
91447636
A
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 ) {
2d21ac55 644 if (!PE_parse_boot_argn( "boot-uuid", uuid, kMaxBootVar )) {
91447636
A
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 }
0b4e3aa0
A
657 } else {
658 matching = IOBSDNameMatching( look );
659 }
1c79356b
A
660 }
661
662 if( !matching) {
2d21ac55
A
663 OSString * astring;
664 // Match any HFS media
665
1c79356b 666 matching = IOService::serviceMatching( "IOMedia" );
55e303ae 667 astring = OSString::withCStringNoCopy("Apple_HFS");
1c79356b 668 if ( astring ) {
0b4e3aa0 669 matching->setObject("Content", astring);
1c79356b
A
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
1c79356b
A
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" );
0b4e3aa0
A
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 }
1c79356b
A
705 }
706 } while( !service);
707 matching->release();
708
55e303ae
A
709 if ( service && findHFSChild ) {
710 bool waiting = true;
b0d623f7
A
711 uint64_t timeoutNS;
712
55e303ae
A
713 // wait for children services to finish registering
714 while ( waiting ) {
b0d623f7
A
715 timeoutNS = ROOTDEVICETIMEOUT;
716 timeoutNS *= kSecondScale;
717
718 if ( (service->waitQuiet(timeoutNS) ) == kIOReturnSuccess) {
55e303ae
A
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;
91447636 727 } else if ( service && mediaProperty ) {
0c530ab8 728 service = (IOService *)service->getProperty(mediaProperty);
55e303ae
A
729 }
730
2d21ac55
A
731 mjr = 0;
732 mnr = 0;
1c79356b
A
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" )
0b4e3aa0 740 && !IORegisterNetworkInterface( service ) )
1c79356b
A
741 {
742 service = 0;
743 }
1c79356b
A
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)
cf7d32b8 753 strlcpy( rootName, iostr->getCStringNoCopy(), rootNameSize );
1c79356b
A
754 off = (OSNumber *) service->getProperty( kIOBSDMajorKey );
755 if( off)
2d21ac55 756 mjr = off->unsigned32BitValue();
1c79356b
A
757 off = (OSNumber *) service->getProperty( kIOBSDMinorKey );
758 if( off)
2d21ac55 759 mnr = off->unsigned32BitValue();
1c79356b
A
760
761 if( service->metaCast( "IONetworkInterface" ))
762 flags |= 1;
763
764 } else {
765
766 IOLog( "Wait for root failed\n" );
cf7d32b8 767 strlcpy( rootName, "en0", rootNameSize );
1c79356b
A
768 flags |= 1;
769 }
770
771 IOLog( "BSD root: %s", rootName );
2d21ac55
A
772 if( mjr)
773 IOLog(", major %d, minor %d\n", mjr, mnr );
1c79356b
A
774 else
775 IOLog("\n");
776
2d21ac55 777 *root = makedev( mjr, mnr );
1c79356b
A
778 *oflags = flags;
779
780 IOFree( str, kMaxPathBuf + kMaxBootVar );
781
55e303ae 782iofrootx:
0b4e3aa0 783 if( (gIOKitDebug & (kIOLogDTree | kIOLogServiceTree | kIOLogMemory)) && !debugInfoPrintedOnce) {
1c79356b 784
0b4e3aa0 785 IOService::getPlatform()->waitQuiet();
1c79356b
A
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
2d21ac55
A
801void IOSecureBSDRoot(const char * rootName)
802{
803#if CONFIG_EMBEDDED
4a3eedf9 804 IOReturn result;
2d21ac55 805 IOPlatformExpert *pe;
4a3eedf9 806 const OSSymbol *functionName = OSSymbol::withCStringNoCopy("SecureRootName");
2d21ac55
A
807
808 while ((pe = IOService::getPlatform()) == 0) IOSleep(1 * 1000);
809
4a3eedf9
A
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);
2d21ac55
A
813
814 functionName->release();
4a3eedf9
A
815
816 if (result == kIOReturnNotPrivileged) mdevremoveall();
2d21ac55
A
817#endif
818}
819
9bccf70c
A
820void *
821IOBSDRegistryEntryForDeviceTree(char * path)
822{
823 return (IORegistryEntry::fromPath(path, gIODTPlane));
824}
825
826void
827IOBSDRegistryEntryRelease(void * entry)
828{
829 IORegistryEntry * regEntry = (IORegistryEntry *)entry;
830
831 if (regEntry)
832 regEntry->release();
833 return;
834}
835
836const void *
837IOBSDRegistryEntryGetData(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
2d21ac55
A
851kern_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
b0d623f7
A
867kern_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
896dev_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
937void 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
e2fac8b1
A
982
983int 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
1c79356b 1019} /* extern "C" */