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/IODeviceTreeSupport.h>
31 #include <IOKit/IOKitDebug.h>
32 #include <IOKit/IOMapper.h>
33 #include <IOKit/IOMessage.h>
34 #include <IOKit/IONVRAM.h>
35 #include <IOKit/IOPlatformExpert.h>
36 #include <IOKit/IORangeAllocator.h>
37 #include <IOKit/IOWorkLoop.h>
38 #include <IOKit/pwr_mgt/RootDomain.h>
39 #include <IOKit/IOKitKeys.h>
40 #include <IOKit/IOTimeStamp.h>
41 #include <IOKit/IOUserClient.h>
42 #include <IOKit/IOKitDiagnosticsUserClient.h>
44 #include <IOKit/system.h>
47 #include <libkern/c++/OSContainers.h>
48 #include <libkern/crypto/sha1.h>
49 #include <libkern/OSAtomic.h>
52 #include <machine/machine_routines.h>
53 #include <pexpert/pexpert.h>
54 #include <uuid/uuid.h>
57 #define kShutdownTimeout 30 //in secs
61 boolean_t coprocessor_cross_panic_enabled
= TRUE
;
62 #define APPLE_SECURE_BOOT_VARIABLE_GUID "94b73556-2197-4702-82a8-3e1337dafbfb"
63 #endif /* !CONFIG_EMBEDDED */
65 void printDictionaryKeys(OSDictionary
* inDictionary
, char * inMsg
);
66 static void getCStringForObject(OSObject
*inObj
, char *outStr
, size_t outStrLen
);
68 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
70 #define super IOService
72 OSDefineMetaClassAndStructors(IOPlatformExpert
, IOService
)
74 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 0);
75 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 1);
76 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 2);
77 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 3);
78 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 4);
80 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 5);
81 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 6);
82 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 7);
83 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 8);
84 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 9);
85 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 10);
86 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 11);
88 static IOPlatformExpert
* gIOPlatform
;
89 static OSDictionary
* gIOInterruptControllers
;
90 static IOLock
* gIOInterruptControllersLock
;
91 static IODTNVRAM
*gIOOptionsEntry
;
93 OSSymbol
* gPlatformInterruptControllerName
;
95 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
98 IOPlatformExpert::attach( IOService
* provider
)
100 if (!super::attach( provider
)) {
108 IOPlatformExpert::start( IOService
* provider
)
110 IORangeAllocator
* physicalRanges
;
111 OSData
* busFrequency
;
115 if (!super::start(provider
)) {
119 // Override the mapper present flag is requested by boot arguments, if SIP disabled.
121 if (csr_check(CSR_ALLOW_UNRESTRICTED_FS
) == 0)
122 #endif /* CONFIG_CSR */
124 if (PE_parse_boot_argn("dart", &debugFlags
, sizeof(debugFlags
)) && (debugFlags
== 0)) {
125 removeProperty(kIOPlatformMapperPresentKey
);
127 #if DEBUG || DEVELOPMENT
128 if (PE_parse_boot_argn("-x", &debugFlags
, sizeof(debugFlags
))) {
129 removeProperty(kIOPlatformMapperPresentKey
);
131 #endif /* DEBUG || DEVELOPMENT */
134 // Register the presence or lack thereof a system
135 // PCI address mapper with the IOMapper class
136 IOMapper::setMapperRequired(0 != getProperty(kIOPlatformMapperPresentKey
));
138 gIOInterruptControllers
= OSDictionary::withCapacity(1);
139 gIOInterruptControllersLock
= IOLockAlloc();
141 // Correct the bus frequency in the device tree.
142 busFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.bus_clock_rate_hz
, 4);
143 provider
->setProperty("clock-frequency", busFrequency
);
144 busFrequency
->release();
146 gPlatformInterruptControllerName
= (OSSymbol
*)OSSymbol::withCStringNoCopy("IOPlatformInterruptController");
148 physicalRanges
= IORangeAllocator::withRange(0xffffffff, 1, 16,
149 IORangeAllocator::kLocking
);
150 assert(physicalRanges
);
151 setProperty("Platform Memory Ranges", physicalRanges
);
156 PMInstantiatePowerDomains();
158 // Parse the serial-number data and publish a user-readable string
159 OSData
* mydata
= (OSData
*) (provider
->getProperty("serial-number"));
160 if (mydata
!= NULL
) {
161 OSString
*serNoString
= createSystemSerialNumberString(mydata
);
162 if (serNoString
!= NULL
) {
163 provider
->setProperty(kIOPlatformSerialNumberKey
, serNoString
);
164 serNoString
->release();
169 if (PEGetCoprocessorVersion() >= kCoprocessorVersion2
) {
170 coprocessor_paniclog_flush
= TRUE
;
171 extended_debug_log_init();
175 return configure(provider
);
179 IOPlatformExpert::configure( IOService
* provider
)
185 topLevel
= OSDynamicCast( OSSet
, getProperty("top-level"));
188 while ((dict
= OSDynamicCast( OSDictionary
,
189 topLevel
->getAnyObject()))) {
191 topLevel
->removeObject( dict
);
192 nub
= createNub( dict
);
198 nub
->registerService();
206 IOPlatformExpert::createNub( OSDictionary
* from
)
210 nub
= new IOPlatformDevice
;
212 if (!nub
->init( from
)) {
221 IOPlatformExpert::compareNubName( const IOService
* nub
,
222 OSString
* name
, OSString
** matched
) const
224 return nub
->IORegistryEntry::compareName( name
, matched
);
228 IOPlatformExpert::getNubResources( IOService
* nub
)
230 return kIOReturnSuccess
;
234 IOPlatformExpert::getBootROMType(void)
236 return _peBootROMType
;
240 IOPlatformExpert::getChipSetType(void)
242 return _peChipSetType
;
246 IOPlatformExpert::getMachineType(void)
248 return _peMachineType
;
252 IOPlatformExpert::setBootROMType(long peBootROMType
)
254 _peBootROMType
= peBootROMType
;
258 IOPlatformExpert::setChipSetType(long peChipSetType
)
260 _peChipSetType
= peChipSetType
;
264 IOPlatformExpert::setMachineType(long peMachineType
)
266 _peMachineType
= peMachineType
;
270 IOPlatformExpert::getMachineName( char * /*name*/, int /*maxLength*/)
276 IOPlatformExpert::getModelName( char * /*name*/, int /*maxLength*/)
282 IOPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
)
288 IOPlatformExpert::getPhysicalRangeAllocator(void)
290 return OSDynamicCast(IORangeAllocator
,
291 getProperty("Platform Memory Ranges"));
294 int (*PE_halt_restart
)(unsigned int type
) = 0;
297 IOPlatformExpert::haltRestart(unsigned int type
)
299 if (type
== kPEPanicSync
) {
303 if (type
== kPEHangCPU
) {
308 if (type
== kPEUPSDelayHaltCPU
) {
309 // RestartOnPowerLoss feature was turned on, proceed with shutdown.
314 // On ARM kPEPanicRestartCPU is supported in the drivers
315 if (type
== kPEPanicRestartCPU
) {
316 type
= kPERestartCPU
;
320 if (PE_halt_restart
) {
321 return (*PE_halt_restart
)(type
);
328 IOPlatformExpert::sleepKernel(void)
334 intState
= ml_set_interrupts_enabled(false);
336 for (cnt
= 0; cnt
< 10000; cnt
++) {
340 ml_set_interrupts_enabled(intState
);
342 // PE_initialize_console(0, kPEDisableScreen);
346 // PE_initialize_console(0, kPEEnableScreen);
351 IOPlatformExpert::getGMTTimeOfDay(void)
357 IOPlatformExpert::setGMTTimeOfDay(long secs
)
363 IOPlatformExpert::getConsoleInfo( PE_Video
* consoleInfo
)
365 return PE_current_console( consoleInfo
);
369 IOPlatformExpert::setConsoleInfo( PE_Video
* consoleInfo
,
372 return PE_initialize_console( consoleInfo
, op
);
376 IOPlatformExpert::registerInterruptController(OSSymbol
*name
, IOInterruptController
*interruptController
)
378 IOLockLock(gIOInterruptControllersLock
);
380 gIOInterruptControllers
->setObject(name
, interruptController
);
382 IOLockWakeup(gIOInterruptControllersLock
,
383 gIOInterruptControllers
, /* one-thread */ false);
385 IOLockUnlock(gIOInterruptControllersLock
);
387 return kIOReturnSuccess
;
391 IOPlatformExpert::deregisterInterruptController(OSSymbol
*name
)
393 IOLockLock(gIOInterruptControllersLock
);
395 gIOInterruptControllers
->removeObject(name
);
397 IOLockUnlock(gIOInterruptControllersLock
);
399 return kIOReturnSuccess
;
402 IOInterruptController
*
403 IOPlatformExpert::lookUpInterruptController(OSSymbol
*name
)
407 IOLockLock(gIOInterruptControllersLock
);
409 object
= gIOInterruptControllers
->getObject(name
);
415 IOLockSleep(gIOInterruptControllersLock
,
416 gIOInterruptControllers
, THREAD_UNINT
);
419 IOLockUnlock(gIOInterruptControllersLock
);
420 return OSDynamicCast(IOInterruptController
, object
);
425 IOPlatformExpert::setCPUInterruptProperties(IOService
*service
)
427 IOCPUInterruptController
*controller
;
429 controller
= OSDynamicCast(IOCPUInterruptController
, waitForService(serviceMatching("IOCPUInterruptController")));
431 controller
->setCPUInterruptProperties(service
);
436 IOPlatformExpert::atInterruptLevel(void)
438 return ml_at_interrupt_context();
442 IOPlatformExpert::platformAdjustService(IOService */
*service*/
)
448 IOPlatformExpert::getUTCTimeOfDay(clock_sec_t
* secs
, clock_nsec_t
* nsecs
)
450 *secs
= getGMTTimeOfDay();
455 IOPlatformExpert::setUTCTimeOfDay(clock_sec_t secs
, __unused clock_nsec_t nsecs
)
457 setGMTTimeOfDay(secs
);
461 //*********************************************************************************
464 //*********************************************************************************
468 PMLog(const char *who
, unsigned long event
,
469 unsigned long param1
, unsigned long param2
)
473 clock_get_system_microtime(&nows
, &nowus
);
474 nowus
+= (nows
% 1000) * 1000000;
476 kprintf("pm%u %p %.30s %d %lx %lx\n",
477 nowus
, OBFUSCATE(current_thread()), who
, // Identity
478 (int) event
, (long)OBFUSCATE(param1
), (long)OBFUSCATE(param2
)); // Args
482 //*********************************************************************************
483 // PMInstantiatePowerDomains
485 // In this vanilla implementation, a Root Power Domain is instantiated.
486 // All other objects which register will be children of this Root.
487 // Where this is inappropriate, PMInstantiatePowerDomains is overridden
488 // in a platform-specific subclass.
489 //*********************************************************************************
492 IOPlatformExpert::PMInstantiatePowerDomains( void )
494 root
= new IOPMrootDomain
;
501 //*********************************************************************************
504 // In this vanilla implementation, all callers are made children of the root power domain.
505 // Where this is inappropriate, PMRegisterDevice is overridden in a platform-specific subclass.
506 //*********************************************************************************
509 IOPlatformExpert::PMRegisterDevice(IOService
* theNub
, IOService
* theDevice
)
511 root
->addPowerChild( theDevice
);
514 //*********************************************************************************
517 //*********************************************************************************
520 IOPlatformExpert::hasPMFeature(unsigned long featureMask
)
522 return (_pePMFeatures
& featureMask
) != 0;
525 //*********************************************************************************
528 //*********************************************************************************
531 IOPlatformExpert::hasPrivPMFeature(unsigned long privFeatureMask
)
533 return (_pePrivPMFeatures
& privFeatureMask
) != 0;
536 //*********************************************************************************
537 // numBatteriesSupported
539 //*********************************************************************************
542 IOPlatformExpert::numBatteriesSupported(void)
544 return _peNumBatteriesSupported
;
547 //*********************************************************************************
550 // This method is called by the instantiated sublass of the platform expert to
551 // determine how a device should be inserted into the Power Domain. The subclass
552 // provides an XML power tree description against which a device is matched based
553 // on class and provider. If a match is found this routine returns true in addition
554 // to flagging the description tree at the appropriate node that a device has been
555 // registered for the given service.
556 //*********************************************************************************
559 IOPlatformExpert::CheckSubTree(OSArray
* inSubTree
, IOService
* theNub
, IOService
* theDevice
, OSDictionary
* theParent
)
562 unsigned int numPowerTreeNodes
;
563 OSDictionary
* entry
;
564 OSDictionary
* matchingDictionary
;
565 OSDictionary
* providerDictionary
;
566 OSDictionary
* deviceDictionary
;
567 OSDictionary
* nubDictionary
;
569 bool nodeFound
= false;
570 bool continueSearch
= false;
571 bool deviceMatch
= false;
572 bool providerMatch
= false;
573 bool multiParentMatch
= false;
575 if ((NULL
== theDevice
) || (NULL
== inSubTree
)) {
579 numPowerTreeNodes
= inSubTree
->getCount();
581 // iterate through the power tree to find a home for this device
583 for (i
= 0; i
< numPowerTreeNodes
; i
++) {
584 entry
= (OSDictionary
*) inSubTree
->getObject(i
);
586 matchingDictionary
= (OSDictionary
*) entry
->getObject("device");
587 providerDictionary
= (OSDictionary
*) entry
->getObject("provider");
589 deviceMatch
= true; // if no matching dictionary, this is not a criteria and so must match
590 if (matchingDictionary
) {
592 if (NULL
!= (deviceDictionary
= theDevice
->dictionaryWithProperties())) {
593 deviceMatch
= deviceDictionary
->isEqualTo( matchingDictionary
, matchingDictionary
);
594 deviceDictionary
->release();
598 providerMatch
= true; // we indicate a match if there is no nub or provider
599 if (theNub
&& providerDictionary
) {
600 providerMatch
= false;
601 if (NULL
!= (nubDictionary
= theNub
->dictionaryWithProperties())) {
602 providerMatch
= nubDictionary
->isEqualTo( providerDictionary
, providerDictionary
);
603 nubDictionary
->release();
607 multiParentMatch
= true; // again we indicate a match if there is no multi-parent node
608 if (deviceMatch
&& providerMatch
) {
609 if (NULL
!= multipleParentKeyValue
) {
610 OSNumber
* aNumber
= (OSNumber
*) entry
->getObject("multiple-parent");
611 multiParentMatch
= (NULL
!= aNumber
) ? multipleParentKeyValue
->isEqualTo(aNumber
) : false;
615 nodeFound
= (deviceMatch
&& providerMatch
&& multiParentMatch
);
617 // if the power tree specifies a provider dictionary but theNub is
618 // NULL then we cannot match with this entry.
620 if (theNub
== NULL
&& providerDictionary
!= NULL
) {
624 // if this node is THE ONE...then register the device
627 if (RegisterServiceInTree(theDevice
, entry
, theParent
, theNub
)) {
628 if (kIOLogPower
& gIOKitDebug
) {
629 IOLog("PMRegisterDevice/CheckSubTree - service registered!\n");
632 numInstancesRegistered
++;
634 // determine if we need to search for additional nodes for this item
635 multipleParentKeyValue
= (OSNumber
*) entry
->getObject("multiple-parent");
641 continueSearch
= ((false == nodeFound
) || (NULL
!= multipleParentKeyValue
));
643 if (continueSearch
&& (NULL
!= (children
= (OSArray
*) entry
->getObject("children")))) {
644 nodeFound
= CheckSubTree( children
, theNub
, theDevice
, entry
);
645 continueSearch
= ((false == nodeFound
) || (NULL
!= multipleParentKeyValue
));
648 if (false == continueSearch
) {
656 //*********************************************************************************
657 // RegisterServiceInTree
659 // Register a device at the specified node of our power tree.
660 //*********************************************************************************
663 IOPlatformExpert::RegisterServiceInTree(IOService
* theService
, OSDictionary
* theTreeNode
, OSDictionary
* theTreeParentNode
, IOService
* theProvider
)
665 IOService
* aService
;
666 bool registered
= false;
668 unsigned int numChildren
;
669 OSDictionary
* child
;
671 // make sure someone is not already registered here
673 if (NULL
== theTreeNode
->getObject("service")) {
674 if (theTreeNode
->setObject("service", OSDynamicCast( OSObject
, theService
))) {
675 // 1. CHILDREN ------------------
677 // we registered the node in the tree...now if the node has children
678 // registered we must tell this service to add them.
680 if (NULL
!= (children
= (OSArray
*) theTreeNode
->getObject("children"))) {
681 numChildren
= children
->getCount();
682 for (unsigned int i
= 0; i
< numChildren
; i
++) {
683 if (NULL
!= (child
= (OSDictionary
*) children
->getObject(i
))) {
684 if (NULL
!= (aService
= (IOService
*) child
->getObject("service"))) {
685 theService
->addPowerChild(aService
);
691 // 2. PARENT --------------------
693 // also we must notify the parent of this node (if a registered service
694 // exists there) of a new child.
696 if (theTreeParentNode
) {
697 if (NULL
!= (aService
= (IOService
*) theTreeParentNode
->getObject("service"))) {
698 if (aService
!= theProvider
) {
699 aService
->addPowerChild(theService
);
711 //*********************************************************************************
712 // printDictionaryKeys
714 // Print the keys for the given dictionary and selected contents.
715 //*********************************************************************************
717 printDictionaryKeys(OSDictionary
* inDictionary
, char * inMsg
)
719 OSCollectionIterator
* mcoll
= OSCollectionIterator::withCollection(inDictionary
);
726 mkey
= OSDynamicCast(OSSymbol
, mcoll
->getNextObject());
729 // kprintf ("dictionary key #%d: %s\n", i, mkey->getCStringNoCopy () );
731 // if this is the IOClass key, print it's contents
733 if (mkey
->isEqualTo("IOClass")) {
734 ioClass
= (OSString
*) inDictionary
->getObject("IOClass");
736 IOLog("%s IOClass is %s\n", inMsg
, ioClass
->getCStringNoCopy());
740 // if this is an IOProviderClass key print it
742 if (mkey
->isEqualTo("IOProviderClass")) {
743 ioClass
= (OSString
*) inDictionary
->getObject("IOProviderClass");
745 IOLog("%s IOProviderClass is %s\n", inMsg
, ioClass
->getCStringNoCopy());
749 // also print IONameMatch keys
750 if (mkey
->isEqualTo("IONameMatch")) {
751 ioClass
= (OSString
*) inDictionary
->getObject("IONameMatch");
753 IOLog("%s IONameMatch is %s\n", inMsg
, ioClass
->getCStringNoCopy());
757 // also print IONameMatched keys
759 if (mkey
->isEqualTo("IONameMatched")) {
760 ioClass
= (OSString
*) inDictionary
->getObject("IONameMatched");
762 IOLog("%s IONameMatched is %s\n", inMsg
, ioClass
->getCStringNoCopy());
769 if (mkey
->isEqualTo("AAPL,clock-id")) {
771 cstr
= getCStringForObject(inDictionary
->getObject("AAPL,clock-id"));
773 kprintf(" ===> AAPL,clock-id is %s\n", cstr
);
780 if (mkey
->isEqualTo("name")) {
783 getCStringForObject(inDictionary
->getObject("name"), nameStr
,
785 if (strlen(nameStr
) > 0) {
786 IOLog("%s name is %s\n", inMsg
, nameStr
);
790 mkey
= (OSSymbol
*) mcoll
->getNextObject();
799 getCStringForObject(OSObject
*inObj
, char *outStr
, size_t outStrLen
)
804 if ((NULL
== inObj
) || (NULL
== outStr
)) {
808 char * objString
= (char *) (inObj
->getMetaClass())->getClassName();
810 if ((0 == strncmp(objString
, "OSString", sizeof("OSString"))) ||
811 (0 == strncmp(objString
, "OSSymbol", sizeof("OSSymbol")))) {
812 strlcpy(outStr
, ((OSString
*)inObj
)->getCStringNoCopy(), outStrLen
);
813 } else if (0 == strncmp(objString
, "OSData", sizeof("OSData"))) {
814 len
= ((OSData
*)inObj
)->getLength();
815 buffer
= (char *)((OSData
*)inObj
)->getBytesNoCopy();
816 if (buffer
&& (len
> 0)) {
817 for (i
= 0; i
< len
; i
++) {
818 outStr
[i
] = buffer
[i
];
825 /* IOShutdownNotificationsTimedOut
826 * - Called from a timer installed by PEHaltRestart
829 IOShutdownNotificationsTimedOut(
830 thread_call_param_t p0
,
831 thread_call_param_t p1
)
833 #ifdef CONFIG_EMBEDDED
834 /* 30 seconds has elapsed - panic */
835 panic("Halt/Restart Timed Out");
837 #else /* ! CONFIG_EMBEDDED */
838 int type
= (int)(long)p0
;
839 uint32_t timeout
= (uint32_t)(uintptr_t)p1
;
841 IOPMrootDomain
*pmRootDomain
= IOService::getPMRootDomain();
843 if ((PEGetCoprocessorVersion() >= kCoprocessorVersion2
) || pmRootDomain
->checkShutdownTimeout()) {
844 pmRootDomain
->panicWithShutdownLog(timeout
* 1000);
848 /* 30 seconds has elapsed - resume shutdown */
850 gIOPlatform
->haltRestart(type
);
852 #endif /* CONFIG_EMBEDDED */
858 * Callouts from BSD for machine name & model
862 PEGetMachineName( char * name
, int maxLength
)
865 return gIOPlatform
->getMachineName( name
, maxLength
);
872 PEGetModelName( char * name
, int maxLength
)
875 return gIOPlatform
->getModelName( name
, maxLength
);
882 PEGetPlatformEpoch(void)
885 return gIOPlatform
->getBootROMType();
892 PEHaltRestart(unsigned int type
)
894 IOPMrootDomain
*pmRootDomain
;
895 AbsoluteTime deadline
;
896 thread_call_t shutdown_hang
;
897 IORegistryEntry
*node
;
899 uint32_t timeout
= kShutdownTimeout
;
900 static boolean_t panic_begin_called
= FALSE
;
902 if (type
== kPEHaltCPU
|| type
== kPERestartCPU
|| type
== kPEUPSDelayHaltCPU
) {
903 pmRootDomain
= IOService::getPMRootDomain();
904 /* Notify IOKit PM clients of shutdown/restart
905 * Clients subscribe to this message with a call to
906 * IOService::registerInterest()
909 /* Spawn a thread that will panic in 30 seconds.
910 * If all goes well the machine will be off by the time
911 * the timer expires. If the device wants a different
912 * timeout, use that value instead of 30 seconds.
915 #define RESTART_NODE_PATH "/defaults"
917 #define RESTART_NODE_PATH "/chosen"
919 node
= IORegistryEntry::fromPath( RESTART_NODE_PATH
, gIODTPlane
);
921 data
= OSDynamicCast( OSData
, node
->getProperty( "halt-restart-timeout" ));
922 if (data
&& data
->getLength() == 4) {
923 timeout
= *((uint32_t *) data
->getBytesNoCopy());
927 shutdown_hang
= thread_call_allocate( &IOShutdownNotificationsTimedOut
,
928 (thread_call_param_t
)(uintptr_t) type
);
929 clock_interval_to_deadline( timeout
, kSecondScale
, &deadline
);
930 thread_call_enter1_delayed( shutdown_hang
, (thread_call_param_t
)(uintptr_t)timeout
, deadline
);
932 pmRootDomain
->handlePlatformHaltRestart(type
);
933 /* This notification should have few clients who all do
934 * their work synchronously.
936 * In this "shutdown notification" context we don't give
937 * drivers the option of working asynchronously and responding
938 * later. PM internals make it very hard to wait for asynchronous
941 } else if (type
== kPEPanicRestartCPU
|| type
== kPEPanicSync
) {
942 if (type
== kPEPanicRestartCPU
) {
943 // Notify any listeners that we're done collecting
944 // panic data before we call through to do the restart
946 if (coprocessor_cross_panic_enabled
)
948 IOCPURunPlatformPanicActions(kPEPanicEnd
);
950 // Callout to shutdown the disk driver once we've returned from the
951 // kPEPanicEnd callback (and we know all core dumps on this system
953 IOCPURunPlatformPanicActions(kPEPanicDiskShutdown
);
956 // Do an initial sync to flush as much panic data as possible,
957 // in case we have a problem in one of the platorm panic handlers.
958 // After running the platform handlers, do a final sync w/
959 // platform hardware quiesced for the panic.
960 PE_sync_panic_buffers();
961 IOCPURunPlatformPanicActions(type
);
962 PE_sync_panic_buffers();
963 } else if (type
== kPEPanicEnd
) {
965 if (coprocessor_cross_panic_enabled
)
967 IOCPURunPlatformPanicActions(type
);
968 } else if (type
== kPEPanicBegin
) {
970 if (coprocessor_cross_panic_enabled
)
973 // Only call the kPEPanicBegin callout once
974 if (!panic_begin_called
) {
975 panic_begin_called
= TRUE
;
976 IOCPURunPlatformPanicActions(type
);
982 return gIOPlatform
->haltRestart(type
);
989 PESavePanicInfo(UInt8
*buffer
, UInt32 length
)
991 if (gIOPlatform
!= 0) {
992 return gIOPlatform
->savePanicInfo(buffer
, length
);
999 PESavePanicInfoAction(void *buffer
, UInt32 offset
, UInt32 length
)
1001 IOCPURunPlatformPanicSyncAction(buffer
, offset
, length
);
1007 init_gIOOptionsEntry(void)
1009 IORegistryEntry
*entry
;
1011 volatile void **options
;
1014 if (gIOOptionsEntry
) {
1018 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
1023 nvram_entry
= (void *) OSDynamicCast(IODTNVRAM
, entry
);
1028 options
= (volatile void **) &gIOOptionsEntry
;
1029 if (!OSCompareAndSwapPtr(NULL
, nvram_entry
, options
)) {
1041 /* pass in a NULL value if you just want to figure out the len */
1043 PEReadNVRAMProperty(const char *symbol
, void *value
,
1050 if (!symbol
|| !len
) {
1054 if (init_gIOOptionsEntry() < 0) {
1061 obj
= gIOOptionsEntry
->getProperty(symbol
);
1066 /* convert to data */
1067 data
= OSDynamicCast(OSData
, obj
);
1072 *len
= data
->getLength();
1073 vlen
= min(vlen
, *len
);
1074 if (value
&& vlen
) {
1075 memcpy((void *) value
, data
->getBytesNoCopy(), vlen
);
1085 PEWriteNVRAMBooleanProperty(const char *symbol
, boolean_t value
)
1087 const OSSymbol
*sym
= NULL
;
1088 OSBoolean
*data
= NULL
;
1091 if (symbol
== NULL
) {
1095 if (init_gIOOptionsEntry() < 0) {
1099 if ((sym
= OSSymbol::withCStringNoCopy(symbol
)) == NULL
) {
1103 data
= value
? kOSBooleanTrue
: kOSBooleanFalse
;
1104 ret
= gIOOptionsEntry
->setProperty(sym
, data
);
1108 /* success, force the NVRAM to flush writes */
1110 gIOOptionsEntry
->sync();
1118 PEWriteNVRAMPropertyInternal(const char *symbol
, boolean_t copySymbol
, const void *value
,
1119 const unsigned int len
)
1121 const OSSymbol
*sym
;
1125 if (!symbol
|| !value
|| !len
) {
1129 if (init_gIOOptionsEntry() < 0) {
1133 if (copySymbol
== TRUE
) {
1134 sym
= OSSymbol::withCString(symbol
);
1136 sym
= OSSymbol::withCStringNoCopy(symbol
);
1143 data
= OSData::withBytes((void *) value
, len
);
1148 ret
= gIOOptionsEntry
->setProperty(sym
, data
);
1155 gIOOptionsEntry
->sync();
1164 PEWriteNVRAMProperty(const char *symbol
, const void *value
,
1165 const unsigned int len
)
1167 return PEWriteNVRAMPropertyInternal(symbol
, FALSE
, value
, len
);
1171 PEWriteNVRAMPropertyWithCopy(const char *symbol
, const void *value
,
1172 const unsigned int len
)
1174 return PEWriteNVRAMPropertyInternal(symbol
, TRUE
, value
, len
);
1178 PERemoveNVRAMProperty(const char *symbol
)
1180 const OSSymbol
*sym
;
1186 if (init_gIOOptionsEntry() < 0) {
1190 sym
= OSSymbol::withCStringNoCopy(symbol
);
1195 gIOOptionsEntry
->removeProperty(sym
);
1199 gIOOptionsEntry
->sync();
1207 PEGetGMTTimeOfDay(void)
1212 PEGetUTCTimeOfDay(&secs
, &usecs
);
1217 PESetGMTTimeOfDay(long secs
)
1219 PESetUTCTimeOfDay(secs
, 0);
1223 PEGetUTCTimeOfDay(clock_sec_t
* secs
, clock_usec_t
* usecs
)
1225 clock_nsec_t nsecs
= 0;
1229 gIOPlatform
->getUTCTimeOfDay(secs
, &nsecs
);
1232 assert(nsecs
< NSEC_PER_SEC
);
1233 *usecs
= nsecs
/ NSEC_PER_USEC
;
1237 PESetUTCTimeOfDay(clock_sec_t secs
, clock_usec_t usecs
)
1239 assert(usecs
< USEC_PER_SEC
);
1241 gIOPlatform
->setUTCTimeOfDay(secs
, usecs
* NSEC_PER_USEC
);
1246 PEGetCoprocessorVersion( void )
1248 coprocessor_type_t coprocessor_version
= kCoprocessorVersionNone
;
1249 #if !CONFIG_EMBEDDED
1250 IORegistryEntry
*platform_entry
= NULL
;
1251 OSData
*coprocessor_version_obj
= NULL
;
1253 platform_entry
= IORegistryEntry::fromPath(kIODeviceTreePlane
":/efi/platform");
1254 if (platform_entry
!= NULL
) {
1255 coprocessor_version_obj
= OSDynamicCast(OSData
, platform_entry
->getProperty("apple-coprocessor-version"));
1256 if ((coprocessor_version_obj
!= NULL
) && (coprocessor_version_obj
->getLength() <= sizeof(uint64_t))) {
1257 memcpy(&coprocessor_version
, coprocessor_version_obj
->getBytesNoCopy(), coprocessor_version_obj
->getLength());
1259 platform_entry
->release();
1262 return coprocessor_version
;
1267 IOPlatformExpert::registerNVRAMController(IONVRAMController
* caller
)
1270 IORegistryEntry
* entry
;
1271 OSString
* string
= 0;
1275 entry
= IORegistryEntry::fromPath( "/chosen", gIODTPlane
);
1279 data1
= OSDynamicCast( OSData
, entry
->getProperty( "unique-chip-id" ));
1280 if (data1
&& data1
->getLength() == 8) {
1283 data2
= OSDynamicCast( OSData
, entry
->getProperty( "chip-id" ));
1284 if (data2
&& data2
->getLength() == 4) {
1286 uint8_t digest
[SHA_DIGEST_LENGTH
];
1287 const uuid_t space
= { 0xA6, 0xDD, 0x4C, 0xCB, 0xB5, 0xE8, 0x4A, 0xF5, 0xAC, 0xDD, 0xB6, 0xDC, 0x6A, 0x05, 0x42, 0xB8 };
1289 SHA1Init( &context
);
1290 SHA1Update( &context
, space
, sizeof(space
));
1291 SHA1Update( &context
, data1
->getBytesNoCopy(), data1
->getLength());
1292 SHA1Update( &context
, data2
->getBytesNoCopy(), data2
->getLength());
1293 SHA1Final( digest
, &context
);
1295 digest
[6] = (digest
[6] & 0x0F) | 0x50;
1296 digest
[8] = (digest
[8] & 0x3F) | 0x80;
1298 uuid_unparse( digest
, uuid
);
1299 string
= OSString::withCString( uuid
);
1305 #else /* !CONFIG_EMBEDDED */
1307 * If we have panic debugging enabled and a prod-fused coprocessor,
1308 * disable cross panics so that the co-processor doesn't cause the system
1309 * to reset when we enter the debugger or hit a panic on the x86 side.
1311 if (panicDebugging
) {
1312 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
1314 data
= OSDynamicCast( OSData
, entry
->getProperty( APPLE_SECURE_BOOT_VARIABLE_GUID
":EffectiveProductionStatus" ));
1315 if (data
&& (data
->getLength() == sizeof(UInt8
))) {
1316 UInt8
*isProdFused
= (UInt8
*) data
->getBytesNoCopy();
1317 UInt32 debug_flags
= 0;
1318 if (*isProdFused
|| (PE_i_can_has_debugger(&debug_flags
) &&
1319 (debug_flags
& DB_DISABLE_CROSS_PANIC
))) {
1320 coprocessor_cross_panic_enabled
= FALSE
;
1327 entry
= IORegistryEntry::fromPath( "/efi/platform", gIODTPlane
);
1329 data
= OSDynamicCast( OSData
, entry
->getProperty( "system-id" ));
1330 if (data
&& data
->getLength() == 16) {
1332 uint8_t digest
[SHA_DIGEST_LENGTH
];
1333 const uuid_t space
= { 0x2A, 0x06, 0x19, 0x90, 0xD3, 0x8D, 0x44, 0x40, 0xA1, 0x39, 0xC4, 0x97, 0x70, 0x37, 0x65, 0xAC };
1335 SHA1Init( &context
);
1336 SHA1Update( &context
, space
, sizeof(space
));
1337 SHA1Update( &context
, data
->getBytesNoCopy(), data
->getLength());
1338 SHA1Final( digest
, &context
);
1340 digest
[6] = (digest
[6] & 0x0F) | 0x50;
1341 digest
[8] = (digest
[8] & 0x3F) | 0x80;
1343 uuid_unparse( digest
, uuid
);
1344 string
= OSString::withCString( uuid
);
1349 #endif /* !CONFIG_EMBEDDED */
1352 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
1354 data
= OSDynamicCast( OSData
, entry
->getProperty( "platform-uuid" ));
1355 if (data
&& data
->getLength() == sizeof(uuid_t
)) {
1356 uuid_unparse((uint8_t *) data
->getBytesNoCopy(), uuid
);
1357 string
= OSString::withCString( uuid
);
1365 getProvider()->setProperty( kIOPlatformUUIDKey
, string
);
1366 publishResource( kIOPlatformUUIDKey
, string
);
1371 publishResource("IONVRAM");
1375 IOPlatformExpert::callPlatformFunction(const OSSymbol
*functionName
,
1376 bool waitForFunction
,
1377 void *param1
, void *param2
,
1378 void *param3
, void *param4
)
1380 IOService
*service
, *_resources
;
1382 if (waitForFunction
) {
1383 _resources
= waitForService(resourceMatching(functionName
));
1385 _resources
= getResourceService();
1387 if (_resources
== 0) {
1388 return kIOReturnUnsupported
;
1391 service
= OSDynamicCast(IOService
, _resources
->getProperty(functionName
));
1393 return kIOReturnUnsupported
;
1396 return service
->callPlatformFunction(functionName
, waitForFunction
,
1397 param1
, param2
, param3
, param4
);
1401 IOPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1406 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1409 #define super IOPlatformExpert
1411 OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert
, IOPlatformExpert
)
1413 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 0);
1414 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 1);
1415 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 2);
1416 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 3);
1417 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 4);
1418 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 5);
1419 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 6);
1420 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 7);
1422 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1425 IODTPlatformExpert::probe( IOService
* provider
,
1428 if (!super::probe( provider
, score
)) {
1432 // check machine types
1433 if (!provider
->compareNames( getProperty( gIONameMatchKey
))) {
1441 IODTPlatformExpert::configure( IOService
* provider
)
1443 if (!super::configure( provider
)) {
1447 processTopLevel( provider
);
1453 IODTPlatformExpert::createNub( IORegistryEntry
* from
)
1457 nub
= new IOPlatformDevice
;
1459 if (!nub
->init( from
, gIODTPlane
)) {
1468 IODTPlatformExpert::createNubs( IOService
* parent
, OSIterator
* iter
)
1470 IORegistryEntry
* next
;
1475 while ((next
= (IORegistryEntry
*) iter
->getNextObject())) {
1476 if (0 == (nub
= createNub( next
))) {
1480 nub
->attach( parent
);
1481 nub
->registerService();
1490 IODTPlatformExpert::processTopLevel( IORegistryEntry
* rootEntry
)
1493 IORegistryEntry
* next
;
1494 IORegistryEntry
* cpus
;
1495 IORegistryEntry
* options
;
1498 kids
= IODTFindMatchingEntries( rootEntry
, 0, deleteList());
1500 while ((next
= (IORegistryEntry
*)kids
->getNextObject())) {
1501 next
->detachAll( gIODTPlane
);
1506 // Publish an IODTNVRAM class on /options.
1507 options
= rootEntry
->childFromPath("options", gIODTPlane
);
1509 dtNVRAM
= new IODTNVRAM
;
1511 if (!dtNVRAM
->init(options
, gIODTPlane
)) {
1515 dtNVRAM
->attach(this);
1516 dtNVRAM
->registerService();
1522 // Publish the cpus.
1523 cpus
= rootEntry
->childFromPath( "cpus", gIODTPlane
);
1525 createNubs( this, IODTFindMatchingEntries( cpus
, kIODTExclusive
, 0));
1529 // publish top level, minus excludeList
1530 createNubs( this, IODTFindMatchingEntries( rootEntry
, kIODTExclusive
, excludeList()));
1534 IODTPlatformExpert::getNubResources( IOService
* nub
)
1536 if (nub
->getDeviceMemory()) {
1537 return kIOReturnSuccess
;
1540 IODTResolveAddressing( nub
, "reg", 0);
1542 return kIOReturnSuccess
;
1546 IODTPlatformExpert::compareNubName( const IOService
* nub
,
1547 OSString
* name
, OSString
** matched
) const
1549 return IODTCompareNubName( nub
, name
, matched
)
1550 || super::compareNubName( nub
, name
, matched
);
1554 IODTPlatformExpert::getModelName( char * name
, int maxLength
)
1564 prop
= (OSData
*) getProvider()->getProperty( gIODTCompatibleKey
);
1566 str
= (const char *) prop
->getBytesNoCopy();
1568 if (0 == strncmp( str
, "AAPL,", strlen( "AAPL," ))) {
1569 str
+= strlen( "AAPL," );
1573 while ((c
= *str
++)) {
1574 if ((c
== '/') || (c
== ' ')) {
1579 if (len
>= maxLength
) {
1591 IODTPlatformExpert::getMachineName( char * name
, int maxLength
)
1597 prop
= (OSData
*) getProvider()->getProperty( gIODTModelKey
);
1601 strlcpy( name
, (const char *) prop
->getBytesNoCopy(), maxLength
);
1607 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1610 IODTPlatformExpert::registerNVRAMController( IONVRAMController
* nvram
)
1613 dtNVRAM
->registerNVRAMController(nvram
);
1616 super::registerNVRAMController(nvram
);
1620 IODTPlatformExpert::haltRestart(unsigned int type
)
1626 return super::haltRestart(type
);
1630 IODTPlatformExpert::readXPRAM(IOByteCount offset
, UInt8
* buffer
,
1634 return dtNVRAM
->readXPRAM(offset
, buffer
, length
);
1636 return kIOReturnNotReady
;
1641 IODTPlatformExpert::writeXPRAM(IOByteCount offset
, UInt8
* buffer
,
1645 return dtNVRAM
->writeXPRAM(offset
, buffer
, length
);
1647 return kIOReturnNotReady
;
1652 IODTPlatformExpert::readNVRAMProperty(
1653 IORegistryEntry
* entry
,
1654 const OSSymbol
** name
, OSData
** value
)
1657 return dtNVRAM
->readNVRAMProperty(entry
, name
, value
);
1659 return kIOReturnNotReady
;
1664 IODTPlatformExpert::writeNVRAMProperty(
1665 IORegistryEntry
* entry
,
1666 const OSSymbol
* name
, OSData
* value
)
1669 return dtNVRAM
->writeNVRAMProperty(entry
, name
, value
);
1671 return kIOReturnNotReady
;
1676 IODTPlatformExpert::getNVRAMPartitions(void)
1679 return dtNVRAM
->getNVRAMPartitions();
1686 IODTPlatformExpert::readNVRAMPartition(const OSSymbol
* partitionID
,
1687 IOByteCount offset
, UInt8
* buffer
,
1691 return dtNVRAM
->readNVRAMPartition(partitionID
, offset
,
1694 return kIOReturnNotReady
;
1699 IODTPlatformExpert::writeNVRAMPartition(const OSSymbol
* partitionID
,
1700 IOByteCount offset
, UInt8
* buffer
,
1704 return dtNVRAM
->writeNVRAMPartition(partitionID
, offset
,
1707 return kIOReturnNotReady
;
1712 IODTPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1714 IOByteCount lengthSaved
= 0;
1717 lengthSaved
= dtNVRAM
->savePanicInfo(buffer
, length
);
1720 if (lengthSaved
== 0) {
1721 lengthSaved
= super::savePanicInfo(buffer
, length
);
1728 IODTPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
)
1730 UInt8
* serialNumber
;
1731 unsigned int serialNumberSize
;
1732 unsigned short pos
= 0;
1736 if (myProperty
!= NULL
) {
1737 serialNumberSize
= myProperty
->getLength();
1738 serialNumber
= (UInt8
*)(myProperty
->getBytesNoCopy());
1739 temp
= (char*)serialNumber
;
1740 if (serialNumberSize
> 0) {
1741 // check to see if this is a CTO serial number...
1742 while (pos
< serialNumberSize
&& temp
[pos
] != '-') {
1746 if (pos
< serialNumberSize
) { // there was a hyphen, so it's a CTO serial number
1747 memcpy(SerialNo
, serialNumber
+ 12, 8);
1748 memcpy(&SerialNo
[8], serialNumber
, 3);
1750 memcpy(&SerialNo
[12], serialNumber
+ 3, 8);
1752 } else { // just a normal serial number
1753 memcpy(SerialNo
, serialNumber
+ 13, 8);
1754 memcpy(&SerialNo
[8], serialNumber
, 3);
1757 return OSString::withCString(SerialNo
);
1764 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1767 #define super IOService
1769 OSDefineMetaClassAndStructors(IOPlatformExpertDevice
, IOService
)
1771 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 0);
1772 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 1);
1773 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 2);
1774 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 3);
1776 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1779 IOPlatformExpertDevice::compareName( OSString
* name
,
1780 OSString
** matched
) const
1782 return IODTCompareNubName( this, name
, matched
);
1786 IOPlatformExpertDevice::initWithArgs(
1787 void * dtTop
, void * p2
, void * p3
, void * p4
)
1789 IORegistryEntry
* dt
= 0;
1792 // dtTop may be zero on non- device tree systems
1793 if (dtTop
&& (dt
= IODeviceTreeAlloc( dtTop
))) {
1794 ok
= super::init( dt
, gIODTPlane
);
1803 workLoop
= IOWorkLoop::workLoop();
1812 IOPlatformExpertDevice::getWorkLoop() const
1818 IOPlatformExpertDevice::setProperties( OSObject
* properties
)
1820 return kIOReturnUnsupported
;
1824 IOPlatformExpertDevice::newUserClient( task_t owningTask
, void * securityID
,
1825 UInt32 type
, OSDictionary
* properties
,
1826 IOUserClient
** handler
)
1828 IOReturn err
= kIOReturnSuccess
;
1829 IOUserClient
* newConnect
= 0;
1830 IOUserClient
* theConnect
= 0;
1833 case kIOKitDiagnosticsClientType
:
1834 newConnect
= IOKitDiagnosticsClient::withTask(owningTask
);
1836 err
= kIOReturnNotPermitted
;
1840 err
= kIOReturnBadArgument
;
1844 if ((false == newConnect
->attach(this))
1845 || (false == newConnect
->start(this))) {
1846 newConnect
->detach( this );
1847 newConnect
->release();
1848 err
= kIOReturnNotPermitted
;
1850 theConnect
= newConnect
;
1854 *handler
= theConnect
;
1859 IOPlatformExpertDevice::free()
1862 workLoop
->release();
1866 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1869 #define super IOService
1871 OSDefineMetaClassAndStructors(IOPlatformDevice
, IOService
)
1873 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 0);
1874 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 1);
1875 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 2);
1876 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 3);
1878 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1881 IOPlatformDevice::compareName( OSString
* name
,
1882 OSString
** matched
) const
1884 return ((IOPlatformExpert
*)getProvider())->
1885 compareNubName( this, name
, matched
);
1889 IOPlatformDevice::matchLocation( IOService
* /* client */ )
1895 IOPlatformDevice::getResources( void )
1897 return ((IOPlatformExpert
*)getProvider())->getNubResources( this );
1900 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1902 /*********************************************************************
1903 * IOPanicPlatform class
1905 * If no legitimate IOPlatformDevice matches, this one does and panics
1906 * the kernel with a suitable message.
1907 *********************************************************************/
1909 class IOPanicPlatform
: IOPlatformExpert
{
1910 OSDeclareDefaultStructors(IOPanicPlatform
);
1913 bool start(IOService
* provider
) APPLE_KEXT_OVERRIDE
;
1917 OSDefineMetaClassAndStructors(IOPanicPlatform
, IOPlatformExpert
);
1921 IOPanicPlatform::start(IOService
* provider
)
1923 const char * platform_name
= "(unknown platform name)";
1926 platform_name
= provider
->getName();
1929 panic("Unable to find driver for this platform: \"%s\".\n",