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