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