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