]> git.saurik.com Git - apple/xnu.git/blob - iokit/bsddev/IOKitBSDInit.cpp
b161dbf608157cd1c10ba21a7ecaa1949bf0c713
[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/storage/IOMedia.h>
28 #include <IOKit/network/IONetworkStack.h>
29 #include <IOKit/network/IONetworkInterface.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 * IONetworkMatching( const char * path,
82 char * buf, int maxLen )
83 {
84 OSDictionary * matching = 0;
85 OSDictionary * dict;
86 OSString * str;
87 char * comp;
88 const char * skip;
89 int len;
90
91 do {
92
93 len = strlen( kIODeviceTreePlane ":" );
94 maxLen -= len;
95 if( maxLen < 0)
96 continue;
97
98 strcpy( buf, kIODeviceTreePlane ":" );
99 comp = buf + len;
100
101 // remove parameters following ':' from the path
102 skip = strchr( path, ':');
103 if( !skip)
104 continue;
105
106 len = skip - path;
107 maxLen -= len;
108 if( maxLen < 0)
109 continue;
110 strncpy( comp, path, len );
111 comp[ len ] = 0;
112
113 matching = IOService::serviceMatching( "IONetworkInterface" );
114 if( !matching)
115 continue;
116 dict = IOService::addLocation( matching );
117 if( !dict)
118 continue;
119
120 str = OSString::withCString( buf );
121 if( !str)
122 continue;
123 dict->setObject( kIOPathMatchKey, str );
124 str->release();
125
126 return( matching );
127
128 } while( false );
129
130 if( matching)
131 matching->release();
132
133 return( 0 );
134 }
135
136 OSDictionary * IONetworkNamePrefixMatching( const char * prefix )
137 {
138 OSDictionary * matching;
139 OSDictionary * propDict = 0;
140 const OSSymbol * str = 0;
141
142 do {
143 matching = IOService::serviceMatching( "IONetworkInterface" );
144 if ( matching == 0 )
145 continue;
146
147 propDict = OSDictionary::withCapacity(1);
148 if ( propDict == 0 )
149 continue;
150
151 str = OSSymbol::withCString( prefix );
152 if ( str == 0 )
153 continue;
154
155 propDict->setObject( kIOInterfaceNamePrefix, (OSObject *) str );
156 str->release();
157 str = 0;
158
159 if ( matching->setObject( gIOPropertyMatchKey,
160 (OSObject *) propDict ) != true )
161 continue;
162
163 propDict->release();
164 propDict = 0;
165
166 return( matching );
167
168 } while ( false );
169
170 if ( matching ) matching->release();
171 if ( propDict ) propDict->release();
172 if ( str ) str->release();
173
174 return( 0 );
175 }
176
177 static bool IORegisterNetworkInterface( IONetworkInterface * netif )
178 {
179 IONetworkStack * stack;
180
181 if (( stack = IONetworkStack::getNetworkStack() ))
182 {
183 stack->registerInterface( netif, netif->getNamePrefix() );
184 }
185
186 return ( netif->getProperty( kIOBSDNameKey ) != 0 );
187 }
188
189 static void IORegisterPrimaryNetworkInterface()
190 {
191 IONetworkStack * stack;
192
193 if (( stack = IONetworkStack::getNetworkStack() ))
194 {
195 stack->registerPrimaryInterface( true );
196 }
197 }
198
199 OSDictionary * IODiskMatching( const char * path, char * buf, int maxLen )
200 {
201 const char * look;
202 const char * alias;
203 char * comp;
204 long unit = -1;
205 long partition = -1;
206 char c;
207
208 // scan the tail of the path for "@unit:partition"
209 do {
210 // Have to get the full path to the controller - an alias may
211 // tell us next to nothing, like "hd:8"
212 alias = IORegistryEntry::dealiasPath( &path, gIODTPlane );
213
214 look = path + strlen( path);
215 c = ':';
216 while( look != path) {
217 if( *(--look) == c) {
218 if( c == ':') {
219 partition = strtol( look + 1, 0, 0 );
220 c = '@';
221 } else if( c == '@') {
222 unit = strtol( look + 1, 0, 16 );
223 c = '/';
224 } else if( c == '/') {
225 c = 0;
226 break;
227 }
228 }
229
230 if( alias && (look == path)) {
231 path = alias;
232 look = path + strlen( path);
233 alias = 0;
234 }
235 }
236 if( c || unit == -1 || partition == -1)
237 continue;
238
239 maxLen -= strlen( "{" kIOPathMatchKey "='" kIODeviceTreePlane ":" );
240 maxLen -= ( alias ? strlen( alias ) : 0 ) + (look - path);
241 maxLen -= strlen( "/@hhhhhhhh:dddddddddd';}" );
242
243 if( maxLen > 0) {
244 sprintf( buf, "{" kIOPathMatchKey "='" kIODeviceTreePlane ":" );
245 comp = buf + strlen( buf );
246
247 if( alias) {
248 strcpy( comp, alias );
249 comp += strlen( alias );
250 }
251
252 if ( (look - path)) {
253 strncpy( comp, path, look - path);
254 comp += look - path;
255 }
256
257 sprintf( comp, "/@%lx:%ld';}", unit, partition );
258 } else
259 continue;
260
261 return( OSDynamicCast(OSDictionary, OSUnserialize( buf, 0 )) );
262
263 } while( false );
264
265 return( 0 );
266 }
267
268 OSDictionary * IOOFPathMatching( const char * path, char * buf, int maxLen )
269 {
270 /* need to look up path, get device type,
271 call matching help based on device type */
272
273 return( IODiskMatching( path, buf, maxLen ));
274
275 }
276
277 kern_return_t IOFindBSDRoot( char * rootName,
278 dev_t * root, u_int32_t * oflags )
279 {
280 mach_timespec_t t;
281 IOService * service;
282 IORegistryEntry * regEntry;
283 OSDictionary * matching = 0;
284 OSString * iostr;
285 OSNumber * off;
286 OSData * data = 0;
287
288 UInt32 flags = 0;
289 int minor, major;
290 char * rdBootVar;
291 enum { kMaxPathBuf = 512, kMaxBootVar = 128 };
292 char * str;
293 const char * look = 0;
294 int len;
295 bool forceNet = false;
296
297 static int mountAttempts = 0;
298
299 if( mountAttempts++)
300 IOSleep( 5 * 1000 );
301
302 str = (char *) IOMalloc( kMaxPathBuf + kMaxBootVar );
303 if( !str)
304 return( kIOReturnNoMemory );
305 rdBootVar = str + kMaxPathBuf;
306
307 if (!PE_parse_boot_arg("rd", rdBootVar )
308 && !PE_parse_boot_arg("rootdev", rdBootVar ))
309 rdBootVar[0] = 0;
310
311 do {
312 if( (regEntry = IORegistryEntry::fromPath( "/chosen", gIODTPlane ))) {
313 data = (OSData *) regEntry->getProperty( "rootpath" );
314 regEntry->release();
315 if( data)
316 continue;
317 }
318 if( (regEntry = IORegistryEntry::fromPath( "/options", gIODTPlane ))) {
319 data = (OSData *) regEntry->getProperty( "boot-file" );
320 regEntry->release();
321 if( data)
322 continue;
323 }
324 } while( false );
325
326 if( data)
327 look = (const char *) data->getBytesNoCopy();
328
329 if( rdBootVar[0] == '*') {
330 look = rdBootVar + 1;
331 forceNet = false;
332 } else {
333 if( (regEntry = IORegistryEntry::fromPath( "/", gIODTPlane ))) {
334 forceNet = (0 != regEntry->getProperty( "net-boot" ));
335 regEntry->release();
336 }
337 }
338
339 if( look) {
340 // from OpenFirmware path
341 IOLog("From path: \"%s\", ", look);
342
343 if( forceNet || (0 == strncmp( look, "enet", strlen( "enet" ))) )
344 matching = IONetworkMatching( look, str, kMaxPathBuf );
345 else
346 matching = IODiskMatching( look, str, kMaxPathBuf );
347 }
348
349 if( (!matching) && rdBootVar[0] ) {
350 // by BSD name
351 look = rdBootVar;
352 if( look[0] == '*')
353 look++;
354
355 if ( strncmp( look, "en", strlen( "en" )) == 0 )
356 matching = IONetworkNamePrefixMatching( "en" );
357 else
358 matching = IOBSDNameMatching( look );
359 }
360
361 if( !matching) {
362 OSString * astring;
363 // any UFS
364 matching = IOService::serviceMatching( "IOMedia" );
365 astring = OSString::withCStringNoCopy("Apple_UFS");
366 if ( astring ) {
367 matching->setObject(kIOMediaContentKey, astring);
368 astring->release();
369 }
370 }
371
372 if( true && matching) {
373 OSSerialize * s = OSSerialize::withCapacity( 5 );
374
375 if( matching->serialize( s )) {
376 IOLog( "Waiting on %s\n", s->text() );
377 s->release();
378 }
379 }
380
381 IOService::waitForService(IOService::serviceMatching("IOMediaBSDClient"));
382
383 do {
384 t.tv_sec = ROOTDEVICETIMEOUT;
385 t.tv_nsec = 0;
386 matching->retain();
387 service = IOService::waitForService( matching, &t );
388 if( (!service) || (mountAttempts == 10)) {
389 PE_display_icon( 0, "noroot");
390 IOLog( "Still waiting for root device\n" );
391 }
392 } while( !service);
393 matching->release();
394
395 major = 0;
396 minor = 0;
397
398 // If the IOService we matched to is a subclass of IONetworkInterface,
399 // then make sure it has been registered with BSD and has a BSD name
400 // assigned.
401
402 if ( service
403 && service->metaCast( "IONetworkInterface" )
404 && !IORegisterNetworkInterface( (IONetworkInterface *) service ) )
405 {
406 service = 0;
407 }
408 IORegisterPrimaryNetworkInterface();
409
410 if( service) {
411
412 len = kMaxPathBuf;
413 service->getPath( str, &len, gIOServicePlane );
414 IOLog( "Got boot device = %s\n", str );
415
416 iostr = (OSString *) service->getProperty( kIOBSDNameKey );
417 if( iostr)
418 strcpy( rootName, iostr->getCStringNoCopy() );
419 off = (OSNumber *) service->getProperty( kIOBSDMajorKey );
420 if( off)
421 major = off->unsigned32BitValue();
422 off = (OSNumber *) service->getProperty( kIOBSDMinorKey );
423 if( off)
424 minor = off->unsigned32BitValue();
425
426 if( service->metaCast( "IONetworkInterface" ))
427 flags |= 1;
428
429 } else {
430
431 IOLog( "Wait for root failed\n" );
432 strcpy( rootName, "en0");
433 flags |= 1;
434 }
435
436 IOLog( "BSD root: %s", rootName );
437 if( major)
438 IOLog(", major %d, minor %d\n", major, minor );
439 else
440 IOLog("\n");
441
442 *root = makedev( major, minor );
443 *oflags = flags;
444
445 IOFree( str, kMaxPathBuf + kMaxBootVar );
446
447 if( gIOKitDebug & (kIOLogDTree | kIOLogServiceTree | kIOLogMemory)) {
448
449 IOSleep(10 * 1000);
450 // IOService::getPlatform()->waitQuiet();
451 if( gIOKitDebug & kIOLogDTree) {
452 IOLog("\nDT plane:\n");
453 IOPrintPlane( gIODTPlane );
454 }
455 if( gIOKitDebug & kIOLogServiceTree) {
456 IOLog("\nService plane:\n");
457 IOPrintPlane( gIOServicePlane );
458 }
459 if( gIOKitDebug & kIOLogMemory)
460 IOPrintMemory();
461 }
462
463 return( kIOReturnSuccess );
464 }
465
466 } /* extern "C" */