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
);
1087 skip_to_haltRestart
:
1089 return gIOPlatform
->haltRestart(type
);
1096 PEHaltRestart(unsigned int type
)
1098 return PEHaltRestartInternal(type
, 0);
1102 PESavePanicInfo(UInt8
*buffer
, UInt32 length
)
1104 if (gIOPlatform
!= NULL
) {
1105 return (UInt32
) gIOPlatform
->savePanicInfo(buffer
, length
);
1112 PESavePanicInfoAction(void *buffer
, UInt32 offset
, UInt32 length
)
1114 IOCPURunPlatformPanicSyncAction(buffer
, offset
, length
);
1120 * Depending on the platform, the /options node may not be created
1121 * until after IOKit matching has started, by an externally-supplied
1122 * platform expert subclass. Therefore, we must check for its presence
1123 * here and update gIOOptionsEntry for the platform code as necessary.
1126 init_gIOOptionsEntry(void)
1128 IORegistryEntry
*entry
;
1130 volatile void **options
;
1133 if (gIOOptionsEntry
) {
1137 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
1142 nvram_entry
= (void *) OSDynamicCast(IODTNVRAM
, entry
);
1147 options
= (volatile void **) &gIOOptionsEntry
;
1148 if (!OSCompareAndSwapPtr(NULL
, nvram_entry
, options
)) {
1160 /* pass in a NULL value if you just want to figure out the len */
1162 PEReadNVRAMProperty(const char *symbol
, void *value
,
1169 if (!symbol
|| !len
) {
1173 if (init_gIOOptionsEntry() < 0) {
1180 obj
= gIOOptionsEntry
->getProperty(symbol
);
1185 /* convert to data */
1186 data
= OSDynamicCast(OSData
, obj
);
1191 *len
= data
->getLength();
1192 vlen
= min(vlen
, *len
);
1193 if (value
&& vlen
) {
1194 memcpy((void *) value
, data
->getBytesNoCopy(), vlen
);
1204 PEWriteNVRAMBooleanProperty(const char *symbol
, boolean_t value
)
1206 const OSSymbol
*sym
= NULL
;
1207 OSBoolean
*data
= NULL
;
1210 if (symbol
== NULL
) {
1214 if (init_gIOOptionsEntry() < 0) {
1218 if ((sym
= OSSymbol::withCStringNoCopy(symbol
)) == NULL
) {
1222 data
= value
? kOSBooleanTrue
: kOSBooleanFalse
;
1223 ret
= gIOOptionsEntry
->setProperty(sym
, data
);
1227 /* success, force the NVRAM to flush writes */
1229 gIOOptionsEntry
->sync();
1237 PEWriteNVRAMPropertyInternal(const char *symbol
, boolean_t copySymbol
, const void *value
,
1238 const unsigned int len
)
1240 const OSSymbol
*sym
;
1244 if (!symbol
|| !value
|| !len
) {
1248 if (init_gIOOptionsEntry() < 0) {
1252 if (copySymbol
== TRUE
) {
1253 sym
= OSSymbol::withCString(symbol
);
1255 sym
= OSSymbol::withCStringNoCopy(symbol
);
1262 data
= OSData::withBytes((void *) value
, len
);
1267 ret
= gIOOptionsEntry
->setProperty(sym
, data
);
1274 gIOOptionsEntry
->sync();
1283 PEWriteNVRAMProperty(const char *symbol
, const void *value
,
1284 const unsigned int len
)
1286 return PEWriteNVRAMPropertyInternal(symbol
, FALSE
, value
, len
);
1290 PEWriteNVRAMPropertyWithCopy(const char *symbol
, const void *value
,
1291 const unsigned int len
)
1293 return PEWriteNVRAMPropertyInternal(symbol
, TRUE
, value
, len
);
1297 PERemoveNVRAMProperty(const char *symbol
)
1299 const OSSymbol
*sym
;
1305 if (init_gIOOptionsEntry() < 0) {
1309 sym
= OSSymbol::withCStringNoCopy(symbol
);
1314 gIOOptionsEntry
->removeProperty(sym
);
1318 gIOOptionsEntry
->sync();
1326 PEGetGMTTimeOfDay(void)
1331 PEGetUTCTimeOfDay(&secs
, &usecs
);
1336 PESetGMTTimeOfDay(long secs
)
1338 PESetUTCTimeOfDay(secs
, 0);
1342 PEGetUTCTimeOfDay(clock_sec_t
* secs
, clock_usec_t
* usecs
)
1344 clock_nsec_t nsecs
= 0;
1348 gIOPlatform
->getUTCTimeOfDay(secs
, &nsecs
);
1351 assert(nsecs
< NSEC_PER_SEC
);
1352 *usecs
= nsecs
/ NSEC_PER_USEC
;
1356 PESetUTCTimeOfDay(clock_sec_t secs
, clock_usec_t usecs
)
1358 assert(usecs
< USEC_PER_SEC
);
1360 gIOPlatform
->setUTCTimeOfDay(secs
, usecs
* NSEC_PER_USEC
);
1365 PEGetCoprocessorVersion( void )
1367 coprocessor_type_t coprocessor_version
= kCoprocessorVersionNone
;
1368 #if defined(__x86_64__)
1369 IORegistryEntry
*platform_entry
= NULL
;
1370 OSData
*coprocessor_version_obj
= NULL
;
1372 platform_entry
= IORegistryEntry::fromPath(kIODeviceTreePlane
":/efi/platform");
1373 if (platform_entry
!= NULL
) {
1374 coprocessor_version_obj
= OSDynamicCast(OSData
, platform_entry
->getProperty("apple-coprocessor-version"));
1375 if ((coprocessor_version_obj
!= NULL
) && (coprocessor_version_obj
->getLength() <= sizeof(uint64_t))) {
1376 memcpy(&coprocessor_version
, coprocessor_version_obj
->getBytesNoCopy(), coprocessor_version_obj
->getLength());
1378 platform_entry
->release();
1381 return coprocessor_version
;
1385 bool gIOPlatformUUIDAndSerialDone
= false;
1388 IOPlatformExpert::publishPlatformUUIDAndSerial( void )
1390 if (!gIOPlatformUUIDAndSerialDone
) {
1391 // Parse the serial-number data and publish a user-readable string
1392 if (NULL
== getProvider()->getProperty(kIOPlatformSerialNumberKey
)) {
1393 OSData
* mydata
= (OSData
*) (getProvider()->getProperty("serial-number"));
1394 if (mydata
!= NULL
) {
1395 OSString
*serNoString
= createSystemSerialNumberString(mydata
);
1396 if (serNoString
!= NULL
) {
1397 getProvider()->setProperty(kIOPlatformSerialNumberKey
, serNoString
);
1398 serNoString
->release();
1402 IOPlatformExpertDevice
*provider
= OSDynamicCast(IOPlatformExpertDevice
, getProvider());
1403 assert(provider
!= NULL
);
1404 provider
->generatePlatformUUID();
1407 if (gIOPlatformUUIDAndSerialDone
) {
1408 publishResource(kIOPlatformUUIDKey
, getProvider()->getProperty(kIOPlatformUUIDKey
));
1413 IOPlatformExpert::publishNVRAM( void )
1415 if (init_gIOOptionsEntry() < 0) {
1416 IOPlatformExpertDevice
*provider
= OSDynamicCast(IOPlatformExpertDevice
, getProvider());
1417 assert(provider
!= NULL
);
1418 provider
->createNVRAM();
1420 if (gIOOptionsEntry
!= NULL
) {
1421 gIOOptionsEntry
->registerService();
1426 IOPlatformExpert::registerNVRAMController(IONVRAMController
* caller
)
1428 #if defined(__x86_64__)
1430 IORegistryEntry
* entry
;
1433 * If we have panic debugging enabled and a prod-fused coprocessor,
1434 * disable cross panics so that the co-processor doesn't cause the system
1435 * to reset when we enter the debugger or hit a panic on the x86 side.
1437 if (panicDebugging
) {
1438 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
1440 data
= OSDynamicCast( OSData
, entry
->getProperty( APPLE_VENDOR_VARIABLE_GUID
":BridgeOSPanicWatchdogEnabled" ));
1441 if (data
&& (data
->getLength() == sizeof(UInt8
))) {
1442 UInt8
*panicWatchdogEnabled
= (UInt8
*) data
->getBytesNoCopy();
1443 UInt32 debug_flags
= 0;
1444 if (*panicWatchdogEnabled
|| (PE_i_can_has_debugger(&debug_flags
) &&
1445 (debug_flags
& DB_DISABLE_CROSS_PANIC
))) {
1446 coprocessor_cross_panic_enabled
= FALSE
;
1453 #if (DEVELOPMENT || DEBUG)
1454 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
1456 data
= OSDynamicCast( OSData
, entry
->getProperty(nvram_osenvironment
));
1458 sysctl_set_osenvironment(data
->getLength(), data
->getBytesNoCopy());
1459 entry
->removeProperty(nvram_osenvironment
);
1460 IODTNVRAM
* nvramOptionsEntry
= OSDynamicCast(IODTNVRAM
, entry
);
1461 if (nvramOptionsEntry
) {
1462 nvramOptionsEntry
->sync();
1467 sysctl_unblock_osenvironment();
1469 /* on intel the UUID must be published after nvram is available */
1470 publishPlatformUUIDAndSerial();
1472 #endif /* defined(__x86_64__) */
1474 publishResource("IONVRAM");
1478 IOPlatformExpert::callPlatformFunction(const OSSymbol
*functionName
,
1479 bool waitForFunction
,
1480 void *param1
, void *param2
,
1481 void *param3
, void *param4
)
1483 IOService
*service
, *_resources
;
1485 if (functionName
== gIOPlatformQuiesceActionKey
||
1486 functionName
== gIOPlatformActiveActionKey
) {
1488 * Services which register for IOPlatformQuiesceAction / IOPlatformActiveAction
1489 * must consume that event themselves, without passing it up to super/IOPlatformExpert.
1491 if (gEnforceQuiesceSafety
) {
1492 panic("Class %s passed the quiesce/active action to IOPlatformExpert",
1493 getMetaClass()->getClassName());
1497 if (waitForFunction
) {
1498 _resources
= waitForService(resourceMatching(functionName
));
1500 _resources
= getResourceService();
1502 if (_resources
== NULL
) {
1503 return kIOReturnUnsupported
;
1506 service
= OSDynamicCast(IOService
, _resources
->getProperty(functionName
));
1507 if (service
== NULL
) {
1508 return kIOReturnUnsupported
;
1511 return service
->callPlatformFunction(functionName
, waitForFunction
,
1512 param1
, param2
, param3
, param4
);
1516 IOPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1521 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1524 #define super IOPlatformExpert
1526 OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert
, IOPlatformExpert
)
1528 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 0);
1529 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 1);
1530 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 2);
1531 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 3);
1532 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 4);
1533 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 5);
1534 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 6);
1535 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 7);
1537 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1540 IODTPlatformExpert::probe( IOService
* provider
,
1543 if (!super::probe( provider
, score
)) {
1547 // check machine types
1548 if (!provider
->compareNames( getProperty( gIONameMatchKey
))) {
1556 IODTPlatformExpert::configure( IOService
* provider
)
1558 if (!super::configure( provider
)) {
1562 processTopLevel( provider
);
1568 IODTPlatformExpert::createNub( IORegistryEntry
* from
)
1572 nub
= new IOPlatformDevice
;
1574 if (!nub
->init( from
, gIODTPlane
)) {
1583 IODTPlatformExpert::createNubs( IOService
* parent
, OSIterator
* iter
)
1585 IORegistryEntry
* next
;
1590 while ((next
= (IORegistryEntry
*) iter
->getNextObject())) {
1591 if (NULL
== (nub
= createNub( next
))) {
1595 nub
->attach( parent
);
1596 #if !defined(__x86_64__)
1597 OSData
*tmpData
= (OSData
*)next
->getProperty("device_type");
1598 if (tmpData
== NULL
) {
1599 nub
->registerService();
1603 char *device_type
= (char *)tmpData
->getBytesNoCopy();
1604 if (strcmp(device_type
, "cpu") != 0) {
1605 nub
->registerService();
1609 tmpData
= (OSData
*)next
->getProperty("reg");
1610 assert(tmpData
!= NULL
);
1611 assert(tmpData
->getLength() >= sizeof(UInt32
));
1613 uint32_t phys_id
= *(UInt32
*)tmpData
->getBytesNoCopy();
1614 int logical_cpu_id
= ml_get_cpu_number(phys_id
);
1615 int logical_cluster_id
= ml_get_cluster_number(phys_id
);
1618 * If the following condition triggers, it means that a CPU that was present in the DT
1619 * was ignored by XNU at topology parsing time. This can happen currently when using the
1620 * cpus=N boot-arg; for example, cpus=1 will cause XNU to parse and enable a single CPU.
1622 * Note that this condition will not trigger for harvested cores because these do not show up
1623 * in the DT/IORegistry in the first place.
1625 if (logical_cpu_id
< 0) {
1626 nub
->registerService();
1630 __assert_only
bool logical_id_added_to_ioreg
= nub
->setProperty("logical-cpu-id", logical_cpu_id
, 32U);
1631 assert(logical_id_added_to_ioreg
== true);
1632 logical_id_added_to_ioreg
= nub
->setProperty("logical-cluster-id", logical_cluster_id
, 32U);
1633 assert(logical_id_added_to_ioreg
== true);
1635 nub
->registerService();
1644 IODTPlatformExpert::processTopLevel( IORegistryEntry
* rootEntry
)
1647 IORegistryEntry
* next
;
1648 IORegistryEntry
* cpus
;
1651 kids
= IODTFindMatchingEntries( rootEntry
, 0, deleteList());
1653 while ((next
= (IORegistryEntry
*)kids
->getNextObject())) {
1654 next
->detachAll( gIODTPlane
);
1660 assert(gIOOptionsEntry
!= NULL
); // subclasses that do their own NVRAM initialization shouldn't be calling this
1661 dtNVRAM
= gIOOptionsEntry
;
1663 // Publish the cpus.
1664 cpus
= rootEntry
->childFromPath( "cpus", gIODTPlane
);
1666 createNubs( this, IODTFindMatchingEntries( cpus
, kIODTExclusive
, NULL
));
1670 // publish top level, minus excludeList
1671 createNubs( this, IODTFindMatchingEntries( rootEntry
, kIODTExclusive
, excludeList()));
1675 IODTPlatformExpert::getNubResources( IOService
* nub
)
1677 if (nub
->getDeviceMemory()) {
1678 return kIOReturnSuccess
;
1681 IODTResolveAddressing( nub
, "reg", NULL
);
1683 return kIOReturnSuccess
;
1687 IODTPlatformExpert::compareNubName( const IOService
* nub
,
1688 OSString
* name
, OSString
** matched
) const
1690 return IODTCompareNubName( nub
, name
, matched
)
1691 || super::compareNubName( nub
, name
, matched
);
1696 * Do not use this method directly, it returns inconsistent results
1697 * across architectures and is considered deprecated.
1699 * Use getTargetName and getProductName respectively. For example:
1701 * targetName: J137AP
1702 * productName: iMacPro1,1
1704 * targetName: D331pAP
1705 * productName: iPhone11,6
1709 IODTPlatformExpert::getModelName( char * name
, int maxLength
)
1719 prop
= (OSData
*) getProvider()->getProperty( gIODTCompatibleKey
);
1721 str
= (const char *) prop
->getBytesNoCopy();
1723 if (0 == strncmp( str
, "AAPL,", strlen( "AAPL," ))) {
1724 str
+= strlen( "AAPL," );
1728 while ((c
= *str
++)) {
1729 if ((c
== '/') || (c
== ' ')) {
1734 if (len
>= maxLength
) {
1746 * Do not use this method directly, it returns inconsistent results
1747 * across architectures and is considered deprecated.
1749 * Use getTargetName and getProductName respectively. For example:
1751 * targetName: J137AP
1752 * productName: iMacPro1,1
1754 * targetName: D331pAP
1755 * productName: iPhone11,6
1759 IODTPlatformExpert::getMachineName( char * name
, int maxLength
)
1765 prop
= (OSData
*) getProvider()->getProperty( gIODTModelKey
);
1766 ok
= (NULL
!= prop
);
1769 strlcpy( name
, (const char *) prop
->getBytesNoCopy(), maxLength
);
1775 /* Examples: J137AP, D331pAP... */
1778 IODTPlatformExpert::getTargetName( char * name
, int maxLength
)
1783 const OSSymbol
* key
= gIODTBridgeModelKey
;
1786 prop
= (OSData
*) getProvider()->getProperty( key
);
1789 // This happens if there is no bridge.
1790 char const * const unknown
= "";
1792 strlcpy( name
, unknown
, maxLength
);
1794 strlcpy( name
, (const char *)prop
->getBytesNoCopy(), maxLength
);
1799 return getModelName( name
, maxLength
);
1803 /* Examples: iMacPro1,1, iPhone11,6... */
1806 IODTPlatformExpert::getProductName( char * name
, int maxLength
)
1809 return getModelName( name
, maxLength
);
1811 return getMachineName( name
, maxLength
);
1815 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1818 IODTPlatformExpert::registerNVRAMController( IONVRAMController
* nvram
)
1821 dtNVRAM
->registerNVRAMController(nvram
);
1824 super::registerNVRAMController(nvram
);
1828 IODTPlatformExpert::haltRestart(unsigned int type
)
1834 return super::haltRestart(type
);
1838 IODTPlatformExpert::readXPRAM(IOByteCount offset
, UInt8
* buffer
,
1842 return dtNVRAM
->readXPRAM(offset
, buffer
, length
);
1844 return kIOReturnNotReady
;
1849 IODTPlatformExpert::writeXPRAM(IOByteCount offset
, UInt8
* buffer
,
1853 return dtNVRAM
->writeXPRAM(offset
, buffer
, length
);
1855 return kIOReturnNotReady
;
1860 IODTPlatformExpert::readNVRAMProperty(
1861 IORegistryEntry
* entry
,
1862 const OSSymbol
** name
, OSData
** value
)
1865 return dtNVRAM
->readNVRAMProperty(entry
, name
, value
);
1867 return kIOReturnNotReady
;
1872 IODTPlatformExpert::readNVRAMProperty(
1873 IORegistryEntry
* entry
,
1874 OSSharedPtr
<const OSSymbol
>& name
, OSSharedPtr
<OSData
>& value
)
1876 const OSSymbol
* nameRaw
= NULL
;
1877 OSData
* valueRaw
= NULL
;
1879 IOReturn result
= readNVRAMProperty(entry
, &nameRaw
, &valueRaw
);
1881 name
.reset(nameRaw
, OSNoRetain
);
1882 value
.reset(valueRaw
, OSNoRetain
);
1888 IODTPlatformExpert::writeNVRAMProperty(
1889 IORegistryEntry
* entry
,
1890 const OSSymbol
* name
, OSData
* value
)
1893 return dtNVRAM
->writeNVRAMProperty(entry
, name
, value
);
1895 return kIOReturnNotReady
;
1900 IODTPlatformExpert::getNVRAMPartitions(void)
1903 return dtNVRAM
->getNVRAMPartitions();
1910 IODTPlatformExpert::readNVRAMPartition(const OSSymbol
* partitionID
,
1911 IOByteCount offset
, UInt8
* buffer
,
1915 return dtNVRAM
->readNVRAMPartition(partitionID
, offset
,
1918 return kIOReturnNotReady
;
1923 IODTPlatformExpert::writeNVRAMPartition(const OSSymbol
* partitionID
,
1924 IOByteCount offset
, UInt8
* buffer
,
1928 return dtNVRAM
->writeNVRAMPartition(partitionID
, offset
,
1931 return kIOReturnNotReady
;
1936 IODTPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1938 IOByteCount lengthSaved
= 0;
1941 lengthSaved
= dtNVRAM
->savePanicInfo(buffer
, length
);
1944 if (lengthSaved
== 0) {
1945 lengthSaved
= super::savePanicInfo(buffer
, length
);
1952 IODTPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
)
1954 UInt8
* serialNumber
;
1955 unsigned int serialNumberSize
;
1956 unsigned short pos
= 0;
1960 if (myProperty
!= NULL
) {
1961 serialNumberSize
= myProperty
->getLength();
1962 serialNumber
= (UInt8
*)(myProperty
->getBytesNoCopy());
1963 temp
= (char*)serialNumber
;
1964 if (serialNumberSize
> 0) {
1965 // check to see if this is a CTO serial number...
1966 while (pos
< serialNumberSize
&& temp
[pos
] != '-') {
1970 if (pos
< serialNumberSize
) { // there was a hyphen, so it's a CTO serial number
1971 memcpy(SerialNo
, serialNumber
+ 12, 8);
1972 memcpy(&SerialNo
[8], serialNumber
, 3);
1974 memcpy(&SerialNo
[12], serialNumber
+ 3, 8);
1976 } else { // just a normal serial number
1977 memcpy(SerialNo
, serialNumber
+ 13, 8);
1978 memcpy(&SerialNo
[8], serialNumber
, 3);
1981 return OSString::withCString(SerialNo
);
1988 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1991 #define super IOService
1993 OSDefineMetaClassAndStructors(IOPlatformExpertDevice
, IOService
)
1995 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 0);
1996 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 1);
1997 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 2);
1998 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 3);
2000 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003 IOPlatformExpertDevice::compareName( OSString
* name
,
2004 OSString
** matched
) const
2006 return IODTCompareNubName( this, name
, matched
);
2010 IOPlatformExpertDevice::init(void *dtRoot
)
2012 IORegistryEntry
* dt
= NULL
;
2015 if ((dtRoot
!= NULL
) && (dt
= IODeviceTreeAlloc(dtRoot
))) {
2016 ok
= super::init( dt
, gIODTPlane
);
2029 IOPlatformExpertDevice::startIOServiceMatching(void)
2031 workLoop
= IOWorkLoop::workLoop();
2042 IOPlatformExpertDevice::getWorkLoop() const
2048 IOPlatformExpertDevice::setProperties( OSObject
* properties
)
2050 return kIOReturnUnsupported
;
2054 IOPlatformExpertDevice::newUserClient( task_t owningTask
, void * securityID
,
2055 UInt32 type
, OSDictionary
* properties
,
2056 IOUserClient
** handler
)
2058 IOReturn err
= kIOReturnSuccess
;
2059 IOUserClient
* newConnect
= NULL
;
2060 IOUserClient
* theConnect
= NULL
;
2063 case kIOKitDiagnosticsClientType
:
2064 newConnect
= IOKitDiagnosticsClient::withTask(owningTask
);
2066 err
= kIOReturnNotPermitted
;
2069 case kIOKitUserServerClientType
:
2070 newConnect
= IOUserServer::withTask(owningTask
);
2072 err
= kIOReturnNotPermitted
;
2076 err
= kIOReturnBadArgument
;
2080 if ((false == newConnect
->attach(this))
2081 || (false == newConnect
->start(this))) {
2082 newConnect
->detach( this );
2083 newConnect
->release();
2084 err
= kIOReturnNotPermitted
;
2086 theConnect
= newConnect
;
2090 *handler
= theConnect
;
2095 IOPlatformExpertDevice::free()
2098 workLoop
->release();
2103 IOPlatformExpertDevice::configureDefaults( void )
2106 // Parse the serial-number data and publish a user-readable string
2107 OSData
* mydata
= (OSData
*) (getProperty("serial-number"));
2108 if (mydata
!= NULL
) {
2109 OSString
*serNoString
= OSString::withCString((const char *)mydata
->getBytesNoCopy());
2110 if (serNoString
!= NULL
) {
2111 setProperty(kIOPlatformSerialNumberKey
, serNoString
);
2112 serNoString
->release();
2115 generatePlatformUUID();
2119 IOPlatformExpertDevice::createNVRAM( void )
2122 * Publish an IODTNVRAM class on /options, if present.
2123 * DT-based platforms may need NVRAM access prior to the start
2124 * of IOKit matching, to support security-related operations
2125 * that must happen before machine_lockdown().
2127 IORegistryEntry
*options
= IORegistryEntry::fromPath("/options", gIODTPlane
);
2128 if (options
== NULL
) {
2129 return; // /options may not be present
2132 assert(gIOOptionsEntry
== NULL
);
2133 gIOOptionsEntry
= new IODTNVRAM
;
2135 assert(gIOOptionsEntry
!= NULL
);
2137 gIOOptionsEntry
->init(options
, gIODTPlane
);
2139 gIOOptionsEntry
->attach(this);
2144 IOPlatformExpertDevice::generatePlatformUUID( void )
2146 IORegistryEntry
* entry
;
2147 OSString
* string
= NULL
;
2150 #if !defined(__x86_64__)
2151 entry
= IORegistryEntry::fromPath( "/chosen", gIODTPlane
);
2155 data1
= OSDynamicCast( OSData
, entry
->getProperty( "unique-chip-id" ));
2156 if (data1
&& data1
->getLength() == 8) {
2159 data2
= OSDynamicCast( OSData
, entry
->getProperty( "chip-id" ));
2160 if (data2
&& data2
->getLength() == 4) {
2162 uint8_t digest
[SHA_DIGEST_LENGTH
];
2163 const uuid_t space
= { 0xA6, 0xDD, 0x4C, 0xCB, 0xB5, 0xE8, 0x4A, 0xF5, 0xAC, 0xDD, 0xB6, 0xDC, 0x6A, 0x05, 0x42, 0xB8 };
2165 SHA1Init( &context
);
2166 SHA1Update( &context
, space
, sizeof(space
));
2167 SHA1Update( &context
, data1
->getBytesNoCopy(), data1
->getLength());
2168 SHA1Update( &context
, data2
->getBytesNoCopy(), data2
->getLength());
2169 SHA1Final( digest
, &context
);
2171 digest
[6] = (digest
[6] & 0x0F) | 0x50;
2172 digest
[8] = (digest
[8] & 0x3F) | 0x80;
2174 uuid_unparse( digest
, uuid
);
2175 string
= OSString::withCString( uuid
);
2181 #else /* !defined(__x86_64__) */
2184 entry
= IORegistryEntry::fromPath( "/efi/platform", gIODTPlane
);
2186 data
= OSDynamicCast( OSData
, entry
->getProperty( "system-id" ));
2187 if (data
&& data
->getLength() == 16) {
2189 uint8_t digest
[SHA_DIGEST_LENGTH
];
2190 const uuid_t space
= { 0x2A, 0x06, 0x19, 0x90, 0xD3, 0x8D, 0x44, 0x40, 0xA1, 0x39, 0xC4, 0x97, 0x70, 0x37, 0x65, 0xAC };
2192 SHA1Init( &context
);
2193 SHA1Update( &context
, space
, sizeof(space
));
2194 SHA1Update( &context
, data
->getBytesNoCopy(), data
->getLength());
2195 SHA1Final( digest
, &context
);
2197 digest
[6] = (digest
[6] & 0x0F) | 0x50;
2198 digest
[8] = (digest
[8] & 0x3F) | 0x80;
2200 uuid_unparse( digest
, uuid
);
2201 string
= OSString::withCString( uuid
);
2207 /* vmware still runs this path */
2208 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
2210 data
= OSDynamicCast( OSData
, entry
->getProperty( "platform-uuid" ));
2211 if (data
&& data
->getLength() == sizeof(uuid_t
)) {
2212 uuid_unparse((uint8_t *) data
->getBytesNoCopy(), uuid
);
2213 string
= OSString::withCString( uuid
);
2218 #endif /* defined(__x86_64__) */
2221 setProperty( kIOPlatformUUIDKey
, string
);
2222 gIOPlatformUUIDAndSerialDone
= true;
2227 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2230 #define super IOService
2232 OSDefineMetaClassAndStructors(IOPlatformDevice
, IOService
)
2234 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 0);
2235 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 1);
2236 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 2);
2237 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 3);
2239 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2242 IOPlatformDevice::compareName( OSString
* name
,
2243 OSString
** matched
) const
2245 return ((IOPlatformExpert
*)getProvider())->
2246 compareNubName( this, name
, matched
);
2250 IOPlatformDevice::matchLocation( IOService
* /* client */ )
2256 IOPlatformDevice::getResources( void )
2258 return ((IOPlatformExpert
*)getProvider())->getNubResources( this );
2261 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2263 /*********************************************************************
2264 * IOPanicPlatform class
2266 * If no legitimate IOPlatformDevice matches, this one does and panics
2267 * the kernel with a suitable message.
2268 *********************************************************************/
2270 class IOPanicPlatform
: IOPlatformExpert
{
2271 OSDeclareDefaultStructors(IOPanicPlatform
);
2274 bool start(IOService
* provider
) APPLE_KEXT_OVERRIDE
;
2278 OSDefineMetaClassAndStructors(IOPanicPlatform
, IOPlatformExpert
);
2282 IOPanicPlatform::start(IOService
* provider
)
2284 const char * platform_name
= "(unknown platform name)";
2287 platform_name
= provider
->getName();
2290 panic("Unable to find driver for this platform: \"%s\".\n",