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