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