2 * Copyright (c) 1998-2011 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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>
38 #include <pexpert/pexpert.h>
39 #include <kern/clock.h>
40 #include <mach/machine.h>
41 #include <uuid/uuid.h>
42 #include <sys/vnode_internal.h>
43 #include <sys/mount.h>
45 // how long to wait for matching root device, secs
47 #define ROOTDEVICETIMEOUT 120
49 #define ROOTDEVICETIMEOUT 60
52 extern dev_t
mdevadd(int devid
, uint64_t base
, unsigned int size
, int phys
);
53 extern dev_t
mdevlookup(int devid
);
54 extern void mdevremoveall(void);
55 extern int mdevgetrange(int devid
, uint64_t *base
, uint64_t *size
);
56 extern void di_root_ramfile(IORegistryEntry
* entry
);
58 #define ROUNDUP(a, b) (((a) + ((b) - 1)) & (~((b) - 1)))
60 #define IOPOLLED_COREFILE (CONFIG_KDP_INTERACTIVE_DEBUGGING)
62 #if defined(XNU_TARGET_OS_BRIDGE)
63 #define kIOCoreDumpPath "/private/var/internal/kernelcore"
65 #define kIOCoreDumpPath "/private/var/vm/kernelcore"
68 #if CONFIG_KDP_INTERACTIVE_DEBUGGING
70 * Touched by IOFindBSDRoot() if a RAMDisk is used for the root device.
72 extern uint64_t kdp_core_ramdisk_addr
;
73 extern uint64_t kdp_core_ramdisk_size
;
77 static void IOOpenPolledCoreFile(thread_call_param_t __unused
, thread_call_param_t corefilename
);
79 thread_call_t corefile_open_call
= NULL
;
85 IOService::publishResource("IOBSD");
88 corefile_open_call
= thread_call_allocate_with_options(IOOpenPolledCoreFile
, NULL
, THREAD_CALL_PRIORITY_KERNEL
, THREAD_CALL_OPTIONS_ONCE
);
91 return kIOReturnSuccess
;
95 IOServicePublishResource( const char * property
, boolean_t value
)
98 IOService::publishResource( property
, kOSBooleanTrue
);
100 IOService::getResourceService()->removeProperty( property
);
105 IOServiceWaitForMatchingResource( const char * property
, uint64_t timeout
)
107 OSDictionary
* dict
= NULL
;
108 IOService
* match
= NULL
;
109 boolean_t found
= false;
112 dict
= IOService::resourceMatching( property
);
116 match
= IOService::waitForMatchingService( dict
, timeout
);
133 IOCatalogueMatchingDriversPresent( const char * property
)
135 OSDictionary
* dict
= NULL
;
136 OSOrderedSet
* set
= NULL
;
137 SInt32 generationCount
= 0;
138 boolean_t found
= false;
141 dict
= OSDictionary::withCapacity(1);
145 dict
->setObject( property
, kOSBooleanTrue
);
146 set
= gIOCatalogue
->findDrivers( dict
, &generationCount
);
147 if (set
&& (set
->getCount() > 0)) {
163 IOBSDNameMatching( const char * name
)
166 const OSSymbol
* str
= NULL
;
169 dict
= IOService::serviceMatching( gIOServiceKey
);
173 str
= OSSymbol::withCString( name
);
177 dict
->setObject( kIOBSDNameKey
, (OSObject
*) str
);
194 IOUUIDMatching( void )
196 return IOService::resourceMatching( "boot-uuid-media" );
200 IONetworkNamePrefixMatching( const char * prefix
)
202 OSDictionary
* matching
;
203 OSDictionary
* propDict
= NULL
;
204 const OSSymbol
* str
= NULL
;
205 char networkType
[128];
208 matching
= IOService::serviceMatching( "IONetworkInterface" );
209 if (matching
== NULL
) {
213 propDict
= OSDictionary::withCapacity(1);
214 if (propDict
== NULL
) {
218 str
= OSSymbol::withCString( prefix
);
223 propDict
->setObject( "IOInterfaceNamePrefix", (OSObject
*) str
);
227 // see if we're contrained to netroot off of specific network type
228 if (PE_parse_boot_argn( "network-type", networkType
, 128 )) {
229 str
= OSSymbol::withCString( networkType
);
231 propDict
->setObject( "IONetworkRootType", str
);
237 if (matching
->setObject( gIOPropertyMatchKey
,
238 (OSObject
*) propDict
) != true) {
262 IORegisterNetworkInterface( IOService
* netif
)
264 // A network interface is typically named and registered
265 // with BSD after receiving a request from a user space
266 // "namer". However, for cases when the system needs to
267 // root from the network, this registration task must be
268 // done inside the kernel and completed before the root
269 // device is handed to BSD.
272 OSNumber
* zero
= NULL
;
273 OSString
* path
= NULL
;
274 OSDictionary
* dict
= NULL
;
275 char * pathBuf
= NULL
;
277 enum { kMaxPathLen
= 512 };
280 stack
= IOService::waitForService(
281 IOService::serviceMatching("IONetworkStack"));
286 dict
= OSDictionary::withCapacity(3);
291 zero
= OSNumber::withNumber((UInt64
) 0, 32);
296 pathBuf
= (char *) IOMalloc( kMaxPathLen
);
297 if (pathBuf
== NULL
) {
302 if (netif
->getPath( pathBuf
, &len
, gIOServicePlane
)
307 path
= OSString::withCStringNoCopy( pathBuf
);
312 dict
->setObject( "IOInterfaceUnit", zero
);
313 dict
->setObject( kIOPathMatchKey
, path
);
315 stack
->setProperties( dict
);
328 IOFree(pathBuf
, kMaxPathLen
);
331 return netif
->getProperty( kIOBSDNameKey
) != NULL
;
335 IOOFPathMatching( const char * path
, char * buf
, int maxLen
)
337 OSDictionary
* matching
= NULL
;
343 len
= strlen( kIODeviceTreePlane
":" );
349 strlcpy( buf
, kIODeviceTreePlane
":", len
+ 1 );
352 len
= strlen( path
);
357 strlcpy( comp
, path
, len
+ 1 );
359 matching
= OSDictionary::withCapacity( 1 );
364 str
= OSString::withCString( buf
);
368 matching
->setObject( kIOPathMatchKey
, str
);
381 static int didRam
= 0;
382 enum { kMaxPathBuf
= 512, kMaxBootVar
= 128 };
385 IOFindBSDRoot( char * rootName
, unsigned int rootNameSize
,
386 dev_t
* root
, u_int32_t
* oflags
)
390 IORegistryEntry
* regEntry
;
391 OSDictionary
* matching
= NULL
;
394 OSData
* data
= NULL
;
398 const char * mediaProperty
= NULL
;
401 const char * look
= NULL
;
403 bool debugInfoPrintedOnce
= false;
404 bool needNetworkKexts
= false;
405 const char * uuidStr
= NULL
;
407 static int mountAttempts
= 0;
411 // stall here for anyone matching on the IOBSD resource to finish (filesystems)
412 matching
= IOService::serviceMatching(gIOResourcesKey
);
414 matching
->setObject(gIOResourceMatchedKey
, gIOBSDKey
);
416 if ((service
= IOService::waitForMatchingService(matching
, 30ULL * kSecondScale
))) {
424 if (mountAttempts
++) {
425 IOLog("mount(%d) failed\n", mountAttempts
);
429 str
= (char *) IOMalloc( kMaxPathBuf
+ kMaxBootVar
);
431 return kIOReturnNoMemory
;
433 rdBootVar
= str
+ kMaxPathBuf
;
435 if (!PE_parse_boot_argn("rd", rdBootVar
, kMaxBootVar
)
436 && !PE_parse_boot_argn("rootdev", rdBootVar
, kMaxBootVar
)) {
441 if ((regEntry
= IORegistryEntry::fromPath( "/chosen", gIODTPlane
))) {
442 di_root_ramfile(regEntry
);
443 data
= OSDynamicCast(OSData
, regEntry
->getProperty( "root-matching" ));
445 matching
= OSDynamicCast(OSDictionary
, OSUnserializeXML((char *)data
->getBytesNoCopy()));
451 data
= (OSData
*) regEntry
->getProperty( "boot-uuid" );
453 uuidStr
= (const char*)data
->getBytesNoCopy();
454 OSString
*uuidString
= OSString::withCString( uuidStr
);
456 // match the boot-args boot-uuid processing below
458 IOLog("rooting via boot-uuid from /chosen: %s\n", uuidStr
);
459 IOService::publishResource( "boot-uuid", uuidString
);
460 uuidString
->release();
461 matching
= IOUUIDMatching();
462 mediaProperty
= "boot-uuid-media";
474 // See if we have a RAMDisk property in /chosen/memory-map. If so, make it into a device.
475 // It will become /dev/mdx, where x is 0-f.
478 if (!didRam
) { /* Have we already build this ram disk? */
479 didRam
= 1; /* Remember we did this */
480 if ((regEntry
= IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane
))) { /* Find the map node */
481 data
= (OSData
*)regEntry
->getProperty("RAMDisk"); /* Find the ram disk, if there */
482 if (data
) { /* We found one */
483 uintptr_t *ramdParms
;
484 ramdParms
= (uintptr_t *)data
->getBytesNoCopy(); /* Point to the ram disk base and size */
485 (void)mdevadd(-1, ml_static_ptovirt(ramdParms
[0]) >> 12, ramdParms
[1] >> 12, 0); /* Initialize it and pass back the device number */
487 regEntry
->release(); /* Toss the entry */
492 // Now check if we are trying to root on a memory device
495 if ((rdBootVar
[0] == 'm') && (rdBootVar
[1] == 'd') && (rdBootVar
[3] == 0)) {
496 dchar
= xchar
= rdBootVar
[2]; /* Get the actual device */
497 if ((xchar
>= '0') && (xchar
<= '9')) {
498 xchar
= xchar
- '0'; /* If digit, convert */
500 xchar
= xchar
& ~' '; /* Fold to upper case */
501 if ((xchar
>= 'A') && (xchar
<= 'F')) { /* Is this a valid digit? */
502 xchar
= (xchar
& 0xF) + 9; /* Convert the hex digit */
503 dchar
= dchar
| ' '; /* Fold to lower case */
505 xchar
= -1; /* Show bogus */
508 if (xchar
>= 0) { /* Do we have a valid memory device name? */
509 *root
= mdevlookup(xchar
); /* Find the device number */
510 if (*root
>= 0) { /* Did we find one? */
511 rootName
[0] = 'm'; /* Build root name */
512 rootName
[1] = 'd'; /* Build root name */
513 rootName
[2] = dchar
; /* Build root name */
514 rootName
[3] = 0; /* Build root name */
515 IOLog("BSD root: %s, major %d, minor %d\n", rootName
, major(*root
), minor(*root
));
516 *oflags
= 0; /* Show that this is not network */
518 #if CONFIG_KDP_INTERACTIVE_DEBUGGING
519 /* retrieve final ramdisk range and initialize KDP variables */
520 if (mdevgetrange(xchar
, &kdp_core_ramdisk_addr
, &kdp_core_ramdisk_size
) != 0) {
521 IOLog("Unable to retrieve range for root memory device %d\n", xchar
);
522 kdp_core_ramdisk_addr
= 0;
523 kdp_core_ramdisk_size
= 0;
527 goto iofrootx
; /* Join common exit... */
529 panic("IOFindBSDRoot: specified root memory device, %s, has not been configured\n", rdBootVar
); /* Not there */
533 if ((!matching
) && rdBootVar
[0]) {
536 if (look
[0] == '*') {
540 if (strncmp( look
, "en", strlen( "en" )) == 0) {
541 matching
= IONetworkNamePrefixMatching( "en" );
542 needNetworkKexts
= true;
543 } else if (strncmp( look
, "uuid", strlen( "uuid" )) == 0) {
545 OSString
*uuidString
;
547 uuid
= (char *)IOMalloc( kMaxBootVar
);
550 if (!PE_parse_boot_argn( "boot-uuid", uuid
, kMaxBootVar
)) {
551 panic( "rd=uuid but no boot-uuid=<value> specified" );
553 uuidString
= OSString::withCString( uuid
);
555 IOService::publishResource( "boot-uuid", uuidString
);
556 uuidString
->release();
557 IOLog( "\nWaiting for boot volume with UUID %s\n", uuid
);
558 matching
= IOUUIDMatching();
559 mediaProperty
= "boot-uuid-media";
561 IOFree( uuid
, kMaxBootVar
);
564 matching
= IOBSDNameMatching( look
);
570 // Match any HFS media
572 matching
= IOService::serviceMatching( "IOMedia" );
573 astring
= OSString::withCStringNoCopy("Apple_HFS");
575 matching
->setObject("Content", astring
);
580 if (gIOKitDebug
& kIOWaitQuietBeforeRoot
) {
581 IOLog( "Waiting for matching to complete\n" );
582 IOService::getPlatform()->waitQuiet();
585 if (true && matching
) {
586 OSSerialize
* s
= OSSerialize::withCapacity( 5 );
588 if (matching
->serialize( s
)) {
589 IOLog( "Waiting on %s\n", s
->text());
596 || PE_parse_boot_argn("-s", namep
, sizeof(namep
))) {
597 IOService::startDeferredMatches();
601 t
.tv_sec
= ROOTDEVICETIMEOUT
;
604 service
= IOService::waitForService( matching
, &t
);
605 if ((!service
) || (mountAttempts
== 10)) {
606 PE_display_icon( 0, "noroot");
607 IOLog( "Still waiting for root device\n" );
609 if (!debugInfoPrintedOnce
) {
610 debugInfoPrintedOnce
= true;
611 if (gIOKitDebug
& kIOLogDTree
) {
612 IOLog("\nDT plane:\n");
613 IOPrintPlane( gIODTPlane
);
615 if (gIOKitDebug
& kIOLogServiceTree
) {
616 IOLog("\nService plane:\n");
617 IOPrintPlane( gIOServicePlane
);
619 if (gIOKitDebug
& kIOLogMemory
) {
627 if (service
&& mediaProperty
) {
628 service
= (IOService
*)service
->getProperty(mediaProperty
);
634 // If the IOService we matched to is a subclass of IONetworkInterface,
635 // then make sure it has been registered with BSD and has a BSD name
639 && service
->metaCast( "IONetworkInterface" )
640 && !IORegisterNetworkInterface( service
)) {
646 service
->getPath( str
, &len
, gIOServicePlane
);
647 IOLog( "Got boot device = %s\n", str
);
649 iostr
= (OSString
*) service
->getProperty( kIOBSDNameKey
);
651 strlcpy( rootName
, iostr
->getCStringNoCopy(), rootNameSize
);
653 off
= (OSNumber
*) service
->getProperty( kIOBSDMajorKey
);
655 mjr
= off
->unsigned32BitValue();
657 off
= (OSNumber
*) service
->getProperty( kIOBSDMinorKey
);
659 mnr
= off
->unsigned32BitValue();
662 if (service
->metaCast( "IONetworkInterface" )) {
666 IOLog( "Wait for root failed\n" );
667 strlcpy( rootName
, "en0", rootNameSize
);
671 IOLog( "BSD root: %s", rootName
);
673 IOLog(", major %d, minor %d\n", mjr
, mnr
);
678 *root
= makedev( mjr
, mnr
);
681 IOFree( str
, kMaxPathBuf
+ kMaxBootVar
);
684 if ((gIOKitDebug
& (kIOLogDTree
| kIOLogServiceTree
| kIOLogMemory
)) && !debugInfoPrintedOnce
) {
685 IOService::getPlatform()->waitQuiet();
686 if (gIOKitDebug
& kIOLogDTree
) {
687 IOLog("\nDT plane:\n");
688 IOPrintPlane( gIODTPlane
);
690 if (gIOKitDebug
& kIOLogServiceTree
) {
691 IOLog("\nService plane:\n");
692 IOPrintPlane( gIOServicePlane
);
694 if (gIOKitDebug
& kIOLogMemory
) {
699 return kIOReturnSuccess
;
703 IORamDiskBSDRoot(void)
705 char rdBootVar
[kMaxBootVar
];
706 if (PE_parse_boot_argn("rd", rdBootVar
, kMaxBootVar
)
707 || PE_parse_boot_argn("rootdev", rdBootVar
, kMaxBootVar
)) {
708 if ((rdBootVar
[0] == 'm') && (rdBootVar
[1] == 'd') && (rdBootVar
[3] == 0)) {
716 IOSecureBSDRoot(const char * rootName
)
720 IOPlatformExpert
*pe
;
721 OSDictionary
*matching
;
722 const OSSymbol
*functionName
= OSSymbol::withCStringNoCopy("SecureRootName");
724 matching
= IOService::serviceMatching("IOPlatformExpert");
726 pe
= (IOPlatformExpert
*) IOService::waitForMatchingService(matching
, 30ULL * kSecondScale
);
729 // Returns kIOReturnNotPrivileged is the root device is not secure.
730 // Returns kIOReturnUnsupported if "SecureRootName" is not implemented.
731 result
= pe
->callPlatformFunction(functionName
, false, (void *)rootName
, (void *)NULL
, (void *)NULL
, (void *)NULL
);
732 functionName
->release();
733 OSSafeReleaseNULL(pe
);
735 if (result
== kIOReturnNotPrivileged
) {
739 #endif // CONFIG_EMBEDDED
743 IOBSDRegistryEntryForDeviceTree(char * path
)
745 return IORegistryEntry::fromPath(path
, gIODTPlane
);
749 IOBSDRegistryEntryRelease(void * entry
)
751 IORegistryEntry
* regEntry
= (IORegistryEntry
*)entry
;
760 IOBSDRegistryEntryGetData(void * entry
, char * property_name
,
764 IORegistryEntry
* regEntry
= (IORegistryEntry
*)entry
;
766 data
= (OSData
*) regEntry
->getProperty(property_name
);
768 *packet_length
= data
->getLength();
769 return data
->getBytesNoCopy();
775 IOBSDGetPlatformUUID( uuid_t uuid
, mach_timespec_t timeout
)
777 IOService
* resources
;
780 resources
= IOService::waitForService( IOService::resourceMatching( kIOPlatformUUIDKey
), (timeout
.tv_sec
|| timeout
.tv_nsec
) ? &timeout
: NULL
);
781 if (resources
== NULL
) {
782 return KERN_OPERATION_TIMED_OUT
;
785 string
= (OSString
*) IOService::getPlatform()->getProvider()->getProperty( kIOPlatformUUIDKey
);
786 if (string
== NULL
) {
787 return KERN_NOT_SUPPORTED
;
790 uuid_parse( string
->getCStringNoCopy(), uuid
);
796 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
798 #include <sys/conf.h>
799 #include <sys/vnode.h>
800 #include <sys/vnode_internal.h>
801 #include <sys/fcntl.h>
802 #include <IOKit/IOPolledInterface.h>
803 #include <IOKit/IOBufferMemoryDescriptor.h>
805 IOPolledFileIOVars
* gIOPolledCoreFileVars
;
806 kern_return_t gIOPolledCoreFileOpenRet
= kIOReturnNotReady
;
807 IOPolledCoreFileMode_t gIOPolledCoreFileMode
= kIOPolledCoreFileModeNotInitialized
;
809 #if IOPOLLED_COREFILE
811 #if defined(XNU_TARGET_OS_BRIDGE)
812 // On bridgeOS allocate a 150MB corefile and leave 150MB free
813 #define kIOCoreDumpSize 150ULL*1024ULL*1024ULL
814 #define kIOCoreDumpFreeSize 150ULL*1024ULL*1024ULL
816 #elif CONFIG_EMBEDDED /* defined(XNU_TARGET_OS_BRIDGE) */
817 // On embedded devices with >3GB DRAM we allocate a 500MB corefile
818 // otherwise allocate a 350MB corefile. Leave 350 MB free
820 #define kIOCoreDumpMinSize 350ULL*1024ULL*1024ULL
821 #define kIOCoreDumpLargeSize 500ULL*1024ULL*1024ULL
823 #define kIOCoreDumpFreeSize 350ULL*1024ULL*1024ULL
825 #else /* defined(XNU_TARGET_OS_BRIDGE) */
826 // on macOS devices allocate a corefile sized at 1GB / 32GB of DRAM,
827 // fallback to a 1GB corefile and leave at least 1GB free
828 #define kIOCoreDumpMinSize 1024ULL*1024ULL*1024ULL
829 #define kIOCoreDumpIncrementalSize 1024ULL*1024ULL*1024ULL
831 #define kIOCoreDumpFreeSize 1024ULL*1024ULL*1024ULL
833 // on older macOS devices we allocate a 1MB file at boot
834 // to store a panic time stackshot
835 #define kIOStackshotFileSize 1024ULL*1024ULL
837 #endif /* defined(XNU_TARGET_OS_BRIDGE) */
839 static IOPolledCoreFileMode_t
842 if (on_device_corefile_enabled()) {
843 return kIOPolledCoreFileModeCoredump
;
844 } else if (panic_stackshot_to_disk_enabled()) {
845 return kIOPolledCoreFileModeStackshot
;
847 return kIOPolledCoreFileModeDisabled
;
852 IOCoreFileGetSize(uint64_t *ideal_size
, uint64_t *fallback_size
, uint64_t *free_space_to_leave
, IOPolledCoreFileMode_t mode
)
854 unsigned int requested_corefile_size
= 0;
856 *ideal_size
= *fallback_size
= *free_space_to_leave
= 0;
858 #if defined(XNU_TARGET_OS_BRIDGE)
860 *ideal_size
= *fallback_size
= kIOCoreDumpSize
;
861 *free_space_to_leave
= kIOCoreDumpFreeSize
;
862 #elif CONFIG_EMBEDDED /* defined(XNU_TARGET_OS_BRIDGE) */
864 *ideal_size
= *fallback_size
= kIOCoreDumpMinSize
;
866 if (max_mem
> (3 * 1024ULL * 1024ULL * 1024ULL)) {
867 *ideal_size
= kIOCoreDumpLargeSize
;
870 *free_space_to_leave
= kIOCoreDumpFreeSize
;
871 #else /* defined(XNU_TARGET_OS_BRIDGE) */
872 if (mode
== kIOPolledCoreFileModeCoredump
) {
873 *ideal_size
= *fallback_size
= kIOCoreDumpMinSize
;
874 if (kIOCoreDumpIncrementalSize
!= 0 && max_mem
> (32 * 1024ULL * 1024ULL * 1024ULL)) {
875 *ideal_size
= ((ROUNDUP(max_mem
, (32 * 1024ULL * 1024ULL * 1024ULL)) / (32 * 1024ULL * 1024ULL * 1024ULL)) * kIOCoreDumpIncrementalSize
);
877 *free_space_to_leave
= kIOCoreDumpFreeSize
;
878 } else if (mode
== kIOPolledCoreFileModeStackshot
) {
879 *ideal_size
= *fallback_size
= *free_space_to_leave
= kIOStackshotFileSize
;
881 #endif /* defined(XNU_TARGET_OS_BRIDGE) */
882 // If a custom size was requested, override the ideal and requested sizes
883 if (PE_parse_boot_argn("corefile_size_mb", &requested_corefile_size
, sizeof(requested_corefile_size
))) {
884 IOLog("Boot-args specify %d MB kernel corefile\n", requested_corefile_size
);
886 *ideal_size
= *fallback_size
= (requested_corefile_size
* 1024ULL * 1024ULL);
893 IOOpenPolledCoreFile(thread_call_param_t __unused
, thread_call_param_t corefilename
)
895 assert(corefilename
!= NULL
);
898 char *filename
= (char *) corefilename
;
899 uint64_t corefile_size_bytes
= 0, corefile_fallback_size_bytes
= 0, free_space_to_leave_bytes
= 0;
900 IOPolledCoreFileMode_t mode_to_init
= GetCoreFileMode();
902 if (gIOPolledCoreFileVars
) {
905 if (!IOPolledInterface::gMetaClass
.getInstanceCount()) {
909 if (mode_to_init
== kIOPolledCoreFileModeDisabled
) {
910 gIOPolledCoreFileMode
= kIOPolledCoreFileModeDisabled
;
914 // We'll overwrite this once we open the file, we update this to mark that we have made
915 // it past initialization
916 gIOPolledCoreFileMode
= kIOPolledCoreFileModeClosed
;
918 IOCoreFileGetSize(&corefile_size_bytes
, &corefile_fallback_size_bytes
, &free_space_to_leave_bytes
, mode_to_init
);
921 err
= IOPolledFileOpen(filename
, kIOPolledFileCreate
, corefile_size_bytes
, free_space_to_leave_bytes
,
922 NULL
, 0, &gIOPolledCoreFileVars
, NULL
, NULL
, NULL
);
923 if (kIOReturnSuccess
== err
) {
925 } else if (kIOReturnNoSpace
== err
) {
926 IOLog("Failed to open corefile of size %llu MB (low disk space)",
927 (corefile_size_bytes
/ (1024ULL * 1024ULL)));
928 if (corefile_size_bytes
== corefile_fallback_size_bytes
) {
929 gIOPolledCoreFileOpenRet
= err
;
933 IOLog("Failed to open corefile of size %llu MB (returned error 0x%x)\n",
934 (corefile_size_bytes
/ (1024ULL * 1024ULL)), err
);
935 gIOPolledCoreFileOpenRet
= err
;
939 err
= IOPolledFileOpen(filename
, kIOPolledFileCreate
, corefile_fallback_size_bytes
, free_space_to_leave_bytes
,
940 NULL
, 0, &gIOPolledCoreFileVars
, NULL
, NULL
, NULL
);
941 if (kIOReturnSuccess
!= err
) {
942 IOLog("Failed to open corefile of size %llu MB (returned error 0x%x)\n",
943 (corefile_fallback_size_bytes
/ (1024ULL * 1024ULL)), err
);
944 gIOPolledCoreFileOpenRet
= err
;
949 gIOPolledCoreFileOpenRet
= IOPolledFilePollersSetup(gIOPolledCoreFileVars
, kIOPolledPreflightCoreDumpState
);
950 if (kIOReturnSuccess
!= gIOPolledCoreFileOpenRet
) {
951 IOPolledFileClose(&gIOPolledCoreFileVars
, 0, NULL
, 0, 0, 0);
952 IOLog("IOPolledFilePollersSetup for corefile failed with error: 0x%x\n", err
);
954 IOLog("Opened corefile of size %llu MB\n", (corefile_size_bytes
/ (1024ULL * 1024ULL)));
955 gIOPolledCoreFileMode
= mode_to_init
;
962 IOClosePolledCoreFile(void)
964 gIOPolledCoreFileOpenRet
= kIOReturnNotOpen
;
965 gIOPolledCoreFileMode
= kIOPolledCoreFileModeClosed
;
966 IOPolledFilePollersClose(gIOPolledCoreFileVars
, kIOPolledPostflightCoreDumpState
);
967 IOPolledFileClose(&gIOPolledCoreFileVars
, 0, NULL
, 0, 0, 0);
970 #endif /* IOPOLLED_COREFILE */
973 IOBSDMountChange(struct mount
* mp
, uint32_t op
)
975 #if IOPOLLED_COREFILE
983 case kIOMountChangeMount
:
984 case kIOMountChangeDidResize
:
986 if (gIOPolledCoreFileVars
) {
989 flags
= vfs_flags(mp
);
990 if (MNT_RDONLY
& flags
) {
993 if (!(MNT_LOCAL
& flags
)) {
997 vn
= vfs_vnodecovered(mp
);
1001 pathLen
= sizeof(path
);
1002 result
= vn_getpath(vn
, &path
[0], &pathLen
);
1010 #if defined(XNU_TARGET_OS_BRIDGE)
1011 // on bridgeOS systems we put the core in /private/var/internal. We don't
1012 // want to match with /private/var because /private/var/internal is often mounted
1013 // over /private/var
1014 if ((pathLen
- 1) < (int) strlen("/private/var/internal")) {
1018 if (0 != strncmp(path
, kIOCoreDumpPath
, pathLen
- 1)) {
1022 thread_call_enter1(corefile_open_call
, (void *) kIOCoreDumpPath
);
1025 case kIOMountChangeUnmount
:
1026 case kIOMountChangeWillResize
:
1027 if (gIOPolledCoreFileVars
&& (mp
== kern_file_mount(gIOPolledCoreFileVars
->fileRef
))) {
1028 thread_call_cancel_wait(corefile_open_call
);
1029 IOClosePolledCoreFile();
1033 #endif /* IOPOLLED_COREFILE */
1036 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1038 extern "C" boolean_t
1039 IOTaskHasEntitlement(task_t task
, const char * entitlement
)
1042 obj
= IOUserClient::copyClientEntitlement(task
, entitlement
);
1047 return obj
!= kOSBooleanFalse
;