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