2 * Copyright (c) 1998-2017 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@
29 #include <IOKit/IOCPU.h>
30 #include <IOKit/IOPlatformActions.h>
31 #include <IOKit/IODeviceTreeSupport.h>
32 #include <IOKit/IOKitDebug.h>
33 #include <IOKit/IOMapper.h>
34 #include <IOKit/IOMessage.h>
35 #include <IOKit/IONVRAM.h>
36 #include <IOKit/IOPlatformExpert.h>
37 #include <IOKit/IORangeAllocator.h>
38 #include <IOKit/IOWorkLoop.h>
39 #include <IOKit/pwr_mgt/RootDomain.h>
40 #include <IOKit/IOKitKeys.h>
41 #include <IOKit/IOTimeStamp.h>
42 #include <IOKit/IOUserClient.h>
43 #include <IOKit/IOKitDiagnosticsUserClient.h>
44 #include <IOKit/IOUserServer.h>
46 #include "IOKitKernelInternal.h"
48 #include <IOKit/system.h>
51 #include <libkern/c++/OSContainers.h>
52 #include <libkern/c++/OSSharedPtr.h>
53 #include <libkern/crypto/sha1.h>
54 #include <libkern/OSAtomic.h>
56 #if defined(__arm64__)
57 #include <arm64/tlb.h>
61 #include <machine/machine_routines.h>
62 #include <pexpert/pexpert.h>
63 #include <uuid/uuid.h>
64 #include <sys/sysctl.h>
67 #define kShutdownTimeout 30 //in secs
69 #if defined(XNU_TARGET_OS_OSX)
71 boolean_t coprocessor_cross_panic_enabled
= TRUE
;
72 #define APPLE_VENDOR_VARIABLE_GUID "4d1ede05-38c7-4a6a-9cc6-4bcca8b38c14"
73 #endif /* defined(XNU_TARGET_OS_OSX) */
75 void printDictionaryKeys(OSDictionary
* inDictionary
, char * inMsg
);
76 static void getCStringForObject(OSObject
*inObj
, char *outStr
, size_t outStrLen
);
79 * There are drivers which take mutexes in the quiesce callout or pass
80 * the quiesce/active action to super. Even though it sometimes panics,
81 * because it doesn't *always* panic, they get away with it.
82 * We need a chicken bit to diagnose and fix them all before this
83 * can be enabled by default.
85 * <rdar://problem/33831837> tracks turning this on by default.
87 uint32_t gEnforceQuiesceSafety
= 0;
89 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
91 #define super IOService
93 OSDefineMetaClassAndStructors(IOPlatformExpert
, IOService
)
95 OSMetaClassDefineReservedUsedX86(IOPlatformExpert
, 0);
96 OSMetaClassDefineReservedUsedX86(IOPlatformExpert
, 1);
97 OSMetaClassDefineReservedUsedX86(IOPlatformExpert
, 2);
98 OSMetaClassDefineReservedUsedX86(IOPlatformExpert
, 3);
99 OSMetaClassDefineReservedUsedX86(IOPlatformExpert
, 4);
100 OSMetaClassDefineReservedUsedX86(IOPlatformExpert
, 5);
101 OSMetaClassDefineReservedUsedX86(IOPlatformExpert
, 6);
103 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 7);
104 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 8);
105 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 9);
106 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 10);
107 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 11);
109 static IOPlatformExpert
* gIOPlatform
;
110 static OSDictionary
* gIOInterruptControllers
;
111 static IOLock
* gIOInterruptControllersLock
;
112 static IODTNVRAM
*gIOOptionsEntry
;
114 OSSymbol
* gPlatformInterruptControllerName
;
116 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
119 IOPlatformExpert::attach( IOService
* provider
)
121 if (!super::attach( provider
)) {
129 IOPlatformExpert::start( IOService
* provider
)
131 IORangeAllocator
* physicalRanges
;
132 OSData
* busFrequency
;
136 if (!super::start(provider
)) {
140 // Override the mapper present flag is requested by boot arguments, if SIP disabled.
142 if (csr_check(CSR_ALLOW_UNRESTRICTED_FS
) == 0)
143 #endif /* CONFIG_CSR */
145 if (PE_parse_boot_argn("dart", &debugFlags
, sizeof(debugFlags
)) && (debugFlags
== 0)) {
146 removeProperty(kIOPlatformMapperPresentKey
);
148 #if DEBUG || DEVELOPMENT
149 if (PE_parse_boot_argn("-x", &debugFlags
, sizeof(debugFlags
))) {
150 removeProperty(kIOPlatformMapperPresentKey
);
152 #endif /* DEBUG || DEVELOPMENT */
155 // Register the presence or lack thereof a system
156 // PCI address mapper with the IOMapper class
157 IOMapper::setMapperRequired(NULL
!= getProperty(kIOPlatformMapperPresentKey
));
159 gIOInterruptControllers
= OSDictionary::withCapacity(1);
160 gIOInterruptControllersLock
= IOLockAlloc();
162 // Correct the bus frequency in the device tree.
163 busFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.bus_clock_rate_hz
, 4);
164 provider
->setProperty("clock-frequency", busFrequency
);
165 busFrequency
->release();
167 gPlatformInterruptControllerName
= (OSSymbol
*)OSSymbol::withCStringNoCopy("IOPlatformInterruptController");
169 physicalRanges
= IORangeAllocator::withRange(0xffffffff, 1, 16,
170 IORangeAllocator::kLocking
);
171 assert(physicalRanges
);
172 setProperty("Platform Memory Ranges", physicalRanges
);
177 PMInstantiatePowerDomains();
179 #if !defined(__x86_64__)
180 publishPlatformUUIDAndSerial();
181 #endif /* !defined(__x86_64__) */
183 #if defined (__x86_64__)
184 if (PEGetCoprocessorVersion() >= kCoprocessorVersion2
) {
185 coprocessor_paniclog_flush
= TRUE
;
186 extended_debug_log_init();
190 PE_parse_boot_argn("enforce_quiesce_safety", &gEnforceQuiesceSafety
,
191 sizeof(gEnforceQuiesceSafety
));
193 return configure(provider
);
197 IOPlatformExpert::configure( IOService
* provider
)
203 topLevel
= OSDynamicCast( OSSet
, getProperty("top-level"));
206 while ((dict
= OSDynamicCast( OSDictionary
,
207 topLevel
->getAnyObject()))) {
209 topLevel
->removeObject( dict
);
210 nub
= createNub( dict
);
216 nub
->registerService();
224 IOPlatformExpert::createNub( OSDictionary
* from
)
228 nub
= new IOPlatformDevice
;
230 if (!nub
->init( from
)) {
239 IOPlatformExpert::compareNubName( const IOService
* nub
,
240 OSString
* name
, OSString
** matched
) const
242 return nub
->IORegistryEntry::compareName( name
, matched
);
246 IOPlatformExpert::compareNubName( const IOService
* nub
,
247 OSString
* name
, OSSharedPtr
<OSString
>& matched
) const
249 OSString
* matchedRaw
= NULL
;
250 bool result
= compareNubName(nub
, name
, &matchedRaw
);
251 matched
.reset(matchedRaw
, OSNoRetain
);
256 IOPlatformExpert::getNubResources( IOService
* nub
)
258 return kIOReturnSuccess
;
262 IOPlatformExpert::getBootROMType(void)
264 return _peBootROMType
;
268 IOPlatformExpert::getChipSetType(void)
270 return _peChipSetType
;
274 IOPlatformExpert::getMachineType(void)
276 return _peMachineType
;
280 IOPlatformExpert::setBootROMType(long peBootROMType
)
282 _peBootROMType
= peBootROMType
;
286 IOPlatformExpert::setChipSetType(long peChipSetType
)
288 _peChipSetType
= peChipSetType
;
292 IOPlatformExpert::setMachineType(long peMachineType
)
294 _peMachineType
= peMachineType
;
298 IOPlatformExpert::getMachineName( char * /*name*/, int /*maxLength*/)
304 IOPlatformExpert::getModelName( char * /*name*/, int /*maxLength*/)
310 IOPlatformExpert::getTargetName( char * /*name*/, int /*maxLength*/)
316 IOPlatformExpert::getProductName( char * /*name*/, int /*maxLength*/)
322 IOPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
)
328 IOPlatformExpert::getPhysicalRangeAllocator(void)
330 return OSDynamicCast(IORangeAllocator
,
331 getProperty("Platform Memory Ranges"));
334 int (*PE_halt_restart
)(unsigned int type
) = NULL
;
337 IOPlatformExpert::haltRestart(unsigned int type
)
339 if (type
== kPEPanicSync
) {
343 if (type
== kPEHangCPU
) {
348 if (type
== kPEUPSDelayHaltCPU
) {
349 // RestartOnPowerLoss feature was turned on, proceed with shutdown.
353 #if defined (__x86_64__)
354 // On ARM kPEPanicRestartCPU is supported in the drivers
355 if (type
== kPEPanicRestartCPU
) {
356 type
= kPERestartCPU
;
360 if (PE_halt_restart
) {
361 return (*PE_halt_restart
)(type
);
368 IOPlatformExpert::sleepKernel(void)
374 intState
= ml_set_interrupts_enabled(false);
376 for (cnt
= 0; cnt
< 10000; cnt
++) {
380 ml_set_interrupts_enabled(intState
);
382 // PE_initialize_console(0, kPEDisableScreen);
386 // PE_initialize_console(0, kPEEnableScreen);
391 IOPlatformExpert::getGMTTimeOfDay(void)
397 IOPlatformExpert::setGMTTimeOfDay(long secs
)
403 IOPlatformExpert::getConsoleInfo( PE_Video
* consoleInfo
)
405 return PE_current_console( consoleInfo
);
409 IOPlatformExpert::setConsoleInfo( PE_Video
* consoleInfo
,
412 return PE_initialize_console( consoleInfo
, op
);
416 IOPlatformExpert::registerInterruptController(OSSymbol
*name
, IOInterruptController
*interruptController
)
418 IOLockLock(gIOInterruptControllersLock
);
420 gIOInterruptControllers
->setObject(name
, interruptController
);
422 IOLockWakeup(gIOInterruptControllersLock
,
423 gIOInterruptControllers
, /* one-thread */ false);
425 IOLockUnlock(gIOInterruptControllersLock
);
427 return kIOReturnSuccess
;
431 IOPlatformExpert::deregisterInterruptController(OSSymbol
*name
)
433 IOLockLock(gIOInterruptControllersLock
);
435 gIOInterruptControllers
->removeObject(name
);
437 IOLockUnlock(gIOInterruptControllersLock
);
439 return kIOReturnSuccess
;
442 IOInterruptController
*
443 IOPlatformExpert::lookUpInterruptController(OSSymbol
*name
)
447 IOLockLock(gIOInterruptControllersLock
);
449 object
= gIOInterruptControllers
->getObject(name
);
451 if (object
!= NULL
) {
455 IOLockSleep(gIOInterruptControllersLock
,
456 gIOInterruptControllers
, THREAD_UNINT
);
459 IOLockUnlock(gIOInterruptControllersLock
);
460 return OSDynamicCast(IOInterruptController
, object
);
465 IOPlatformExpert::setCPUInterruptProperties(IOService
*service
)
467 IOInterruptController
*controller
;
469 OSDictionary
*matching
= serviceMatching("IOInterruptController");
470 matching
= propertyMatching(gPlatformInterruptControllerName
, kOSBooleanTrue
, matching
);
472 controller
= OSDynamicCast(IOInterruptController
, waitForService(matching
));
474 controller
->setCPUInterruptProperties(service
);
479 IOPlatformExpert::atInterruptLevel(void)
481 return ml_at_interrupt_context();
485 IOPlatformExpert::platformAdjustService(IOService */
*service*/
)
491 IOPlatformExpert::getUTCTimeOfDay(clock_sec_t
* secs
, clock_nsec_t
* nsecs
)
493 *secs
= getGMTTimeOfDay();
498 IOPlatformExpert::setUTCTimeOfDay(clock_sec_t secs
, __unused clock_nsec_t nsecs
)
500 setGMTTimeOfDay(secs
);
504 //*********************************************************************************
507 //*********************************************************************************
511 PMLog(const char *who
, unsigned long event
,
512 unsigned long param1
, unsigned long param2
)
516 clock_get_system_microtime(&nows
, &nowus
);
517 nowus
+= (nows
% 1000) * 1000000;
519 kprintf("pm%u %p %.30s %d %lx %lx\n",
520 nowus
, OBFUSCATE(current_thread()), who
, // Identity
521 (int) event
, (long)OBFUSCATE(param1
), (long)OBFUSCATE(param2
)); // Args
525 //*********************************************************************************
526 // PMInstantiatePowerDomains
528 // In this vanilla implementation, a Root Power Domain is instantiated.
529 // All other objects which register will be children of this Root.
530 // Where this is inappropriate, PMInstantiatePowerDomains is overridden
531 // in a platform-specific subclass.
532 //*********************************************************************************
535 IOPlatformExpert::PMInstantiatePowerDomains( void )
537 root
= new IOPMrootDomain
;
544 //*********************************************************************************
547 // In this vanilla implementation, all callers are made children of the root power domain.
548 // Where this is inappropriate, PMRegisterDevice is overridden in a platform-specific subclass.
549 //*********************************************************************************
552 IOPlatformExpert::PMRegisterDevice(IOService
* theNub
, IOService
* theDevice
)
554 root
->addPowerChild( theDevice
);
557 //*********************************************************************************
560 //*********************************************************************************
563 IOPlatformExpert::hasPMFeature(unsigned long featureMask
)
565 return (_pePMFeatures
& featureMask
) != 0;
568 //*********************************************************************************
571 //*********************************************************************************
574 IOPlatformExpert::hasPrivPMFeature(unsigned long privFeatureMask
)
576 return (_pePrivPMFeatures
& privFeatureMask
) != 0;
579 //*********************************************************************************
580 // numBatteriesSupported
582 //*********************************************************************************
585 IOPlatformExpert::numBatteriesSupported(void)
587 return _peNumBatteriesSupported
;
590 //*********************************************************************************
593 // This method is called by the instantiated sublass of the platform expert to
594 // determine how a device should be inserted into the Power Domain. The subclass
595 // provides an XML power tree description against which a device is matched based
596 // on class and provider. If a match is found this routine returns true in addition
597 // to flagging the description tree at the appropriate node that a device has been
598 // registered for the given service.
599 //*********************************************************************************
602 IOPlatformExpert::CheckSubTree(OSArray
* inSubTree
, IOService
* theNub
, IOService
* theDevice
, OSDictionary
* theParent
)
605 unsigned int numPowerTreeNodes
;
606 OSDictionary
* entry
;
607 OSDictionary
* matchingDictionary
;
608 OSDictionary
* providerDictionary
;
609 OSDictionary
* deviceDictionary
;
610 OSDictionary
* nubDictionary
;
612 bool nodeFound
= false;
613 bool continueSearch
= false;
614 bool deviceMatch
= false;
615 bool providerMatch
= false;
616 bool multiParentMatch
= false;
618 if ((NULL
== theDevice
) || (NULL
== inSubTree
)) {
622 numPowerTreeNodes
= inSubTree
->getCount();
624 // iterate through the power tree to find a home for this device
626 for (i
= 0; i
< numPowerTreeNodes
; i
++) {
627 entry
= (OSDictionary
*) inSubTree
->getObject(i
);
629 matchingDictionary
= (OSDictionary
*) entry
->getObject("device");
630 providerDictionary
= (OSDictionary
*) entry
->getObject("provider");
632 deviceMatch
= true; // if no matching dictionary, this is not a criteria and so must match
633 if (matchingDictionary
) {
635 if (NULL
!= (deviceDictionary
= theDevice
->dictionaryWithProperties())) {
636 deviceMatch
= deviceDictionary
->isEqualTo( matchingDictionary
, matchingDictionary
);
637 deviceDictionary
->release();
641 providerMatch
= true; // we indicate a match if there is no nub or provider
642 if (theNub
&& providerDictionary
) {
643 providerMatch
= false;
644 if (NULL
!= (nubDictionary
= theNub
->dictionaryWithProperties())) {
645 providerMatch
= nubDictionary
->isEqualTo( providerDictionary
, providerDictionary
);
646 nubDictionary
->release();
650 multiParentMatch
= true; // again we indicate a match if there is no multi-parent node
651 if (deviceMatch
&& providerMatch
) {
652 if (NULL
!= multipleParentKeyValue
) {
653 OSNumber
* aNumber
= (OSNumber
*) entry
->getObject("multiple-parent");
654 multiParentMatch
= (NULL
!= aNumber
) ? multipleParentKeyValue
->isEqualTo(aNumber
) : false;
658 nodeFound
= (deviceMatch
&& providerMatch
&& multiParentMatch
);
660 // if the power tree specifies a provider dictionary but theNub is
661 // NULL then we cannot match with this entry.
663 if (theNub
== NULL
&& providerDictionary
!= NULL
) {
667 // if this node is THE ONE...then register the device
670 if (RegisterServiceInTree(theDevice
, entry
, theParent
, theNub
)) {
671 if (kIOLogPower
& gIOKitDebug
) {
672 IOLog("PMRegisterDevice/CheckSubTree - service registered!\n");
675 numInstancesRegistered
++;
677 // determine if we need to search for additional nodes for this item
678 multipleParentKeyValue
= (OSNumber
*) entry
->getObject("multiple-parent");
684 continueSearch
= ((false == nodeFound
) || (NULL
!= multipleParentKeyValue
));
686 if (continueSearch
&& (NULL
!= (children
= (OSArray
*) entry
->getObject("children")))) {
687 nodeFound
= CheckSubTree( children
, theNub
, theDevice
, entry
);
688 continueSearch
= ((false == nodeFound
) || (NULL
!= multipleParentKeyValue
));
691 if (false == continueSearch
) {
699 //*********************************************************************************
700 // RegisterServiceInTree
702 // Register a device at the specified node of our power tree.
703 //*********************************************************************************
706 IOPlatformExpert::RegisterServiceInTree(IOService
* theService
, OSDictionary
* theTreeNode
, OSDictionary
* theTreeParentNode
, IOService
* theProvider
)
708 IOService
* aService
;
709 bool registered
= false;
711 unsigned int numChildren
;
712 OSDictionary
* child
;
714 // make sure someone is not already registered here
716 if (NULL
== theTreeNode
->getObject("service")) {
717 if (theTreeNode
->setObject("service", OSDynamicCast( OSObject
, theService
))) {
718 // 1. CHILDREN ------------------
720 // we registered the node in the tree...now if the node has children
721 // registered we must tell this service to add them.
723 if (NULL
!= (children
= (OSArray
*) theTreeNode
->getObject("children"))) {
724 numChildren
= children
->getCount();
725 for (unsigned int i
= 0; i
< numChildren
; i
++) {
726 if (NULL
!= (child
= (OSDictionary
*) children
->getObject(i
))) {
727 if (NULL
!= (aService
= (IOService
*) child
->getObject("service"))) {
728 theService
->addPowerChild(aService
);
734 // 2. PARENT --------------------
736 // also we must notify the parent of this node (if a registered service
737 // exists there) of a new child.
739 if (theTreeParentNode
) {
740 if (NULL
!= (aService
= (IOService
*) theTreeParentNode
->getObject("service"))) {
741 if (aService
!= theProvider
) {
742 aService
->addPowerChild(theService
);
754 //*********************************************************************************
755 // printDictionaryKeys
757 // Print the keys for the given dictionary and selected contents.
758 //*********************************************************************************
760 printDictionaryKeys(OSDictionary
* inDictionary
, char * inMsg
)
762 OSCollectionIterator
* mcoll
= OSCollectionIterator::withCollection(inDictionary
);
769 mkey
= OSDynamicCast(OSSymbol
, mcoll
->getNextObject());
772 // kprintf ("dictionary key #%d: %s\n", i, mkey->getCStringNoCopy () );
774 // if this is the IOClass key, print it's contents
776 if (mkey
->isEqualTo("IOClass")) {
777 ioClass
= (OSString
*) inDictionary
->getObject("IOClass");
779 IOLog("%s IOClass is %s\n", inMsg
, ioClass
->getCStringNoCopy());
783 // if this is an IOProviderClass key print it
785 if (mkey
->isEqualTo("IOProviderClass")) {
786 ioClass
= (OSString
*) inDictionary
->getObject("IOProviderClass");
788 IOLog("%s IOProviderClass is %s\n", inMsg
, ioClass
->getCStringNoCopy());
792 // also print IONameMatch keys
793 if (mkey
->isEqualTo("IONameMatch")) {
794 ioClass
= (OSString
*) inDictionary
->getObject("IONameMatch");
796 IOLog("%s IONameMatch is %s\n", inMsg
, ioClass
->getCStringNoCopy());
800 // also print IONameMatched keys
802 if (mkey
->isEqualTo("IONameMatched")) {
803 ioClass
= (OSString
*) inDictionary
->getObject("IONameMatched");
805 IOLog("%s IONameMatched is %s\n", inMsg
, ioClass
->getCStringNoCopy());
812 if (mkey
->isEqualTo("AAPL,clock-id")) {
814 cstr
= getCStringForObject(inDictionary
->getObject("AAPL,clock-id"));
816 kprintf(" ===> AAPL,clock-id is %s\n", cstr
);
823 if (mkey
->isEqualTo("name")) {
826 getCStringForObject(inDictionary
->getObject("name"), nameStr
,
828 if (strlen(nameStr
) > 0) {
829 IOLog("%s name is %s\n", inMsg
, nameStr
);
833 mkey
= (OSSymbol
*) mcoll
->getNextObject();
842 getCStringForObject(OSObject
*inObj
, char *outStr
, size_t outStrLen
)
847 if ((NULL
== inObj
) || (NULL
== outStr
)) {
851 char * objString
= (char *) (inObj
->getMetaClass())->getClassName();
853 if ((0 == strncmp(objString
, "OSString", sizeof("OSString"))) ||
854 (0 == strncmp(objString
, "OSSymbol", sizeof("OSSymbol")))) {
855 strlcpy(outStr
, ((OSString
*)inObj
)->getCStringNoCopy(), outStrLen
);
856 } else if (0 == strncmp(objString
, "OSData", sizeof("OSData"))) {
857 len
= ((OSData
*)inObj
)->getLength();
858 buffer
= (char *)((OSData
*)inObj
)->getBytesNoCopy();
859 if (buffer
&& (len
> 0)) {
860 for (i
= 0; i
< len
; i
++) {
861 outStr
[i
] = buffer
[i
];
868 /* IOShutdownNotificationsTimedOut
869 * - Called from a timer installed by PEHaltRestart
871 #if !defined(__x86_64)
875 IOShutdownNotificationsTimedOut(
876 thread_call_param_t p0
,
877 thread_call_param_t p1
)
879 #if !defined(__x86_64__)
880 /* 30 seconds has elapsed - panic */
881 panic("Halt/Restart Timed Out");
883 #else /* !defined(__x86_64__) */
884 int type
= (int)(long)p0
;
885 uint32_t timeout
= (uint32_t)(uintptr_t)p1
;
887 IOPMrootDomain
*pmRootDomain
= IOService::getPMRootDomain();
889 if ((PEGetCoprocessorVersion() >= kCoprocessorVersion2
) || pmRootDomain
->checkShutdownTimeout()) {
890 pmRootDomain
->panicWithShutdownLog(timeout
* 1000);
894 /* 30 seconds has elapsed - resume shutdown */
896 gIOPlatform
->haltRestart(type
);
898 #endif /* defined(__x86_64__) */
904 * Callouts from BSD for machine name & model
908 * PEGetMachineName() and PEGetModelName() are inconsistent across
909 * architectures, and considered deprecated. Use PEGetTargetName() and
910 * PEGetProductName() instead.
913 PEGetMachineName( char * name
, int maxLength
)
916 return gIOPlatform
->getMachineName( name
, maxLength
);
923 * PEGetMachineName() and PEGetModelName() are inconsistent across
924 * architectures, and considered deprecated. Use PEGetTargetName() and
925 * PEGetProductName() instead.
928 PEGetModelName( char * name
, int maxLength
)
931 return gIOPlatform
->getModelName( name
, maxLength
);
938 PEGetTargetName( char * name
, int maxLength
)
941 return gIOPlatform
->getTargetName( name
, maxLength
);
948 PEGetProductName( char * name
, int maxLength
)
951 return gIOPlatform
->getProductName( name
, maxLength
);
958 PEGetPlatformEpoch(void)
961 return (int) gIOPlatform
->getBootROMType();
967 /* Handle necessary platform specific actions prior to panic */
969 PEInitiatePanic(void)
971 #if defined(__arm64__)
973 * Trigger a TLB flush so any hard hangs exercise the SoC diagnostic
974 * collection flow rather than hanging late in panic (see rdar://58062030)
976 flush_mmu_tlb_entry(0);
981 PEHaltRestartInternal(unsigned int type
, uint32_t details
)
983 IOPMrootDomain
*pmRootDomain
;
984 AbsoluteTime deadline
;
985 thread_call_t shutdown_hang
;
986 IORegistryEntry
*node
;
988 uint32_t timeout
= kShutdownTimeout
;
989 static boolean_t panic_begin_called
= FALSE
;
991 if (type
== kPEHaltCPU
|| type
== kPERestartCPU
|| type
== kPEUPSDelayHaltCPU
) {
992 /* If we're in the panic path, the locks and memory allocations required below
993 * could fail. So just try to reboot instead of risking a nested panic.
995 if (panic_begin_called
) {
996 goto skip_to_haltRestart
;
999 pmRootDomain
= IOService::getPMRootDomain();
1000 /* Notify IOKit PM clients of shutdown/restart
1001 * Clients subscribe to this message with a call to
1002 * IOService::registerInterest()
1005 /* Spawn a thread that will panic in 30 seconds.
1006 * If all goes well the machine will be off by the time
1007 * the timer expires. If the device wants a different
1008 * timeout, use that value instead of 30 seconds.
1010 #if defined(__arm__) || defined(__arm64__)
1011 #define RESTART_NODE_PATH "/defaults"
1013 #define RESTART_NODE_PATH "/chosen"
1015 node
= IORegistryEntry::fromPath( RESTART_NODE_PATH
, gIODTPlane
);
1017 data
= OSDynamicCast( OSData
, node
->getProperty( "halt-restart-timeout" ));
1018 if (data
&& data
->getLength() == 4) {
1019 timeout
= *((uint32_t *) data
->getBytesNoCopy());
1023 #if (DEVELOPMENT || DEBUG)
1024 /* Override the default timeout via a boot-arg */
1025 uint32_t boot_arg_val
;
1026 if (PE_parse_boot_argn("halt_restart_timeout", &boot_arg_val
, sizeof(boot_arg_val
))) {
1027 timeout
= boot_arg_val
;
1032 shutdown_hang
= thread_call_allocate( &IOShutdownNotificationsTimedOut
,
1033 (thread_call_param_t
)(uintptr_t) type
);
1034 clock_interval_to_deadline( timeout
, kSecondScale
, &deadline
);
1035 thread_call_enter1_delayed( shutdown_hang
, (thread_call_param_t
)(uintptr_t)timeout
, deadline
);
1038 pmRootDomain
->handlePlatformHaltRestart(type
);
1039 /* This notification should have few clients who all do
1040 * their work synchronously.
1042 * In this "shutdown notification" context we don't give
1043 * drivers the option of working asynchronously and responding
1044 * later. PM internals make it very hard to wait for asynchronous
1047 } else if (type
== kPEPanicRestartCPU
|| type
== kPEPanicSync
|| type
== kPEPanicRestartCPUNoCallouts
) {
1048 if (type
== kPEPanicRestartCPU
) {
1049 // Notify any listeners that we're done collecting
1050 // panic data before we call through to do the restart
1051 #if defined(__x86_64__)
1052 if (coprocessor_cross_panic_enabled
)
1054 IOCPURunPlatformPanicActions(kPEPanicEnd
, details
);
1055 } else if (type
== kPEPanicRestartCPUNoCallouts
) {
1056 // We skipped the callouts so now set the type to
1057 // the variant that the platform uses for panic restarts.
1058 type
= kPEPanicRestartCPU
;
1062 // Do an initial sync to flush as much panic data as possible,
1063 // in case we have a problem in one of the platorm panic handlers.
1064 // After running the platform handlers, do a final sync w/
1065 // platform hardware quiesced for the panic.
1066 PE_sync_panic_buffers();
1067 IOCPURunPlatformPanicActions(type
, details
);
1068 PE_sync_panic_buffers();
1069 } else if (type
== kPEPanicEnd
) {
1070 #if defined(__x86_64__)
1071 if (coprocessor_cross_panic_enabled
)
1073 IOCPURunPlatformPanicActions(type
, details
);
1074 } else if (type
== kPEPanicBegin
) {
1075 #if defined(__x86_64__)
1076 if (coprocessor_cross_panic_enabled
)
1079 // Only call the kPEPanicBegin callout once
1080 if (!panic_begin_called
) {
1081 panic_begin_called
= TRUE
;
1082 IOCPURunPlatformPanicActions(type
, details
);
1085 } else if (type
== kPEPanicDiagnosticsDone
) {
1086 IOCPURunPlatformPanicActions(type
, details
);
1089 skip_to_haltRestart
:
1091 return gIOPlatform
->haltRestart(type
);
1098 PEHaltRestart(unsigned int type
)
1100 return PEHaltRestartInternal(type
, 0);
1104 PESavePanicInfo(UInt8
*buffer
, UInt32 length
)
1106 if (gIOPlatform
!= NULL
) {
1107 return (UInt32
) gIOPlatform
->savePanicInfo(buffer
, length
);
1114 PESavePanicInfoAction(void *buffer
, UInt32 offset
, UInt32 length
)
1116 IOCPURunPlatformPanicSyncAction(buffer
, offset
, length
);
1122 * Depending on the platform, the /options node may not be created
1123 * until after IOKit matching has started, by an externally-supplied
1124 * platform expert subclass. Therefore, we must check for its presence
1125 * here and update gIOOptionsEntry for the platform code as necessary.
1128 init_gIOOptionsEntry(void)
1130 IORegistryEntry
*entry
;
1132 volatile void **options
;
1135 if (gIOOptionsEntry
) {
1139 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
1144 nvram_entry
= (void *) OSDynamicCast(IODTNVRAM
, entry
);
1149 options
= (volatile void **) &gIOOptionsEntry
;
1150 if (!OSCompareAndSwapPtr(NULL
, nvram_entry
, options
)) {
1162 /* pass in a NULL value if you just want to figure out the len */
1164 PEReadNVRAMProperty(const char *symbol
, void *value
,
1171 if (!symbol
|| !len
) {
1175 if (init_gIOOptionsEntry() < 0) {
1182 obj
= gIOOptionsEntry
->getProperty(symbol
);
1187 /* convert to data */
1188 data
= OSDynamicCast(OSData
, obj
);
1193 *len
= data
->getLength();
1194 vlen
= min(vlen
, *len
);
1195 if (value
&& vlen
) {
1196 memcpy((void *) value
, data
->getBytesNoCopy(), vlen
);
1206 PEWriteNVRAMBooleanProperty(const char *symbol
, boolean_t value
)
1208 const OSSymbol
*sym
= NULL
;
1209 OSBoolean
*data
= NULL
;
1212 if (symbol
== NULL
) {
1216 if (init_gIOOptionsEntry() < 0) {
1220 if ((sym
= OSSymbol::withCStringNoCopy(symbol
)) == NULL
) {
1224 data
= value
? kOSBooleanTrue
: kOSBooleanFalse
;
1225 ret
= gIOOptionsEntry
->setProperty(sym
, data
);
1229 /* success, force the NVRAM to flush writes */
1231 gIOOptionsEntry
->sync();
1239 PEWriteNVRAMPropertyInternal(const char *symbol
, boolean_t copySymbol
, const void *value
,
1240 const unsigned int len
)
1242 const OSSymbol
*sym
;
1246 if (!symbol
|| !value
|| !len
) {
1250 if (init_gIOOptionsEntry() < 0) {
1254 if (copySymbol
== TRUE
) {
1255 sym
= OSSymbol::withCString(symbol
);
1257 sym
= OSSymbol::withCStringNoCopy(symbol
);
1264 data
= OSData::withBytes((void *) value
, len
);
1269 ret
= gIOOptionsEntry
->setProperty(sym
, data
);
1276 gIOOptionsEntry
->sync();
1285 PEWriteNVRAMProperty(const char *symbol
, const void *value
,
1286 const unsigned int len
)
1288 return PEWriteNVRAMPropertyInternal(symbol
, FALSE
, value
, len
);
1292 PEWriteNVRAMPropertyWithCopy(const char *symbol
, const void *value
,
1293 const unsigned int len
)
1295 return PEWriteNVRAMPropertyInternal(symbol
, TRUE
, value
, len
);
1299 PERemoveNVRAMProperty(const char *symbol
)
1301 const OSSymbol
*sym
;
1307 if (init_gIOOptionsEntry() < 0) {
1311 sym
= OSSymbol::withCStringNoCopy(symbol
);
1316 gIOOptionsEntry
->removeProperty(sym
);
1320 gIOOptionsEntry
->sync();
1328 PEGetGMTTimeOfDay(void)
1333 PEGetUTCTimeOfDay(&secs
, &usecs
);
1338 PESetGMTTimeOfDay(long secs
)
1340 PESetUTCTimeOfDay(secs
, 0);
1344 PEGetUTCTimeOfDay(clock_sec_t
* secs
, clock_usec_t
* usecs
)
1346 clock_nsec_t nsecs
= 0;
1350 gIOPlatform
->getUTCTimeOfDay(secs
, &nsecs
);
1353 assert(nsecs
< NSEC_PER_SEC
);
1354 *usecs
= nsecs
/ NSEC_PER_USEC
;
1358 PESetUTCTimeOfDay(clock_sec_t secs
, clock_usec_t usecs
)
1360 assert(usecs
< USEC_PER_SEC
);
1362 gIOPlatform
->setUTCTimeOfDay(secs
, usecs
* NSEC_PER_USEC
);
1367 PEGetCoprocessorVersion( void )
1369 coprocessor_type_t coprocessor_version
= kCoprocessorVersionNone
;
1370 #if defined(__x86_64__)
1371 IORegistryEntry
*platform_entry
= NULL
;
1372 OSData
*coprocessor_version_obj
= NULL
;
1374 platform_entry
= IORegistryEntry::fromPath(kIODeviceTreePlane
":/efi/platform");
1375 if (platform_entry
!= NULL
) {
1376 coprocessor_version_obj
= OSDynamicCast(OSData
, platform_entry
->getProperty("apple-coprocessor-version"));
1377 if ((coprocessor_version_obj
!= NULL
) && (coprocessor_version_obj
->getLength() <= sizeof(uint64_t))) {
1378 memcpy(&coprocessor_version
, coprocessor_version_obj
->getBytesNoCopy(), coprocessor_version_obj
->getLength());
1380 platform_entry
->release();
1383 return coprocessor_version
;
1387 bool gIOPlatformUUIDAndSerialDone
= false;
1390 IOPlatformExpert::publishPlatformUUIDAndSerial( void )
1392 if (!gIOPlatformUUIDAndSerialDone
) {
1393 // Parse the serial-number data and publish a user-readable string
1394 if (NULL
== getProvider()->getProperty(kIOPlatformSerialNumberKey
)) {
1395 OSData
* mydata
= (OSData
*) (getProvider()->getProperty("serial-number"));
1396 if (mydata
!= NULL
) {
1397 OSString
*serNoString
= createSystemSerialNumberString(mydata
);
1398 if (serNoString
!= NULL
) {
1399 getProvider()->setProperty(kIOPlatformSerialNumberKey
, serNoString
);
1400 serNoString
->release();
1404 IOPlatformExpertDevice
*provider
= OSDynamicCast(IOPlatformExpertDevice
, getProvider());
1405 assert(provider
!= NULL
);
1406 provider
->generatePlatformUUID();
1409 if (gIOPlatformUUIDAndSerialDone
) {
1410 publishResource(kIOPlatformUUIDKey
, getProvider()->getProperty(kIOPlatformUUIDKey
));
1415 IOPlatformExpert::publishNVRAM( void )
1417 if (init_gIOOptionsEntry() < 0) {
1418 IOPlatformExpertDevice
*provider
= OSDynamicCast(IOPlatformExpertDevice
, getProvider());
1419 assert(provider
!= NULL
);
1420 provider
->createNVRAM();
1422 if (gIOOptionsEntry
!= NULL
) {
1423 gIOOptionsEntry
->registerService();
1428 IOPlatformExpert::registerNVRAMController(IONVRAMController
* caller
)
1430 #if defined(__x86_64__)
1432 IORegistryEntry
* entry
;
1435 * If we have panic debugging enabled and a prod-fused coprocessor,
1436 * disable cross panics so that the co-processor doesn't cause the system
1437 * to reset when we enter the debugger or hit a panic on the x86 side.
1439 if (panicDebugging
) {
1440 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
1442 data
= OSDynamicCast( OSData
, entry
->getProperty( APPLE_VENDOR_VARIABLE_GUID
":BridgeOSPanicWatchdogEnabled" ));
1443 if (data
&& (data
->getLength() == sizeof(UInt8
))) {
1444 UInt8
*panicWatchdogEnabled
= (UInt8
*) data
->getBytesNoCopy();
1445 UInt32 debug_flags
= 0;
1446 if (*panicWatchdogEnabled
|| (PE_i_can_has_debugger(&debug_flags
) &&
1447 (debug_flags
& DB_DISABLE_CROSS_PANIC
))) {
1448 coprocessor_cross_panic_enabled
= FALSE
;
1455 #if (DEVELOPMENT || DEBUG)
1456 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
1458 data
= OSDynamicCast( OSData
, entry
->getProperty(nvram_osenvironment
));
1460 sysctl_set_osenvironment(data
->getLength(), data
->getBytesNoCopy());
1461 entry
->removeProperty(nvram_osenvironment
);
1462 IODTNVRAM
* nvramOptionsEntry
= OSDynamicCast(IODTNVRAM
, entry
);
1463 if (nvramOptionsEntry
) {
1464 nvramOptionsEntry
->sync();
1469 sysctl_unblock_osenvironment();
1471 /* on intel the UUID must be published after nvram is available */
1472 publishPlatformUUIDAndSerial();
1474 #endif /* defined(__x86_64__) */
1476 publishResource("IONVRAM");
1480 IOPlatformExpert::callPlatformFunction(const OSSymbol
*functionName
,
1481 bool waitForFunction
,
1482 void *param1
, void *param2
,
1483 void *param3
, void *param4
)
1485 IOService
*service
, *_resources
;
1487 if (functionName
== gIOPlatformQuiesceActionKey
||
1488 functionName
== gIOPlatformActiveActionKey
) {
1490 * Services which register for IOPlatformQuiesceAction / IOPlatformActiveAction
1491 * must consume that event themselves, without passing it up to super/IOPlatformExpert.
1493 if (gEnforceQuiesceSafety
) {
1494 panic("Class %s passed the quiesce/active action to IOPlatformExpert",
1495 getMetaClass()->getClassName());
1499 if (waitForFunction
) {
1500 _resources
= waitForService(resourceMatching(functionName
));
1502 _resources
= getResourceService();
1504 if (_resources
== NULL
) {
1505 return kIOReturnUnsupported
;
1508 service
= OSDynamicCast(IOService
, _resources
->getProperty(functionName
));
1509 if (service
== NULL
) {
1510 return kIOReturnUnsupported
;
1513 return service
->callPlatformFunction(functionName
, waitForFunction
,
1514 param1
, param2
, param3
, param4
);
1518 IOPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1523 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1526 #define super IOPlatformExpert
1528 OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert
, IOPlatformExpert
)
1530 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 0);
1531 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 1);
1532 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 2);
1533 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 3);
1534 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 4);
1535 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 5);
1536 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 6);
1537 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 7);
1539 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1542 IODTPlatformExpert::probe( IOService
* provider
,
1545 if (!super::probe( provider
, score
)) {
1549 // check machine types
1550 if (!provider
->compareNames( getProperty( gIONameMatchKey
))) {
1558 IODTPlatformExpert::configure( IOService
* provider
)
1560 if (!super::configure( provider
)) {
1564 processTopLevel( provider
);
1570 IODTPlatformExpert::createNub( IORegistryEntry
* from
)
1574 nub
= new IOPlatformDevice
;
1576 if (!nub
->init( from
, gIODTPlane
)) {
1585 IODTPlatformExpert::createNubs( IOService
* parent
, OSIterator
* iter
)
1587 IORegistryEntry
* next
;
1592 while ((next
= (IORegistryEntry
*) iter
->getNextObject())) {
1593 if (NULL
== (nub
= createNub( next
))) {
1597 nub
->attach( parent
);
1598 #if !defined(__x86_64__)
1599 OSData
*tmpData
= (OSData
*)next
->getProperty("device_type");
1600 if (tmpData
== NULL
) {
1601 nub
->registerService();
1605 char *device_type
= (char *)tmpData
->getBytesNoCopy();
1606 if (strcmp(device_type
, "cpu") != 0) {
1607 nub
->registerService();
1611 tmpData
= (OSData
*)next
->getProperty("reg");
1612 assert(tmpData
!= NULL
);
1613 assert(tmpData
->getLength() >= sizeof(UInt32
));
1615 uint32_t phys_id
= *(UInt32
*)tmpData
->getBytesNoCopy();
1616 int logical_cpu_id
= ml_get_cpu_number(phys_id
);
1617 int logical_cluster_id
= ml_get_cluster_number(phys_id
);
1620 * If the following condition triggers, it means that a CPU that was present in the DT
1621 * was ignored by XNU at topology parsing time. This can happen currently when using the
1622 * cpus=N boot-arg; for example, cpus=1 will cause XNU to parse and enable a single CPU.
1624 * Note that this condition will not trigger for harvested cores because these do not show up
1625 * in the DT/IORegistry in the first place.
1627 if (logical_cpu_id
< 0) {
1628 nub
->registerService();
1632 __assert_only
bool logical_id_added_to_ioreg
= nub
->setProperty("logical-cpu-id", logical_cpu_id
, 32U);
1633 assert(logical_id_added_to_ioreg
== true);
1634 logical_id_added_to_ioreg
= nub
->setProperty("logical-cluster-id", logical_cluster_id
, 32U);
1635 assert(logical_id_added_to_ioreg
== true);
1637 nub
->registerService();
1646 IODTPlatformExpert::processTopLevel( IORegistryEntry
* rootEntry
)
1649 IORegistryEntry
* next
;
1650 IORegistryEntry
* cpus
;
1653 kids
= IODTFindMatchingEntries( rootEntry
, 0, deleteList());
1655 while ((next
= (IORegistryEntry
*)kids
->getNextObject())) {
1656 next
->detachAll( gIODTPlane
);
1662 assert(gIOOptionsEntry
!= NULL
); // subclasses that do their own NVRAM initialization shouldn't be calling this
1663 dtNVRAM
= gIOOptionsEntry
;
1665 // Publish the cpus.
1666 cpus
= rootEntry
->childFromPath( "cpus", gIODTPlane
);
1668 createNubs( this, IODTFindMatchingEntries( cpus
, kIODTExclusive
, NULL
));
1672 // publish top level, minus excludeList
1673 createNubs( this, IODTFindMatchingEntries( rootEntry
, kIODTExclusive
, excludeList()));
1677 IODTPlatformExpert::getNubResources( IOService
* nub
)
1679 if (nub
->getDeviceMemory()) {
1680 return kIOReturnSuccess
;
1683 IODTResolveAddressing( nub
, "reg", NULL
);
1685 return kIOReturnSuccess
;
1689 IODTPlatformExpert::compareNubName( const IOService
* nub
,
1690 OSString
* name
, OSString
** matched
) const
1692 return IODTCompareNubName( nub
, name
, matched
)
1693 || super::compareNubName( nub
, name
, matched
);
1698 * Do not use this method directly, it returns inconsistent results
1699 * across architectures and is considered deprecated.
1701 * Use getTargetName and getProductName respectively. For example:
1703 * targetName: J137AP
1704 * productName: iMacPro1,1
1706 * targetName: D331pAP
1707 * productName: iPhone11,6
1711 IODTPlatformExpert::getModelName( char * name
, int maxLength
)
1721 prop
= (OSData
*) getProvider()->getProperty( gIODTCompatibleKey
);
1723 str
= (const char *) prop
->getBytesNoCopy();
1725 if (0 == strncmp( str
, "AAPL,", strlen( "AAPL," ))) {
1726 str
+= strlen( "AAPL," );
1730 while ((c
= *str
++)) {
1731 if ((c
== '/') || (c
== ' ')) {
1736 if (len
>= maxLength
) {
1748 * Do not use this method directly, it returns inconsistent results
1749 * across architectures and is considered deprecated.
1751 * Use getTargetName and getProductName respectively. For example:
1753 * targetName: J137AP
1754 * productName: iMacPro1,1
1756 * targetName: D331pAP
1757 * productName: iPhone11,6
1761 IODTPlatformExpert::getMachineName( char * name
, int maxLength
)
1767 prop
= (OSData
*) getProvider()->getProperty( gIODTModelKey
);
1768 ok
= (NULL
!= prop
);
1771 strlcpy( name
, (const char *) prop
->getBytesNoCopy(), maxLength
);
1777 /* Examples: J137AP, D331pAP... */
1780 IODTPlatformExpert::getTargetName( char * name
, int maxLength
)
1785 const OSSymbol
* key
= gIODTBridgeModelKey
;
1788 prop
= (OSData
*) getProvider()->getProperty( key
);
1791 // This happens if there is no bridge.
1792 char const * const unknown
= "";
1794 strlcpy( name
, unknown
, maxLength
);
1796 strlcpy( name
, (const char *)prop
->getBytesNoCopy(), maxLength
);
1801 return getModelName( name
, maxLength
);
1805 /* Examples: iMacPro1,1, iPhone11,6... */
1808 IODTPlatformExpert::getProductName( char * name
, int maxLength
)
1811 return getModelName( name
, maxLength
);
1813 return getMachineName( name
, maxLength
);
1817 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1820 IODTPlatformExpert::registerNVRAMController( IONVRAMController
* nvram
)
1823 dtNVRAM
->registerNVRAMController(nvram
);
1826 super::registerNVRAMController(nvram
);
1830 IODTPlatformExpert::haltRestart(unsigned int type
)
1836 return super::haltRestart(type
);
1840 IODTPlatformExpert::readXPRAM(IOByteCount offset
, UInt8
* buffer
,
1844 return dtNVRAM
->readXPRAM(offset
, buffer
, length
);
1846 return kIOReturnNotReady
;
1851 IODTPlatformExpert::writeXPRAM(IOByteCount offset
, UInt8
* buffer
,
1855 return dtNVRAM
->writeXPRAM(offset
, buffer
, length
);
1857 return kIOReturnNotReady
;
1862 IODTPlatformExpert::readNVRAMProperty(
1863 IORegistryEntry
* entry
,
1864 const OSSymbol
** name
, OSData
** value
)
1867 return dtNVRAM
->readNVRAMProperty(entry
, name
, value
);
1869 return kIOReturnNotReady
;
1874 IODTPlatformExpert::readNVRAMProperty(
1875 IORegistryEntry
* entry
,
1876 OSSharedPtr
<const OSSymbol
>& name
, OSSharedPtr
<OSData
>& value
)
1878 const OSSymbol
* nameRaw
= NULL
;
1879 OSData
* valueRaw
= NULL
;
1881 IOReturn result
= readNVRAMProperty(entry
, &nameRaw
, &valueRaw
);
1883 name
.reset(nameRaw
, OSNoRetain
);
1884 value
.reset(valueRaw
, OSNoRetain
);
1890 IODTPlatformExpert::writeNVRAMProperty(
1891 IORegistryEntry
* entry
,
1892 const OSSymbol
* name
, OSData
* value
)
1895 return dtNVRAM
->writeNVRAMProperty(entry
, name
, value
);
1897 return kIOReturnNotReady
;
1902 IODTPlatformExpert::getNVRAMPartitions(void)
1905 return dtNVRAM
->getNVRAMPartitions();
1912 IODTPlatformExpert::readNVRAMPartition(const OSSymbol
* partitionID
,
1913 IOByteCount offset
, UInt8
* buffer
,
1917 return dtNVRAM
->readNVRAMPartition(partitionID
, offset
,
1920 return kIOReturnNotReady
;
1925 IODTPlatformExpert::writeNVRAMPartition(const OSSymbol
* partitionID
,
1926 IOByteCount offset
, UInt8
* buffer
,
1930 return dtNVRAM
->writeNVRAMPartition(partitionID
, offset
,
1933 return kIOReturnNotReady
;
1938 IODTPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1940 IOByteCount lengthSaved
= 0;
1943 lengthSaved
= dtNVRAM
->savePanicInfo(buffer
, length
);
1946 if (lengthSaved
== 0) {
1947 lengthSaved
= super::savePanicInfo(buffer
, length
);
1954 IODTPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
)
1956 UInt8
* serialNumber
;
1957 unsigned int serialNumberSize
;
1958 unsigned short pos
= 0;
1962 if (myProperty
!= NULL
) {
1963 serialNumberSize
= myProperty
->getLength();
1964 serialNumber
= (UInt8
*)(myProperty
->getBytesNoCopy());
1965 temp
= (char*)serialNumber
;
1966 if (serialNumberSize
> 0) {
1967 // check to see if this is a CTO serial number...
1968 while (pos
< serialNumberSize
&& temp
[pos
] != '-') {
1972 if (pos
< serialNumberSize
) { // there was a hyphen, so it's a CTO serial number
1973 memcpy(SerialNo
, serialNumber
+ 12, 8);
1974 memcpy(&SerialNo
[8], serialNumber
, 3);
1976 memcpy(&SerialNo
[12], serialNumber
+ 3, 8);
1978 } else { // just a normal serial number
1979 memcpy(SerialNo
, serialNumber
+ 13, 8);
1980 memcpy(&SerialNo
[8], serialNumber
, 3);
1983 return OSString::withCString(SerialNo
);
1990 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1993 #define super IOService
1995 OSDefineMetaClassAndStructors(IOPlatformExpertDevice
, IOService
)
1997 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 0);
1998 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 1);
1999 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 2);
2000 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 3);
2002 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005 IOPlatformExpertDevice::compareName( OSString
* name
,
2006 OSString
** matched
) const
2008 return IODTCompareNubName( this, name
, matched
);
2012 IOPlatformExpertDevice::init(void *dtRoot
)
2014 IORegistryEntry
* dt
= NULL
;
2017 if ((dtRoot
!= NULL
) && (dt
= IODeviceTreeAlloc(dtRoot
))) {
2018 ok
= super::init( dt
, gIODTPlane
);
2031 IOPlatformExpertDevice::startIOServiceMatching(void)
2033 workLoop
= IOWorkLoop::workLoop();
2044 IOPlatformExpertDevice::getWorkLoop() const
2050 IOPlatformExpertDevice::setProperties( OSObject
* properties
)
2052 return kIOReturnUnsupported
;
2056 IOPlatformExpertDevice::newUserClient( task_t owningTask
, void * securityID
,
2057 UInt32 type
, OSDictionary
* properties
,
2058 IOUserClient
** handler
)
2060 IOReturn err
= kIOReturnSuccess
;
2061 IOUserClient
* newConnect
= NULL
;
2062 IOUserClient
* theConnect
= NULL
;
2065 case kIOKitDiagnosticsClientType
:
2066 newConnect
= IOKitDiagnosticsClient::withTask(owningTask
);
2068 err
= kIOReturnNotPermitted
;
2071 case kIOKitUserServerClientType
:
2072 newConnect
= IOUserServer::withTask(owningTask
);
2074 err
= kIOReturnNotPermitted
;
2078 err
= kIOReturnBadArgument
;
2082 if ((false == newConnect
->attach(this))
2083 || (false == newConnect
->start(this))) {
2084 newConnect
->detach( this );
2085 newConnect
->release();
2086 err
= kIOReturnNotPermitted
;
2088 theConnect
= newConnect
;
2092 *handler
= theConnect
;
2097 IOPlatformExpertDevice::free()
2100 workLoop
->release();
2105 IOPlatformExpertDevice::configureDefaults( void )
2108 // Parse the serial-number data and publish a user-readable string
2109 OSData
* mydata
= (OSData
*) (getProperty("serial-number"));
2110 if (mydata
!= NULL
) {
2111 OSString
*serNoString
= OSString::withCString((const char *)mydata
->getBytesNoCopy());
2112 if (serNoString
!= NULL
) {
2113 setProperty(kIOPlatformSerialNumberKey
, serNoString
);
2114 serNoString
->release();
2117 generatePlatformUUID();
2121 IOPlatformExpertDevice::createNVRAM( void )
2124 * Publish an IODTNVRAM class on /options, if present.
2125 * DT-based platforms may need NVRAM access prior to the start
2126 * of IOKit matching, to support security-related operations
2127 * that must happen before machine_lockdown().
2129 IORegistryEntry
*options
= IORegistryEntry::fromPath("/options", gIODTPlane
);
2130 if (options
== NULL
) {
2131 return; // /options may not be present
2134 assert(gIOOptionsEntry
== NULL
);
2135 gIOOptionsEntry
= new IODTNVRAM
;
2137 assert(gIOOptionsEntry
!= NULL
);
2139 gIOOptionsEntry
->init(options
, gIODTPlane
);
2141 gIOOptionsEntry
->attach(this);
2146 IOPlatformExpertDevice::generatePlatformUUID( void )
2148 IORegistryEntry
* entry
;
2149 OSString
* string
= NULL
;
2152 #if !defined(__x86_64__)
2153 entry
= IORegistryEntry::fromPath( "/chosen", gIODTPlane
);
2157 data1
= OSDynamicCast( OSData
, entry
->getProperty( "unique-chip-id" ));
2158 if (data1
&& data1
->getLength() == 8) {
2161 data2
= OSDynamicCast( OSData
, entry
->getProperty( "chip-id" ));
2162 if (data2
&& data2
->getLength() == 4) {
2164 uint8_t digest
[SHA_DIGEST_LENGTH
];
2165 const uuid_t space
= { 0xA6, 0xDD, 0x4C, 0xCB, 0xB5, 0xE8, 0x4A, 0xF5, 0xAC, 0xDD, 0xB6, 0xDC, 0x6A, 0x05, 0x42, 0xB8 };
2167 SHA1Init( &context
);
2168 SHA1Update( &context
, space
, sizeof(space
));
2169 SHA1Update( &context
, data1
->getBytesNoCopy(), data1
->getLength());
2170 SHA1Update( &context
, data2
->getBytesNoCopy(), data2
->getLength());
2171 SHA1Final( digest
, &context
);
2173 digest
[6] = (digest
[6] & 0x0F) | 0x50;
2174 digest
[8] = (digest
[8] & 0x3F) | 0x80;
2176 uuid_unparse( digest
, uuid
);
2177 string
= OSString::withCString( uuid
);
2183 #else /* !defined(__x86_64__) */
2186 entry
= IORegistryEntry::fromPath( "/efi/platform", gIODTPlane
);
2188 data
= OSDynamicCast( OSData
, entry
->getProperty( "system-id" ));
2189 if (data
&& data
->getLength() == 16) {
2191 uint8_t digest
[SHA_DIGEST_LENGTH
];
2192 const uuid_t space
= { 0x2A, 0x06, 0x19, 0x90, 0xD3, 0x8D, 0x44, 0x40, 0xA1, 0x39, 0xC4, 0x97, 0x70, 0x37, 0x65, 0xAC };
2194 SHA1Init( &context
);
2195 SHA1Update( &context
, space
, sizeof(space
));
2196 SHA1Update( &context
, data
->getBytesNoCopy(), data
->getLength());
2197 SHA1Final( digest
, &context
);
2199 digest
[6] = (digest
[6] & 0x0F) | 0x50;
2200 digest
[8] = (digest
[8] & 0x3F) | 0x80;
2202 uuid_unparse( digest
, uuid
);
2203 string
= OSString::withCString( uuid
);
2209 /* vmware still runs this path */
2210 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
2212 data
= OSDynamicCast( OSData
, entry
->getProperty( "platform-uuid" ));
2213 if (data
&& data
->getLength() == sizeof(uuid_t
)) {
2214 uuid_unparse((uint8_t *) data
->getBytesNoCopy(), uuid
);
2215 string
= OSString::withCString( uuid
);
2220 #endif /* defined(__x86_64__) */
2223 setProperty( kIOPlatformUUIDKey
, string
);
2224 gIOPlatformUUIDAndSerialDone
= true;
2229 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2232 #define super IOService
2234 OSDefineMetaClassAndStructors(IOPlatformDevice
, IOService
)
2236 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 0);
2237 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 1);
2238 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 2);
2239 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 3);
2241 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2244 IOPlatformDevice::compareName( OSString
* name
,
2245 OSString
** matched
) const
2247 return ((IOPlatformExpert
*)getProvider())->
2248 compareNubName( this, name
, matched
);
2252 IOPlatformDevice::matchLocation( IOService
* /* client */ )
2258 IOPlatformDevice::getResources( void )
2260 return ((IOPlatformExpert
*)getProvider())->getNubResources( this );
2263 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2265 /*********************************************************************
2266 * IOPanicPlatform class
2268 * If no legitimate IOPlatformDevice matches, this one does and panics
2269 * the kernel with a suitable message.
2270 *********************************************************************/
2272 class IOPanicPlatform
: IOPlatformExpert
{
2273 OSDeclareDefaultStructors(IOPanicPlatform
);
2276 bool start(IOService
* provider
) APPLE_KEXT_OVERRIDE
;
2280 OSDefineMetaClassAndStructors(IOPanicPlatform
, IOPlatformExpert
);
2284 IOPanicPlatform::start(IOService
* provider
)
2286 const char * platform_name
= "(unknown platform name)";
2289 platform_name
= provider
->getName();
2292 panic("Unable to find driver for this platform: \"%s\".\n",