]> git.saurik.com Git - apple/xnu.git/blob - iokit/bsddev/IOKitBSDInit.cpp
xnu-344.49.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
43 kern_return_t
44 IOKitBSDInit( void )
45 {
46 IOLog("IOKitBSDInit\n");
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( const char * name )
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", (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 char c;
260
261 // scan the tail of the path for "@unit:partition"
262 do {
263 // Have to get the full path to the controller - an alias may
264 // tell us next to nothing, like "hd:8"
265 alias = IORegistryEntry::dealiasPath( &path, gIODTPlane );
266
267 look = path + strlen( path);
268 c = ':';
269 while( look != path) {
270 if( *(--look) == c) {
271 if( c == ':') {
272 partition = strtol( look + 1, 0, 0 );
273 c = '@';
274 } else if( c == '@') {
275 unit = strtol( look + 1, 0, 16 );
276 c = '/';
277 } else if( c == '/') {
278 c = 0;
279 break;
280 }
281 }
282
283 if( alias && (look == path)) {
284 path = alias;
285 look = path + strlen( path);
286 alias = 0;
287 }
288 }
289 if( c || unit == -1 || partition == -1)
290 continue;
291
292 maxLen -= strlen( "{" kIOPathMatchKey "='" kIODeviceTreePlane ":" );
293 maxLen -= ( alias ? strlen( alias ) : 0 ) + (look - path);
294 maxLen -= strlen( "/@hhhhhhhh:dddddddddd';}" );
295
296 if( maxLen > 0) {
297 sprintf( buf, "{" kIOPathMatchKey "='" kIODeviceTreePlane ":" );
298 comp = buf + strlen( buf );
299
300 if( alias) {
301 strcpy( comp, alias );
302 comp += strlen( alias );
303 }
304
305 if ( (look - path)) {
306 strncpy( comp, path, look - path);
307 comp += look - path;
308 }
309
310 sprintf( comp, "/@%lx:%ld';}", unit, partition );
311 } else
312 continue;
313
314 return( OSDynamicCast(OSDictionary, OSUnserialize( buf, 0 )) );
315
316 } while( false );
317
318 return( 0 );
319 }
320
321 OSDictionary * IOOFPathMatching( const char * path, char * buf, int maxLen )
322 {
323 /* need to look up path, get device type,
324 call matching help based on device type */
325
326 return( IODiskMatching( path, buf, maxLen ));
327
328 }
329
330 kern_return_t IOFindBSDRoot( char * rootName,
331 dev_t * root, u_int32_t * oflags )
332 {
333 mach_timespec_t t;
334 IOService * service;
335 IORegistryEntry * regEntry;
336 OSDictionary * matching = 0;
337 OSString * iostr;
338 OSNumber * off;
339 OSData * data = 0;
340
341 UInt32 flags = 0;
342 int minor, major;
343 char * rdBootVar;
344 enum { kMaxPathBuf = 512, kMaxBootVar = 128 };
345 char * str;
346 const char * look = 0;
347 int len;
348 bool forceNet = false;
349 bool debugInfoPrintedOnce = false;
350
351 static int mountAttempts = 0;
352
353 if( mountAttempts++)
354 IOSleep( 5 * 1000 );
355
356 str = (char *) IOMalloc( kMaxPathBuf + kMaxBootVar );
357 if( !str)
358 return( kIOReturnNoMemory );
359 rdBootVar = str + kMaxPathBuf;
360
361 if (!PE_parse_boot_arg("rd", rdBootVar )
362 && !PE_parse_boot_arg("rootdev", rdBootVar ))
363 rdBootVar[0] = 0;
364
365 do {
366 if( (regEntry = IORegistryEntry::fromPath( "/chosen", gIODTPlane ))) {
367 data = (OSData *) regEntry->getProperty( "rootpath" );
368 regEntry->release();
369 if( data)
370 continue;
371 }
372 if( (regEntry = IORegistryEntry::fromPath( "/options", gIODTPlane ))) {
373 data = (OSData *) regEntry->getProperty( "boot-file" );
374 regEntry->release();
375 if( data)
376 continue;
377 }
378 } while( false );
379
380 if( data)
381 look = (const char *) data->getBytesNoCopy();
382
383 if( rdBootVar[0] == '*') {
384 look = rdBootVar + 1;
385 forceNet = false;
386 } else {
387 if( (regEntry = IORegistryEntry::fromPath( "/", gIODTPlane ))) {
388 forceNet = (0 != regEntry->getProperty( "net-boot" ));
389 regEntry->release();
390 }
391 }
392
393 if( look) {
394 // from OpenFirmware path
395 IOLog("From path: \"%s\", ", look);
396
397 if( forceNet || (0 == strncmp( look, "enet", strlen( "enet" ))) ) {
398 matching = IONetworkMatching( look, str, kMaxPathBuf );
399 } else {
400 matching = IODiskMatching( look, str, kMaxPathBuf );
401 }
402 }
403
404 if( (!matching) && rdBootVar[0] ) {
405 // by BSD name
406 look = rdBootVar;
407 if( look[0] == '*')
408 look++;
409
410 if ( strncmp( look, "en", strlen( "en" )) == 0 ) {
411 matching = IONetworkNamePrefixMatching( "en" );
412 } else if ( strncmp( look, "cdrom", strlen( "cdrom" )) == 0 ) {
413 matching = IOCDMatching( look );
414 } else {
415 matching = IOBSDNameMatching( look );
416 }
417 }
418
419 if( !matching) {
420 OSString * astring;
421 // any UFS
422 matching = IOService::serviceMatching( "IOMedia" );
423 astring = OSString::withCStringNoCopy("Apple_UFS");
424 if ( astring ) {
425 matching->setObject("Content", astring);
426 astring->release();
427 }
428 }
429
430 if( true && matching) {
431 OSSerialize * s = OSSerialize::withCapacity( 5 );
432
433 if( matching->serialize( s )) {
434 IOLog( "Waiting on %s\n", s->text() );
435 s->release();
436 }
437 }
438
439 do {
440 t.tv_sec = ROOTDEVICETIMEOUT;
441 t.tv_nsec = 0;
442 matching->retain();
443 service = IOService::waitForService( matching, &t );
444 if( (!service) || (mountAttempts == 10)) {
445 PE_display_icon( 0, "noroot");
446 IOLog( "Still waiting for root device\n" );
447
448 if( !debugInfoPrintedOnce) {
449 debugInfoPrintedOnce = true;
450 if( gIOKitDebug & kIOLogDTree) {
451 IOLog("\nDT plane:\n");
452 IOPrintPlane( gIODTPlane );
453 }
454 if( gIOKitDebug & kIOLogServiceTree) {
455 IOLog("\nService plane:\n");
456 IOPrintPlane( gIOServicePlane );
457 }
458 if( gIOKitDebug & kIOLogMemory)
459 IOPrintMemory();
460 }
461 }
462 } while( !service);
463 matching->release();
464
465 major = 0;
466 minor = 0;
467
468 // If the IOService we matched to is a subclass of IONetworkInterface,
469 // then make sure it has been registered with BSD and has a BSD name
470 // assigned.
471
472 if ( service
473 && service->metaCast( "IONetworkInterface" )
474 && !IORegisterNetworkInterface( service ) )
475 {
476 service = 0;
477 }
478
479 if( service) {
480
481 len = kMaxPathBuf;
482 service->getPath( str, &len, gIOServicePlane );
483 IOLog( "Got boot device = %s\n", str );
484
485 iostr = (OSString *) service->getProperty( kIOBSDNameKey );
486 if( iostr)
487 strcpy( rootName, iostr->getCStringNoCopy() );
488 off = (OSNumber *) service->getProperty( kIOBSDMajorKey );
489 if( off)
490 major = off->unsigned32BitValue();
491 off = (OSNumber *) service->getProperty( kIOBSDMinorKey );
492 if( off)
493 minor = off->unsigned32BitValue();
494
495 if( service->metaCast( "IONetworkInterface" ))
496 flags |= 1;
497
498 } else {
499
500 IOLog( "Wait for root failed\n" );
501 strcpy( rootName, "en0");
502 flags |= 1;
503 }
504
505 IOLog( "BSD root: %s", rootName );
506 if( major)
507 IOLog(", major %d, minor %d\n", major, minor );
508 else
509 IOLog("\n");
510
511 *root = makedev( major, minor );
512 *oflags = flags;
513
514 IOFree( str, kMaxPathBuf + kMaxBootVar );
515
516 if( (gIOKitDebug & (kIOLogDTree | kIOLogServiceTree | kIOLogMemory)) && !debugInfoPrintedOnce) {
517
518 IOService::getPlatform()->waitQuiet();
519 if( gIOKitDebug & kIOLogDTree) {
520 IOLog("\nDT plane:\n");
521 IOPrintPlane( gIODTPlane );
522 }
523 if( gIOKitDebug & kIOLogServiceTree) {
524 IOLog("\nService plane:\n");
525 IOPrintPlane( gIOServicePlane );
526 }
527 if( gIOKitDebug & kIOLogMemory)
528 IOPrintMemory();
529 }
530
531 return( kIOReturnSuccess );
532 }
533
534 void *
535 IOBSDRegistryEntryForDeviceTree(char * path)
536 {
537 return (IORegistryEntry::fromPath(path, gIODTPlane));
538 }
539
540 void
541 IOBSDRegistryEntryRelease(void * entry)
542 {
543 IORegistryEntry * regEntry = (IORegistryEntry *)entry;
544
545 if (regEntry)
546 regEntry->release();
547 return;
548 }
549
550 const void *
551 IOBSDRegistryEntryGetData(void * entry, char * property_name,
552 int * packet_length)
553 {
554 OSData * data;
555 IORegistryEntry * regEntry = (IORegistryEntry *)entry;
556
557 data = (OSData *) regEntry->getProperty(property_name);
558 if (data) {
559 *packet_length = data->getLength();
560 return (data->getBytesNoCopy());
561 }
562 return (NULL);
563 }
564
565 } /* extern "C" */