xref: /xnu-11215/iokit/bsddev/IOKitBSDInit.cpp (revision 76e12aa3)
1 /*
2  * Copyright (c) 1998-2011 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 #include <IOKit/IOBSD.h>
29 #include <IOKit/IOLib.h>
30 #include <IOKit/IOService.h>
31 #include <IOKit/IOCatalogue.h>
32 #include <IOKit/IODeviceTreeSupport.h>
33 #include <IOKit/IOKitKeys.h>
34 #include <IOKit/IOPlatformExpert.h>
35 #include <IOKit/IOUserClient.h>
36 
37 extern "C" {
38 
39 #include <pexpert/pexpert.h>
40 #include <kern/clock.h>
41 #include <uuid/uuid.h>
42 #include <sys/vnode_internal.h>
43 #include <sys/mount.h>
44 
45 // how long to wait for matching root device, secs
46 #if DEBUG
47 #define ROOTDEVICETIMEOUT       120
48 #else
49 #define ROOTDEVICETIMEOUT       60
50 #endif
51 
52 int panic_on_exception_triage = 0;
53 
54 extern dev_t mdevadd(int devid, uint64_t base, unsigned int size, int phys);
55 extern dev_t mdevlookup(int devid);
56 extern void mdevremoveall(void);
57 extern int mdevgetrange(int devid, uint64_t *base, uint64_t *size);
58 extern void di_root_ramfile(IORegistryEntry * entry);
59 
60 
61 #if CONFIG_EMBEDDED
62 #define IOPOLLED_COREFILE 	(CONFIG_KDP_INTERACTIVE_DEBUGGING)
63 #define kIOCoreDumpPath 	"/private/var/vm/kernelcore"
64 #define kIOCoreDumpSize		350ULL*1024ULL*1024ULL
65 // leave free space on volume:
66 #define kIOCoreDumpFreeSize	350ULL*1024ULL*1024ULL
67 #elif DEVELOPMENT
68 #define IOPOLLED_COREFILE  	1
69 // no sizing
70 #define kIOCoreDumpSize		0ULL
71 #define kIOCoreDumpFreeSize	0ULL
72 #else
73 #define IOPOLLED_COREFILE  	0
74 #endif
75 
76 
77 #if IOPOLLED_COREFILE
78 static bool
79 NewKernelCoreMedia(void * target, void * refCon,
80 		   IOService * newService,
81 		   IONotifier * notifier);
82 #endif /* IOPOLLED_COREFILE */
83 
84 #if CONFIG_KDP_INTERACTIVE_DEBUGGING
85 /*
86  * Touched by IOFindBSDRoot() if a RAMDisk is used for the root device.
87  */
88 extern uint64_t kdp_core_ramdisk_addr;
89 extern uint64_t kdp_core_ramdisk_size;
90 #endif
91 
92 kern_return_t
93 IOKitBSDInit( void )
94 {
95     IOService::publishResource("IOBSD");
96 
97     return( kIOReturnSuccess );
98 }
99 
100 void
101 IOServicePublishResource( const char * property, boolean_t value )
102 {
103     if ( value)
104         IOService::publishResource( property, kOSBooleanTrue );
105     else
106         IOService::getResourceService()->removeProperty( property );
107 }
108 
109 boolean_t
110 IOServiceWaitForMatchingResource( const char * property, uint64_t timeout )
111 {
112     OSDictionary *	dict = 0;
113     IOService *         match = 0;
114     boolean_t		found = false;
115 
116     do {
117 
118         dict = IOService::resourceMatching( property );
119         if( !dict)
120             continue;
121         match = IOService::waitForMatchingService( dict, timeout );
122         if ( match)
123             found = true;
124 
125     } while( false );
126 
127     if( dict)
128         dict->release();
129     if( match)
130         match->release();
131 
132     return( found );
133 }
134 
135 boolean_t
136 IOCatalogueMatchingDriversPresent( const char * property )
137 {
138     OSDictionary *	dict = 0;
139     OSOrderedSet *	set = 0;
140     SInt32		generationCount = 0;
141     boolean_t		found = false;
142 
143     do {
144 
145         dict = OSDictionary::withCapacity(1);
146         if( !dict)
147             continue;
148         dict->setObject( property, kOSBooleanTrue );
149         set = gIOCatalogue->findDrivers( dict, &generationCount );
150         if ( set && (set->getCount() > 0))
151             found = true;
152 
153     } while( false );
154 
155     if( dict)
156         dict->release();
157     if( set)
158         set->release();
159 
160     return( found );
161 }
162 
163 OSDictionary * IOBSDNameMatching( const char * name )
164 {
165     OSDictionary *	dict;
166     const OSSymbol *	str = 0;
167 
168     do {
169 
170 	dict = IOService::serviceMatching( gIOServiceKey );
171 	if( !dict)
172 	    continue;
173         str = OSSymbol::withCString( name );
174 	if( !str)
175 	    continue;
176         dict->setObject( kIOBSDNameKey, (OSObject *) str );
177         str->release();
178 
179         return( dict );
180 
181     } while( false );
182 
183     if( dict)
184 	dict->release();
185     if( str)
186 	str->release();
187 
188     return( 0 );
189 }
190 
191 OSDictionary * IOUUIDMatching( void )
192 {
193     return IOService::resourceMatching( "boot-uuid-media" );
194 }
195 
196 OSDictionary * IONetworkNamePrefixMatching( const char * prefix )
197 {
198     OSDictionary *	 matching;
199     OSDictionary *   propDict = 0;
200     const OSSymbol * str      = 0;
201 	char networkType[128];
202 
203     do {
204         matching = IOService::serviceMatching( "IONetworkInterface" );
205         if ( matching == 0 )
206             continue;
207 
208         propDict = OSDictionary::withCapacity(1);
209         if ( propDict == 0 )
210             continue;
211 
212         str = OSSymbol::withCString( prefix );
213         if ( str == 0 )
214             continue;
215 
216         propDict->setObject( "IOInterfaceNamePrefix", (OSObject *) str );
217         str->release();
218         str = 0;
219 
220 		// see if we're contrained to netroot off of specific network type
221 		if(PE_parse_boot_argn( "network-type", networkType, 128 ))
222 		{
223 			str = OSSymbol::withCString( networkType );
224 			if(str)
225 			{
226 				propDict->setObject( "IONetworkRootType", str);
227 				str->release();
228 				str = 0;
229 			}
230 		}
231 
232         if ( matching->setObject( gIOPropertyMatchKey,
233                                   (OSObject *) propDict ) != true )
234             continue;
235 
236         propDict->release();
237         propDict = 0;
238 
239         return( matching );
240 
241     } while ( false );
242 
243     if ( matching ) matching->release();
244     if ( propDict ) propDict->release();
245     if ( str      ) str->release();
246 
247     return( 0 );
248 }
249 
250 static bool IORegisterNetworkInterface( IOService * netif )
251 {
252     // A network interface is typically named and registered
253     // with BSD after receiving a request from a user space
254     // "namer". However, for cases when the system needs to
255     // root from the network, this registration task must be
256     // done inside the kernel and completed before the root
257     // device is handed to BSD.
258 
259     IOService *    stack;
260     OSNumber *     zero    = 0;
261     OSString *     path    = 0;
262     OSDictionary * dict    = 0;
263     char *         pathBuf = 0;
264     int            len;
265     enum { kMaxPathLen = 512 };
266 
267     do {
268         stack = IOService::waitForService(
269                 IOService::serviceMatching("IONetworkStack") );
270         if ( stack == 0 ) break;
271 
272         dict = OSDictionary::withCapacity(3);
273         if ( dict == 0 ) break;
274 
275         zero = OSNumber::withNumber((UInt64) 0, 32);
276         if ( zero == 0 ) break;
277 
278         pathBuf = (char *) IOMalloc( kMaxPathLen );
279         if ( pathBuf == 0 ) break;
280 
281         len = kMaxPathLen;
282         if ( netif->getPath( pathBuf, &len, gIOServicePlane )
283              == false ) break;
284 
285         path = OSString::withCStringNoCopy( pathBuf );
286         if ( path == 0 ) break;
287 
288         dict->setObject( "IOInterfaceUnit", zero );
289         dict->setObject( kIOPathMatchKey,   path );
290 
291         stack->setProperties( dict );
292     }
293     while ( false );
294 
295     if ( zero ) zero->release();
296     if ( path ) path->release();
297     if ( dict ) dict->release();
298     if ( pathBuf ) IOFree(pathBuf, kMaxPathLen);
299 
300 	return ( netif->getProperty( kIOBSDNameKey ) != 0 );
301 }
302 
303 OSDictionary * IOOFPathMatching( const char * path, char * buf, int maxLen )
304 {
305     OSDictionary *	matching = NULL;
306     OSString *		str;
307     char *		comp;
308     int			len;
309 
310     do {
311 
312 	len = strlen( kIODeviceTreePlane ":" );
313 	maxLen -= len;
314 	if( maxLen <= 0)
315 	    continue;
316 
317 	strlcpy( buf, kIODeviceTreePlane ":", len + 1 );
318 	comp = buf + len;
319 
320 	len = strlen( path );
321 	maxLen -= len;
322 	if( maxLen <= 0)
323 	    continue;
324 	strlcpy( comp, path, len + 1 );
325 
326 	matching = OSDictionary::withCapacity( 1 );
327 	if( !matching)
328 	    continue;
329 
330 	str = OSString::withCString( buf );
331 	if( !str)
332 	    continue;
333         matching->setObject( kIOPathMatchKey, str );
334 	str->release();
335 
336 	return( matching );
337 
338     } while( false );
339 
340     if( matching)
341         matching->release();
342 
343     return( 0 );
344 }
345 
346 static int didRam = 0;
347 enum { kMaxPathBuf = 512, kMaxBootVar = 128 };
348 
349 kern_return_t IOFindBSDRoot( char * rootName, unsigned int rootNameSize,
350 				dev_t * root, u_int32_t * oflags )
351 {
352     mach_timespec_t	t;
353     IOService *		service;
354     IORegistryEntry *	regEntry;
355     OSDictionary *	matching = 0;
356     OSString *		iostr;
357     OSNumber *		off;
358     OSData *		data = 0;
359 
360     UInt32		flags = 0;
361     int			mnr, mjr;
362     const char *        mediaProperty = 0;
363     char *		rdBootVar;
364     char *		str;
365     const char *	look = 0;
366     int			len;
367     bool		debugInfoPrintedOnce = false;
368     const char * 	uuidStr = NULL;
369 
370     static int		mountAttempts = 0;
371 
372     int xchar, dchar;
373 
374     // stall here for anyone matching on the IOBSD resource to finish (filesystems)
375     matching = IOService::serviceMatching(gIOResourcesKey);
376     assert(matching);
377     matching->setObject(gIOResourceMatchedKey, gIOBSDKey);
378 
379 	if ((service = IOService::waitForMatchingService(matching, 30ULL * kSecondScale))) {
380 		service->release();
381 	} else {
382 		IOLog("!BSD\n");
383 	}
384     matching->release();
385 	matching = NULL;
386 
387     if( mountAttempts++)
388     {
389         IOLog("mount(%d) failed\n", mountAttempts);
390 	IOSleep( 5 * 1000 );
391     }
392 
393     str = (char *) IOMalloc( kMaxPathBuf + kMaxBootVar );
394     if( !str)
395 	return( kIOReturnNoMemory );
396     rdBootVar = str + kMaxPathBuf;
397 
398     if (!PE_parse_boot_argn("rd", rdBootVar, kMaxBootVar )
399      && !PE_parse_boot_argn("rootdev", rdBootVar, kMaxBootVar ))
400 	rdBootVar[0] = 0;
401 
402     do {
403 	if( (regEntry = IORegistryEntry::fromPath( "/chosen", gIODTPlane ))) {
404 	    di_root_ramfile(regEntry);
405             data = OSDynamicCast(OSData, regEntry->getProperty( "root-matching" ));
406             if (data) {
407                matching = OSDynamicCast(OSDictionary, OSUnserializeXML((char *)data->getBytesNoCopy()));
408                 if (matching) {
409                     continue;
410                 }
411             }
412 
413 	    data = (OSData *) regEntry->getProperty( "boot-uuid" );
414 	    if( data) {
415 		uuidStr = (const char*)data->getBytesNoCopy();
416 		OSString *uuidString = OSString::withCString( uuidStr );
417 
418 		// match the boot-args boot-uuid processing below
419 		if( uuidString) {
420 		    IOLog("rooting via boot-uuid from /chosen: %s\n", uuidStr);
421 		    IOService::publishResource( "boot-uuid", uuidString );
422 		    uuidString->release();
423 		    matching = IOUUIDMatching();
424 		    mediaProperty = "boot-uuid-media";
425 		    regEntry->release();
426 		    continue;
427 		} else {
428 		    uuidStr = NULL;
429 		}
430 	    }
431 	    regEntry->release();
432 	}
433     } while( false );
434 
435 //
436 //	See if we have a RAMDisk property in /chosen/memory-map.  If so, make it into a device.
437 //	It will become /dev/mdx, where x is 0-f.
438 //
439 
440 	if(!didRam) {												/* Have we already build this ram disk? */
441 		didRam = 1;												/* Remember we did this */
442 		if((regEntry = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane ))) {	/* Find the map node */
443 			data = (OSData *)regEntry->getProperty("RAMDisk");	/* Find the ram disk, if there */
444 			if(data) {											/* We found one */
445 				uintptr_t *ramdParms;
446 				ramdParms = (uintptr_t *)data->getBytesNoCopy();	/* Point to the ram disk base and size */
447 				(void)mdevadd(-1, ml_static_ptovirt(ramdParms[0]) >> 12, ramdParms[1] >> 12, 0);	/* Initialize it and pass back the device number */
448 			}
449 			regEntry->release();								/* Toss the entry */
450 		}
451 	}
452 
453 //
454 //	Now check if we are trying to root on a memory device
455 //
456 
457 	if((rdBootVar[0] == 'm') && (rdBootVar[1] == 'd') && (rdBootVar[3] == 0)) {
458 		dchar = xchar = rdBootVar[2];							/* Get the actual device */
459 		if((xchar >= '0') && (xchar <= '9')) xchar = xchar - '0';	/* If digit, convert */
460 		else {
461 			xchar = xchar & ~' ';								/* Fold to upper case */
462 			if((xchar >= 'A') && (xchar <= 'F')) {				/* Is this a valid digit? */
463 				xchar = (xchar & 0xF) + 9;						/* Convert the hex digit */
464 				dchar = dchar | ' ';							/* Fold to lower case */
465 			}
466 			else xchar = -1;									/* Show bogus */
467 		}
468 		if(xchar >= 0) {										/* Do we have a valid memory device name? */
469 			*root = mdevlookup(xchar);							/* Find the device number */
470 			if(*root >= 0) {									/* Did we find one? */
471 				rootName[0] = 'm';								/* Build root name */
472 				rootName[1] = 'd';								/* Build root name */
473 				rootName[2] = dchar;							/* Build root name */
474 				rootName[3] = 0;								/* Build root name */
475 				IOLog("BSD root: %s, major %d, minor %d\n", rootName, major(*root), minor(*root));
476 				*oflags = 0;									/* Show that this is not network */
477 
478 #if CONFIG_KDP_INTERACTIVE_DEBUGGING
479                 /* retrieve final ramdisk range and initialize KDP variables */
480                 if (mdevgetrange(xchar, &kdp_core_ramdisk_addr, &kdp_core_ramdisk_size) != 0) {
481                     IOLog("Unable to retrieve range for root memory device %d\n", xchar);
482                     kdp_core_ramdisk_addr = 0;
483                     kdp_core_ramdisk_size = 0;
484                 }
485 #endif
486 
487 				goto iofrootx;									/* Join common exit... */
488 			}
489 			panic("IOFindBSDRoot: specified root memory device, %s, has not been configured\n", rdBootVar);	/* Not there */
490 		}
491 	}
492 
493       if( (!matching) && rdBootVar[0] ) {
494 	// by BSD name
495 	look = rdBootVar;
496 	if( look[0] == '*')
497 	    look++;
498 
499 	if ( strncmp( look, "en", strlen( "en" )) == 0 ) {
500 	    matching = IONetworkNamePrefixMatching( "en" );
501 	} else if ( strncmp( look, "uuid", strlen( "uuid" )) == 0 ) {
502             char *uuid;
503             OSString *uuidString;
504 
505             uuid = (char *)IOMalloc( kMaxBootVar );
506 
507             if ( uuid ) {
508                 if (!PE_parse_boot_argn( "boot-uuid", uuid, kMaxBootVar )) {
509                     panic( "rd=uuid but no boot-uuid=<value> specified" );
510                 }
511                 uuidString = OSString::withCString( uuid );
512                 if ( uuidString ) {
513                     IOService::publishResource( "boot-uuid", uuidString );
514                     uuidString->release();
515                     IOLog( "\nWaiting for boot volume with UUID %s\n", uuid );
516                     matching = IOUUIDMatching();
517                     mediaProperty = "boot-uuid-media";
518                 }
519                 IOFree( uuid, kMaxBootVar );
520             }
521 	} else {
522 	    matching = IOBSDNameMatching( look );
523 	}
524     }
525 
526     if( !matching) {
527 	OSString * astring;
528 	// Match any HFS media
529 
530         matching = IOService::serviceMatching( "IOMedia" );
531         astring = OSString::withCStringNoCopy("Apple_HFS");
532         if ( astring ) {
533             matching->setObject("Content", astring);
534             astring->release();
535         }
536     }
537 
538     if( gIOKitDebug & kIOWaitQuietBeforeRoot ) {
539     	IOLog( "Waiting for matching to complete\n" );
540     	IOService::getPlatform()->waitQuiet();
541     }
542 
543     if( true && matching) {
544         OSSerialize * s = OSSerialize::withCapacity( 5 );
545 
546         if( matching->serialize( s )) {
547             IOLog( "Waiting on %s\n", s->text() );
548             s->release();
549         }
550     }
551 
552     do {
553         t.tv_sec = ROOTDEVICETIMEOUT;
554         t.tv_nsec = 0;
555 	matching->retain();
556         service = IOService::waitForService( matching, &t );
557 	if( (!service) || (mountAttempts == 10)) {
558             PE_display_icon( 0, "noroot");
559             IOLog( "Still waiting for root device\n" );
560 
561             if( !debugInfoPrintedOnce) {
562                 debugInfoPrintedOnce = true;
563                 if( gIOKitDebug & kIOLogDTree) {
564                     IOLog("\nDT plane:\n");
565                     IOPrintPlane( gIODTPlane );
566                 }
567                 if( gIOKitDebug & kIOLogServiceTree) {
568                     IOLog("\nService plane:\n");
569                     IOPrintPlane( gIOServicePlane );
570                 }
571                 if( gIOKitDebug & kIOLogMemory)
572                     IOPrintMemory();
573             }
574 	}
575     } while( !service);
576     matching->release();
577 
578     if ( service && mediaProperty ) {
579         service = (IOService *)service->getProperty(mediaProperty);
580     }
581 
582     mjr = 0;
583     mnr = 0;
584 
585     // If the IOService we matched to is a subclass of IONetworkInterface,
586     // then make sure it has been registered with BSD and has a BSD name
587     // assigned.
588 
589     if ( service
590     &&   service->metaCast( "IONetworkInterface" )
591     &&   !IORegisterNetworkInterface( service ) )
592     {
593         service = 0;
594     }
595 
596     if( service) {
597 
598 	len = kMaxPathBuf;
599 	service->getPath( str, &len, gIOServicePlane );
600 	IOLog( "Got boot device = %s\n", str );
601 
602 	iostr = (OSString *) service->getProperty( kIOBSDNameKey );
603 	if( iostr)
604 	    strlcpy( rootName, iostr->getCStringNoCopy(), rootNameSize );
605 	off = (OSNumber *) service->getProperty( kIOBSDMajorKey );
606 	if( off)
607 	    mjr = off->unsigned32BitValue();
608 	off = (OSNumber *) service->getProperty( kIOBSDMinorKey );
609 	if( off)
610 	    mnr = off->unsigned32BitValue();
611 
612 	if( service->metaCast( "IONetworkInterface" ))
613 	    flags |= 1;
614 
615     } else {
616 
617 	IOLog( "Wait for root failed\n" );
618         strlcpy( rootName, "en0", rootNameSize );
619         flags |= 1;
620     }
621 
622     IOLog( "BSD root: %s", rootName );
623     if( mjr)
624 	IOLog(", major %d, minor %d\n", mjr, mnr );
625     else
626 	IOLog("\n");
627 
628     *root = makedev( mjr, mnr );
629     *oflags = flags;
630 
631     IOFree( str,  kMaxPathBuf + kMaxBootVar );
632 
633 iofrootx:
634     if( (gIOKitDebug & (kIOLogDTree | kIOLogServiceTree | kIOLogMemory)) && !debugInfoPrintedOnce) {
635 
636 	IOService::getPlatform()->waitQuiet();
637         if( gIOKitDebug & kIOLogDTree) {
638             IOLog("\nDT plane:\n");
639             IOPrintPlane( gIODTPlane );
640         }
641         if( gIOKitDebug & kIOLogServiceTree) {
642             IOLog("\nService plane:\n");
643             IOPrintPlane( gIOServicePlane );
644         }
645         if( gIOKitDebug & kIOLogMemory)
646             IOPrintMemory();
647     }
648 
649     return( kIOReturnSuccess );
650 }
651 
652 bool IORamDiskBSDRoot(void)
653 {
654     char rdBootVar[kMaxBootVar];
655     if (PE_parse_boot_argn("rd", rdBootVar, kMaxBootVar )
656      || PE_parse_boot_argn("rootdev", rdBootVar, kMaxBootVar )) {
657         if((rdBootVar[0] == 'm') && (rdBootVar[1] == 'd') && (rdBootVar[3] == 0)) {
658             return true;
659         }
660     }
661     return false;
662 }
663 
664 void IOSecureBSDRoot(const char * rootName)
665 {
666 #if CONFIG_EMBEDDED
667     int              tmpInt;
668     IOReturn         result;
669     IOPlatformExpert *pe;
670     OSDictionary     *matching;
671     const OSSymbol   *functionName = OSSymbol::withCStringNoCopy("SecureRootName");
672 
673     matching = IOService::serviceMatching("IOPlatformExpert");
674     assert(matching);
675     pe = (IOPlatformExpert *) IOService::waitForMatchingService(matching, 30ULL * kSecondScale);
676     matching->release();
677     assert(pe);
678     // Returns kIOReturnNotPrivileged is the root device is not secure.
679     // Returns kIOReturnUnsupported if "SecureRootName" is not implemented.
680     result = pe->callPlatformFunction(functionName, false, (void *)rootName, (void *)0, (void *)0, (void *)0);
681     functionName->release();
682     OSSafeReleaseNULL(pe);
683 
684     if (result == kIOReturnNotPrivileged) {
685         mdevremoveall();
686     } else if (result == kIOReturnSuccess) {
687         // If we are booting with a secure root, and we have the right
688 	// boot-arg, we will want to panic on exception triage.  This
689 	// behavior is intended as a debug aid (we can look at why an
690 	// exception occured in the kernel debugger).
691         if (PE_parse_boot_argn("-panic_on_exception_triage", &tmpInt, sizeof(tmpInt))) {
692             panic_on_exception_triage = 1;
693         }
694     }
695 
696 #endif  // CONFIG_EMBEDDED
697 }
698 
699 void *
700 IOBSDRegistryEntryForDeviceTree(char * path)
701 {
702     return (IORegistryEntry::fromPath(path, gIODTPlane));
703 }
704 
705 void
706 IOBSDRegistryEntryRelease(void * entry)
707 {
708     IORegistryEntry * regEntry = (IORegistryEntry *)entry;
709 
710     if (regEntry)
711 	regEntry->release();
712     return;
713 }
714 
715 const void *
716 IOBSDRegistryEntryGetData(void * entry, char * property_name,
717 			  int * packet_length)
718 {
719     OSData *		data;
720     IORegistryEntry * 	regEntry = (IORegistryEntry *)entry;
721 
722     data = (OSData *) regEntry->getProperty(property_name);
723     if (data) {
724 	*packet_length = data->getLength();
725         return (data->getBytesNoCopy());
726     }
727     return (NULL);
728 }
729 
730 kern_return_t IOBSDGetPlatformUUID( uuid_t uuid, mach_timespec_t timeout )
731 {
732     IOService * resources;
733     OSString *  string;
734 
735     resources = IOService::waitForService( IOService::resourceMatching( kIOPlatformUUIDKey ), ( timeout.tv_sec || timeout.tv_nsec ) ? &timeout : 0 );
736     if ( resources == 0 ) return KERN_OPERATION_TIMED_OUT;
737 
738     string = ( OSString * ) IOService::getPlatform( )->getProvider( )->getProperty( kIOPlatformUUIDKey );
739     if ( string == 0 ) return KERN_NOT_SUPPORTED;
740 
741     uuid_parse( string->getCStringNoCopy( ), uuid );
742 
743     return KERN_SUCCESS;
744 }
745 
746 } /* extern "C" */
747 
748 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
749 
750 #include <sys/conf.h>
751 #include <sys/vnode.h>
752 #include <sys/vnode_internal.h>
753 #include <sys/fcntl.h>
754 #include <IOKit/IOPolledInterface.h>
755 #include <IOKit/IOBufferMemoryDescriptor.h>
756 
757 IOPolledFileIOVars * gIOPolledCoreFileVars;
758 
759 #if IOPOLLED_COREFILE
760 
761 static IOReturn
762 IOOpenPolledCoreFile(const char * filename)
763 {
764     IOReturn err;
765     unsigned int debug;
766 
767     if (gIOPolledCoreFileVars)                             return (kIOReturnBusy);
768     if (!IOPolledInterface::gMetaClass.getInstanceCount()) return (kIOReturnUnsupported);
769 
770     debug = 0;
771     PE_parse_boot_argn("debug", &debug, sizeof (debug));
772     if (DB_DISABLE_LOCAL_CORE & debug)                     return (kIOReturnUnsupported);
773 
774     err = IOPolledFileOpen(filename, kIOCoreDumpSize, kIOCoreDumpFreeSize,
775 			    NULL, 0,
776 			    &gIOPolledCoreFileVars, NULL, NULL, 0);
777     if (kIOReturnSuccess != err)                           return (err);
778 
779     err = IOPolledFilePollersSetup(gIOPolledCoreFileVars, kIOPolledPreflightCoreDumpState);
780     if (kIOReturnSuccess != err)
781     {
782 	IOPolledFileClose(&gIOPolledCoreFileVars, NULL, NULL, 0, 0, 0);
783     }
784 
785     return (err);
786 }
787 
788 static void
789 IOClosePolledCoreFile(void)
790 {
791     IOPolledFilePollersClose(gIOPolledCoreFileVars, kIOPolledPostflightCoreDumpState);
792     IOPolledFileClose(&gIOPolledCoreFileVars, NULL, NULL, 0, 0, 0);
793 }
794 
795 static thread_call_t gIOOpenPolledCoreFileTC;
796 static IONotifier  * gIOPolledCoreFileNotifier;
797 static IONotifier  * gIOPolledCoreFileInterestNotifier;
798 
799 static IOReturn
800 KernelCoreMediaInterest(void * target, void * refCon,
801 			UInt32 messageType, IOService * provider,
802 			void * messageArgument, vm_size_t argSize )
803 {
804     if (kIOMessageServiceIsTerminated == messageType)
805     {
806 	gIOPolledCoreFileInterestNotifier->remove();
807 	gIOPolledCoreFileInterestNotifier = 0;
808 	IOClosePolledCoreFile();
809     }
810 
811     return (kIOReturnSuccess);
812 }
813 
814 static void
815 OpenKernelCoreMedia(thread_call_param_t p0, thread_call_param_t p1)
816 {
817     IOService * newService;
818     OSString  * string;
819     char        filename[16];
820 
821     newService = (IOService *) p1;
822     do
823     {
824 	if (gIOPolledCoreFileVars) break;
825 	string = OSDynamicCast(OSString, newService->getProperty(kIOBSDNameKey));
826 	if (!string) break;
827 	snprintf(filename, sizeof(filename), "/dev/%s", string->getCStringNoCopy());
828 	if (kIOReturnSuccess != IOOpenPolledCoreFile(filename)) break;
829 	gIOPolledCoreFileInterestNotifier = newService->registerInterest(
830 				gIOGeneralInterest, &KernelCoreMediaInterest, NULL, 0);
831     }
832     while (false);
833 
834     newService->release();
835 }
836 
837 static bool
838 NewKernelCoreMedia(void * target, void * refCon,
839 		   IOService * newService,
840 		   IONotifier * notifier)
841 {
842     static volatile UInt32 onlyOneCorePartition = 0;
843     do
844     {
845 	if (!OSCompareAndSwap(0, 1, &onlyOneCorePartition)) break;
846 	if (gIOPolledCoreFileVars)    break;
847         if (!gIOOpenPolledCoreFileTC) break;
848         newService = newService->getProvider();
849         if (!newService)              break;
850         newService->retain();
851 	thread_call_enter1(gIOOpenPolledCoreFileTC, newService);
852     }
853     while (false);
854 
855     return (false);
856 }
857 
858 #endif /* IOPOLLED_COREFILE */
859 
860 extern "C" void
861 IOBSDMountChange(struct mount * mp, uint32_t op)
862 {
863 #if IOPOLLED_COREFILE
864 
865     OSDictionary * bsdMatching;
866     OSDictionary * mediaMatching;
867     OSString     * string;
868 
869     if (!gIOPolledCoreFileNotifier) do
870     {
871 	if (!gIOOpenPolledCoreFileTC) gIOOpenPolledCoreFileTC = thread_call_allocate(&OpenKernelCoreMedia, NULL);
872 	bsdMatching = IOService::serviceMatching("IOMediaBSDClient");
873 	if (!bsdMatching) break;
874 	mediaMatching = IOService::serviceMatching("IOMedia");
875 	string = OSString::withCStringNoCopy("5361644D-6163-11AA-AA11-00306543ECAC");
876 	if (!string || !mediaMatching) break;
877 	mediaMatching->setObject("Content", string);
878 	string->release();
879 	bsdMatching->setObject(gIOParentMatchKey, mediaMatching);
880 	mediaMatching->release();
881 
882 	gIOPolledCoreFileNotifier = IOService::addMatchingNotification(
883 						  gIOFirstMatchNotification, bsdMatching,
884 						  &NewKernelCoreMedia, NULL, NULL, -1000);
885     }
886     while (false);
887 
888 #if CONFIG_EMBEDDED
889     uint64_t flags;
890     char path[128];
891     int pathLen;
892     vnode_t vn;
893     int result;
894 
895     switch (op)
896     {
897 	case kIOMountChangeMount:
898 	case kIOMountChangeDidResize:
899 
900 	    if (gIOPolledCoreFileVars) break;
901 	    flags = vfs_flags(mp);
902 	    if (MNT_RDONLY & flags) break;
903 	    if (!(MNT_LOCAL & flags)) break;
904 
905 	    vn = vfs_vnodecovered(mp);
906 	    if (!vn) break;
907 	    pathLen = sizeof(path);
908 	    result = vn_getpath(vn, &path[0], &pathLen);
909 	    vnode_put(vn);
910 	    if (0 != result) break;
911 	    if (!pathLen) break;
912 	    if (0 != bcmp(path, kIOCoreDumpPath, pathLen - 1)) break;
913 	    IOOpenPolledCoreFile(kIOCoreDumpPath);
914 	    break;
915 
916 	case kIOMountChangeUnmount:
917 	case kIOMountChangeWillResize:
918 	    if (gIOPolledCoreFileVars && (mp == kern_file_mount(gIOPolledCoreFileVars->fileRef)))
919 	    {
920 		IOClosePolledCoreFile();
921 	    }
922 	    break;
923     }
924 #endif /* CONFIG_EMBEDDED */
925 #endif /* IOPOLLED_COREFILE */
926 }
927 
928 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
929 
930 extern "C" boolean_t
931 IOTaskHasEntitlement(task_t task, const char * entitlement)
932 {
933     OSObject * obj;
934     obj = IOUserClient::copyClientEntitlement(task, entitlement);
935     if (!obj) return (false);
936     obj->release();
937     return (obj != kOSBooleanFalse);
938 }
939 
940