]> git.saurik.com Git - apple/xnu.git/blob - iokit/bsddev/IOKitBSDInit.cpp
xnu-517.tar.gz
[apple/xnu.git] / iokit / bsddev / IOKitBSDInit.cpp
1 /*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 #include <IOKit/IOBSD.h>
26 #include <IOKit/IOLib.h>
27 #include <IOKit/IOService.h>
28 #include <IOKit/IODeviceTreeSupport.h>
29 #include <IOKit/IOKitKeys.h>
30 #include <IOKit/IOPlatformExpert.h>
31
32 #include <sys/disklabel.h>
33
34 extern "C" {
35
36 #include <pexpert/pexpert.h>
37 #include <kern/clock.h>
38
39 // how long to wait for matching root device, secs
40 #define ROOTDEVICETIMEOUT 60
41
42 extern dev_t mdevadd(int devid, ppnum_t base, unsigned int size, int phys);
43 extern dev_t mdevlookup(int devid);
44
45 kern_return_t
46 IOKitBSDInit( void )
47 {
48 IOService::publishResource("IOBSD");
49
50 return( kIOReturnSuccess );
51 }
52
53 OSDictionary * IOBSDNameMatching( const char * name )
54 {
55 OSDictionary * dict;
56 const OSSymbol * str = 0;
57
58 do {
59
60 dict = IOService::serviceMatching( gIOServiceKey );
61 if( !dict)
62 continue;
63 str = OSSymbol::withCString( name );
64 if( !str)
65 continue;
66 dict->setObject( kIOBSDNameKey, (OSObject *) str );
67 str->release();
68
69 return( dict );
70
71 } while( false );
72
73 if( dict)
74 dict->release();
75 if( str)
76 str->release();
77
78 return( 0 );
79 }
80
81 OSDictionary * IOCDMatching( void )
82 {
83 OSDictionary * dict;
84 const OSSymbol * str;
85
86 dict = IOService::serviceMatching( "IOMedia" );
87 if( dict == 0 ) {
88 IOLog("Unable to find IOMedia\n");
89 return 0;
90 }
91
92 str = OSSymbol::withCString( "CD_ROM_Mode_1" );
93 if( str == 0 ) {
94 dict->release();
95 return 0;
96 }
97
98 dict->setObject( "Content Hint", (OSObject *)str );
99 str->release();
100 return( dict );
101 }
102
103 OSDictionary * IONetworkMatching( const char * path,
104 char * buf, int maxLen )
105 {
106 OSDictionary * matching = 0;
107 OSDictionary * dict;
108 OSString * str;
109 char * comp;
110 const char * skip;
111 int len;
112
113 do {
114
115 len = strlen( kIODeviceTreePlane ":" );
116 maxLen -= len;
117 if( maxLen < 0)
118 continue;
119
120 strcpy( buf, kIODeviceTreePlane ":" );
121 comp = buf + len;
122
123 // remove parameters following ':' from the path
124 skip = strchr( path, ':');
125 if( !skip)
126 continue;
127
128 len = skip - path;
129 maxLen -= len;
130 if( maxLen < 0)
131 continue;
132 strncpy( comp, path, len );
133 comp[ len ] = 0;
134
135 matching = IOService::serviceMatching( "IONetworkInterface" );
136 if( !matching)
137 continue;
138 dict = IOService::addLocation( matching );
139 if( !dict)
140 continue;
141
142 str = OSString::withCString( buf );
143 if( !str)
144 continue;
145 dict->setObject( kIOPathMatchKey, str );
146 str->release();
147
148 return( matching );
149
150 } while( false );
151
152 if( matching)
153 matching->release();
154
155 return( 0 );
156 }
157
158 OSDictionary * IONetworkNamePrefixMatching( const char * prefix )
159 {
160 OSDictionary * matching;
161 OSDictionary * propDict = 0;
162 const OSSymbol * str = 0;
163
164 do {
165 matching = IOService::serviceMatching( "IONetworkInterface" );
166 if ( matching == 0 )
167 continue;
168
169 propDict = OSDictionary::withCapacity(1);
170 if ( propDict == 0 )
171 continue;
172
173 str = OSSymbol::withCString( prefix );
174 if ( str == 0 )
175 continue;
176
177 propDict->setObject( "IOInterfaceNamePrefix", (OSObject *) str );
178 str->release();
179 str = 0;
180
181 if ( matching->setObject( gIOPropertyMatchKey,
182 (OSObject *) propDict ) != true )
183 continue;
184
185 propDict->release();
186 propDict = 0;
187
188 return( matching );
189
190 } while ( false );
191
192 if ( matching ) matching->release();
193 if ( propDict ) propDict->release();
194 if ( str ) str->release();
195
196 return( 0 );
197 }
198
199 static bool IORegisterNetworkInterface( IOService * netif )
200 {
201 // A network interface is typically named and registered
202 // with BSD after receiving a request from a user space
203 // "namer". However, for cases when the system needs to
204 // root from the network, this registration task must be
205 // done inside the kernel and completed before the root
206 // device is handed to BSD.
207
208 IOService * stack;
209 OSNumber * zero = 0;
210 OSString * path = 0;
211 OSDictionary * dict = 0;
212 char * pathBuf = 0;
213 int len;
214 enum { kMaxPathLen = 512 };
215
216 do {
217 stack = IOService::waitForService(
218 IOService::serviceMatching("IONetworkStack") );
219 if ( stack == 0 ) break;
220
221 dict = OSDictionary::withCapacity(3);
222 if ( dict == 0 ) break;
223
224 zero = OSNumber::withNumber((UInt64) 0, 32);
225 if ( zero == 0 ) break;
226
227 pathBuf = (char *) IOMalloc( kMaxPathLen );
228 if ( pathBuf == 0 ) break;
229
230 len = kMaxPathLen;
231 if ( netif->getPath( pathBuf, &len, gIOServicePlane )
232 == false ) break;
233
234 path = OSString::withCStringNoCopy( pathBuf );
235 if ( path == 0 ) break;
236
237 dict->setObject( "IOInterfaceUnit", zero );
238 dict->setObject( kIOPathMatchKey, path );
239
240 stack->setProperties( dict );
241 }
242 while ( false );
243
244 if ( zero ) zero->release();
245 if ( path ) path->release();
246 if ( dict ) dict->release();
247 if ( pathBuf ) IOFree(pathBuf, kMaxPathLen);
248
249 return ( netif->getProperty( kIOBSDNameKey ) != 0 );
250 }
251
252 OSDictionary * IODiskMatching( const char * path, char * buf, int maxLen )
253 {
254 const char * look;
255 const char * alias;
256 char * comp;
257 long unit = -1;
258 long partition = -1;
259 long lun = -1;
260 char c;
261 const char * partitionSep = NULL;
262
263 // scan the tail of the path for "@unit:partition"
264 do {
265 // Have to get the full path to the controller - an alias may
266 // tell us next to nothing, like "hd:8"
267 alias = IORegistryEntry::dealiasPath( &path, gIODTPlane );
268
269 look = path + strlen( path);
270 c = ':';
271 while( look != path) {
272 if( *(--look) == c) {
273 if( c == ':') {
274 partition = strtol( look + 1, 0, 0 );
275 partitionSep = look;
276 c = '@';
277 } else if( c == '@') {
278 int diff = -1;
279
280 unit = strtol( look + 1, 0, 16 );
281
282 diff = (int)partitionSep - (int)look;
283 if ( diff > 0 ) {
284
285 for ( ; diff > 0; diff-- )
286 {
287 if( look[diff] == ',' )
288 {
289 lun = strtol ( &look[diff + 1], 0, 16 );
290 break;
291 }
292 }
293 }
294
295 c = '/';
296 } else if( c == '/') {
297 c = 0;
298 break;
299 }
300 }
301
302 if( alias && (look == path)) {
303 path = alias;
304 look = path + strlen( path);
305 alias = 0;
306 }
307 }
308 if( c || unit == -1 || partition == -1)
309 continue;
310
311 maxLen -= strlen( "{" kIOPathMatchKey "='" kIODeviceTreePlane ":" );
312 maxLen -= ( alias ? strlen( alias ) : 0 ) + (look - path);
313 maxLen -= strlen( "/@hhhhhhhh,hhhhhhhh:dddddddddd';}" );
314
315 if( maxLen > 0) {
316 sprintf( buf, "{" kIOPathMatchKey "='" kIODeviceTreePlane ":" );
317 comp = buf + strlen( buf );
318
319 if( alias) {
320 strcpy( comp, alias );
321 comp += strlen( alias );
322 }
323
324 if ( (look - path)) {
325 strncpy( comp, path, look - path);
326 comp += look - path;
327 }
328
329 if ( lun != -1 )
330 {
331 sprintf ( comp, "/@%lx,%lx:%ld';}", unit, lun, partition );
332 }
333 else
334 {
335 sprintf( comp, "/@%lx:%ld';}", unit, partition );
336 }
337 } else
338 continue;
339
340 return( OSDynamicCast(OSDictionary, OSUnserialize( buf, 0 )) );
341
342 } while( false );
343
344 return( 0 );
345 }
346
347 OSDictionary * IOOFPathMatching( const char * path, char * buf, int maxLen )
348 {
349 /* need to look up path, get device type,
350 call matching help based on device type */
351
352 return( IODiskMatching( path, buf, maxLen ));
353
354 }
355
356 IOService * IOFindMatchingChild( IOService * service )
357 {
358 // find a matching child service
359 IOService * child = 0;
360 OSIterator * iter = service->getClientIterator();
361 if ( iter ) {
362 while( ( child = (IOService *) iter->getNextObject() ) ) {
363 OSDictionary * dict = OSDictionary::withCapacity( 1 );
364 if( dict == 0 ) {
365 iter->release();
366 return 0;
367 }
368 const OSSymbol * str = OSSymbol::withCString( "Apple_HFS" );
369 if( str == 0 ) {
370 dict->release();
371 iter->release();
372 return 0;
373 }
374 dict->setObject( "Content", (OSObject *)str );
375 str->release();
376 if ( child->compareProperty( dict, "Content" ) ) {
377 dict->release();
378 break;
379 }
380 dict->release();
381 IOService * subchild = IOFindMatchingChild( child );
382 if ( subchild ) {
383 child = subchild;
384 break;
385 }
386 }
387 iter->release();
388 }
389 return child;
390 }
391
392 static int didRam = 0;
393
394 kern_return_t IOFindBSDRoot( char * rootName,
395 dev_t * root, u_int32_t * oflags )
396 {
397 mach_timespec_t t;
398 IOService * service;
399 IORegistryEntry * regEntry;
400 OSDictionary * matching = 0;
401 OSString * iostr;
402 OSNumber * off;
403 OSData * data = 0;
404 UInt32 *ramdParms = 0;
405
406 UInt32 flags = 0;
407 int minor, major;
408 bool findHFSChild = false;
409 char * rdBootVar;
410 enum { kMaxPathBuf = 512, kMaxBootVar = 128 };
411 char * str;
412 const char * look = 0;
413 int len;
414 bool forceNet = false;
415 bool debugInfoPrintedOnce = false;
416
417 static int mountAttempts = 0;
418
419 int xchar, dchar;
420
421
422 if( mountAttempts++)
423 IOSleep( 5 * 1000 );
424
425 str = (char *) IOMalloc( kMaxPathBuf + kMaxBootVar );
426 if( !str)
427 return( kIOReturnNoMemory );
428 rdBootVar = str + kMaxPathBuf;
429
430 if (!PE_parse_boot_arg("rd", rdBootVar )
431 && !PE_parse_boot_arg("rootdev", rdBootVar ))
432 rdBootVar[0] = 0;
433
434 do {
435 if( (regEntry = IORegistryEntry::fromPath( "/chosen", gIODTPlane ))) {
436 data = (OSData *) regEntry->getProperty( "rootpath" );
437 regEntry->release();
438 if( data) continue;
439 }
440 if( (regEntry = IORegistryEntry::fromPath( "/options", gIODTPlane ))) {
441 data = (OSData *) regEntry->getProperty( "boot-file" );
442 regEntry->release();
443 if( data) continue;
444 }
445 } while( false );
446
447 if( data)
448 look = (const char *) data->getBytesNoCopy();
449
450 if( rdBootVar[0] == '*') {
451 look = rdBootVar + 1;
452 forceNet = false;
453 } else {
454 if( (regEntry = IORegistryEntry::fromPath( "/", gIODTPlane ))) {
455 forceNet = (0 != regEntry->getProperty( "net-boot" ));
456 regEntry->release();
457 }
458 }
459
460
461
462 //
463 // See if we have a RAMDisk property in /chosen/memory-map. If so, make it into a device.
464 // It will become /dev/mdx, where x is 0-f.
465 //
466
467 if(!didRam) { /* Have we already build this ram disk? */
468 didRam = 1; /* Remember we did this */
469 if((regEntry = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane ))) { /* Find the map node */
470 data = (OSData *)regEntry->getProperty("RAMDisk"); /* Find the ram disk, if there */
471 if(data) { /* We found one */
472
473 ramdParms = (UInt32 *)data->getBytesNoCopy(); /* Point to the ram disk base and size */
474 (void)mdevadd(-1, ramdParms[0] >> 12, ramdParms[1] >> 12, 0); /* Initialize it and pass back the device number */
475 }
476 regEntry->release(); /* Toss the entry */
477 }
478 }
479
480 //
481 // Now check if we are trying to root on a memory device
482 //
483
484 if((rdBootVar[0] == 'm') && (rdBootVar[1] == 'd') && (rdBootVar[3] == 0)) {
485 dchar = xchar = rdBootVar[2]; /* Get the actual device */
486 if((xchar >= '0') && (xchar <= '9')) xchar = xchar - '0'; /* If digit, convert */
487 else {
488 xchar = xchar & ~' '; /* Fold to upper case */
489 if((xchar >= 'A') && (xchar <= 'F')) { /* Is this a valid digit? */
490 xchar = (xchar & 0xF) + 9; /* Convert the hex digit */
491 dchar = dchar | ' '; /* Fold to lower case */
492 }
493 else xchar = -1; /* Show bogus */
494 }
495 if(xchar >= 0) { /* Do we have a valid memory device name? */
496 *root = mdevlookup(xchar); /* Find the device number */
497 if(*root >= 0) { /* Did we find one? */
498
499 rootName[0] = 'm'; /* Build root name */
500 rootName[1] = 'd'; /* Build root name */
501 rootName[2] = dchar; /* Build root name */
502 rootName[3] = 0; /* Build root name */
503 IOLog("BSD root: %s, major %d, minor %d\n", rootName, major(*root), minor(*root));
504 *oflags = 0; /* Show that this is not network */
505 goto iofrootx; /* Join common exit... */
506 }
507 panic("IOFindBSDRoot: specified root memory device, %s, has not been configured\n", rdBootVar); /* Not there */
508 }
509 }
510
511 if( look) {
512 // from OpenFirmware path
513 IOLog("From path: \"%s\", ", look);
514
515 if( forceNet || (0 == strncmp( look, "enet", strlen( "enet" ))) ) {
516 matching = IONetworkMatching( look, str, kMaxPathBuf );
517 } else {
518 matching = IODiskMatching( look, str, kMaxPathBuf );
519 }
520 }
521
522 if( (!matching) && rdBootVar[0] ) {
523 // by BSD name
524 look = rdBootVar;
525 if( look[0] == '*')
526 look++;
527
528 if ( strncmp( look, "en", strlen( "en" )) == 0 ) {
529 matching = IONetworkNamePrefixMatching( "en" );
530 } else if ( strncmp( look, "cdrom", strlen( "cdrom" )) == 0 ) {
531 matching = IOCDMatching();
532 findHFSChild = true;
533 } else {
534 matching = IOBSDNameMatching( look );
535 }
536 }
537
538 if( !matching) {
539 OSString * astring;
540 // any HFS
541 matching = IOService::serviceMatching( "IOMedia" );
542 astring = OSString::withCStringNoCopy("Apple_HFS");
543 if ( astring ) {
544 matching->setObject("Content", astring);
545 astring->release();
546 }
547 }
548
549 if( true && matching) {
550 OSSerialize * s = OSSerialize::withCapacity( 5 );
551
552 if( matching->serialize( s )) {
553 IOLog( "Waiting on %s\n", s->text() );
554 s->release();
555 }
556 }
557
558 do {
559 t.tv_sec = ROOTDEVICETIMEOUT;
560 t.tv_nsec = 0;
561 matching->retain();
562 service = IOService::waitForService( matching, &t );
563 if( (!service) || (mountAttempts == 10)) {
564 PE_display_icon( 0, "noroot");
565 IOLog( "Still waiting for root device\n" );
566
567 if( !debugInfoPrintedOnce) {
568 debugInfoPrintedOnce = true;
569 if( gIOKitDebug & kIOLogDTree) {
570 IOLog("\nDT plane:\n");
571 IOPrintPlane( gIODTPlane );
572 }
573 if( gIOKitDebug & kIOLogServiceTree) {
574 IOLog("\nService plane:\n");
575 IOPrintPlane( gIOServicePlane );
576 }
577 if( gIOKitDebug & kIOLogMemory)
578 IOPrintMemory();
579 }
580 }
581 } while( !service);
582 matching->release();
583
584 if ( service && findHFSChild ) {
585 bool waiting = true;
586 // wait for children services to finish registering
587 while ( waiting ) {
588 t.tv_sec = ROOTDEVICETIMEOUT;
589 t.tv_nsec = 0;
590 if ( service->waitQuiet( &t ) == kIOReturnSuccess ) {
591 waiting = false;
592 } else {
593 IOLog( "Waiting for child registration\n" );
594 }
595 }
596 // look for a subservice with an Apple_HFS child
597 IOService * subservice = IOFindMatchingChild( service );
598 if ( subservice ) service = subservice;
599 }
600
601 major = 0;
602 minor = 0;
603
604 // If the IOService we matched to is a subclass of IONetworkInterface,
605 // then make sure it has been registered with BSD and has a BSD name
606 // assigned.
607
608 if ( service
609 && service->metaCast( "IONetworkInterface" )
610 && !IORegisterNetworkInterface( service ) )
611 {
612 service = 0;
613 }
614
615 if( service) {
616
617 len = kMaxPathBuf;
618 service->getPath( str, &len, gIOServicePlane );
619 IOLog( "Got boot device = %s\n", str );
620
621 iostr = (OSString *) service->getProperty( kIOBSDNameKey );
622 if( iostr)
623 strcpy( rootName, iostr->getCStringNoCopy() );
624 off = (OSNumber *) service->getProperty( kIOBSDMajorKey );
625 if( off)
626 major = off->unsigned32BitValue();
627 off = (OSNumber *) service->getProperty( kIOBSDMinorKey );
628 if( off)
629 minor = off->unsigned32BitValue();
630
631 if( service->metaCast( "IONetworkInterface" ))
632 flags |= 1;
633
634 } else {
635
636 IOLog( "Wait for root failed\n" );
637 strcpy( rootName, "en0");
638 flags |= 1;
639 }
640
641 IOLog( "BSD root: %s", rootName );
642 if( major)
643 IOLog(", major %d, minor %d\n", major, minor );
644 else
645 IOLog("\n");
646
647 *root = makedev( major, minor );
648 *oflags = flags;
649
650 IOFree( str, kMaxPathBuf + kMaxBootVar );
651
652 iofrootx:
653 if( (gIOKitDebug & (kIOLogDTree | kIOLogServiceTree | kIOLogMemory)) && !debugInfoPrintedOnce) {
654
655 IOService::getPlatform()->waitQuiet();
656 if( gIOKitDebug & kIOLogDTree) {
657 IOLog("\nDT plane:\n");
658 IOPrintPlane( gIODTPlane );
659 }
660 if( gIOKitDebug & kIOLogServiceTree) {
661 IOLog("\nService plane:\n");
662 IOPrintPlane( gIOServicePlane );
663 }
664 if( gIOKitDebug & kIOLogMemory)
665 IOPrintMemory();
666 }
667
668 return( kIOReturnSuccess );
669 }
670
671 void *
672 IOBSDRegistryEntryForDeviceTree(char * path)
673 {
674 return (IORegistryEntry::fromPath(path, gIODTPlane));
675 }
676
677 void
678 IOBSDRegistryEntryRelease(void * entry)
679 {
680 IORegistryEntry * regEntry = (IORegistryEntry *)entry;
681
682 if (regEntry)
683 regEntry->release();
684 return;
685 }
686
687 const void *
688 IOBSDRegistryEntryGetData(void * entry, char * property_name,
689 int * packet_length)
690 {
691 OSData * data;
692 IORegistryEntry * regEntry = (IORegistryEntry *)entry;
693
694 data = (OSData *) regEntry->getProperty(property_name);
695 if (data) {
696 *packet_length = data->getLength();
697 return (data->getBytesNoCopy());
698 }
699 return (NULL);
700 }
701
702 } /* extern "C" */