]> git.saurik.com Git - apple/xnu.git/blame_incremental - iokit/Kernel/IOPlatformExpert.cpp
xnu-7195.101.1.tar.gz
[apple/xnu.git] / iokit / Kernel / IOPlatformExpert.cpp
... / ...
CommitLineData
1/*
2 * Copyright (c) 1998-2017 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
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>
45
46#include "IOKitKernelInternal.h"
47
48#include <IOKit/system.h>
49#include <sys/csr.h>
50
51#include <libkern/c++/OSContainers.h>
52#include <libkern/c++/OSSharedPtr.h>
53#include <libkern/crypto/sha1.h>
54#include <libkern/OSAtomic.h>
55
56#if defined(__arm64__)
57#include <arm64/tlb.h>
58#endif
59
60extern "C" {
61#include <machine/machine_routines.h>
62#include <pexpert/pexpert.h>
63#include <uuid/uuid.h>
64#include <sys/sysctl.h>
65}
66
67#define kShutdownTimeout 30 //in secs
68
69#if defined(XNU_TARGET_OS_OSX)
70
71boolean_t coprocessor_cross_panic_enabled = TRUE;
72#define APPLE_VENDOR_VARIABLE_GUID "4d1ede05-38c7-4a6a-9cc6-4bcca8b38c14"
73#endif /* defined(XNU_TARGET_OS_OSX) */
74
75void printDictionaryKeys(OSDictionary * inDictionary, char * inMsg);
76static void getCStringForObject(OSObject *inObj, char *outStr, size_t outStrLen);
77
78/*
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.
84 *
85 * <rdar://problem/33831837> tracks turning this on by default.
86 */
87uint32_t gEnforceQuiesceSafety = 0;
88
89/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
90
91#define super IOService
92
93OSDefineMetaClassAndStructors(IOPlatformExpert, IOService)
94
95OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 0);
96OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 1);
97OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 2);
98OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 3);
99OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 4);
100OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 5);
101OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 6);
102
103OSMetaClassDefineReservedUnused(IOPlatformExpert, 7);
104OSMetaClassDefineReservedUnused(IOPlatformExpert, 8);
105OSMetaClassDefineReservedUnused(IOPlatformExpert, 9);
106OSMetaClassDefineReservedUnused(IOPlatformExpert, 10);
107OSMetaClassDefineReservedUnused(IOPlatformExpert, 11);
108
109static IOPlatformExpert * gIOPlatform;
110static OSDictionary * gIOInterruptControllers;
111static IOLock * gIOInterruptControllersLock;
112static IODTNVRAM *gIOOptionsEntry;
113
114OSSymbol * gPlatformInterruptControllerName;
115
116/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
117
118bool
119IOPlatformExpert::attach( IOService * provider )
120{
121 if (!super::attach( provider )) {
122 return false;
123 }
124
125 return true;
126}
127
128bool
129IOPlatformExpert::start( IOService * provider )
130{
131 IORangeAllocator * physicalRanges;
132 OSData * busFrequency;
133 uint32_t debugFlags;
134
135
136 if (!super::start(provider)) {
137 return false;
138 }
139
140 // Override the mapper present flag is requested by boot arguments, if SIP disabled.
141#if CONFIG_CSR
142 if (csr_check(CSR_ALLOW_UNRESTRICTED_FS) == 0)
143#endif /* CONFIG_CSR */
144 {
145 if (PE_parse_boot_argn("dart", &debugFlags, sizeof(debugFlags)) && (debugFlags == 0)) {
146 removeProperty(kIOPlatformMapperPresentKey);
147 }
148#if DEBUG || DEVELOPMENT
149 if (PE_parse_boot_argn("-x", &debugFlags, sizeof(debugFlags))) {
150 removeProperty(kIOPlatformMapperPresentKey);
151 }
152#endif /* DEBUG || DEVELOPMENT */
153 }
154
155 // Register the presence or lack thereof a system
156 // PCI address mapper with the IOMapper class
157 IOMapper::setMapperRequired(NULL != getProperty(kIOPlatformMapperPresentKey));
158
159 gIOInterruptControllers = OSDictionary::withCapacity(1);
160 gIOInterruptControllersLock = IOLockAlloc();
161
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();
166
167 gPlatformInterruptControllerName = (OSSymbol *)OSSymbol::withCStringNoCopy("IOPlatformInterruptController");
168
169 physicalRanges = IORangeAllocator::withRange(0xffffffff, 1, 16,
170 IORangeAllocator::kLocking);
171 assert(physicalRanges);
172 setProperty("Platform Memory Ranges", physicalRanges);
173
174 setPlatform( this );
175 gIOPlatform = this;
176
177 PMInstantiatePowerDomains();
178
179#if !defined(__x86_64__)
180 publishPlatformUUIDAndSerial();
181#endif /* !defined(__x86_64__) */
182
183#if defined (__x86_64__)
184 if (PEGetCoprocessorVersion() >= kCoprocessorVersion2) {
185 coprocessor_paniclog_flush = TRUE;
186 extended_debug_log_init();
187 }
188#endif
189
190 PE_parse_boot_argn("enforce_quiesce_safety", &gEnforceQuiesceSafety,
191 sizeof(gEnforceQuiesceSafety));
192
193 return configure(provider);
194}
195
196bool
197IOPlatformExpert::configure( IOService * provider )
198{
199 OSSet * topLevel;
200 OSDictionary * dict;
201 IOService * nub;
202
203 topLevel = OSDynamicCast( OSSet, getProperty("top-level"));
204
205 if (topLevel) {
206 while ((dict = OSDynamicCast( OSDictionary,
207 topLevel->getAnyObject()))) {
208 dict->retain();
209 topLevel->removeObject( dict );
210 nub = createNub( dict );
211 if (NULL == nub) {
212 continue;
213 }
214 dict->release();
215 nub->attach( this );
216 nub->registerService();
217 }
218 }
219
220 return true;
221}
222
223IOService *
224IOPlatformExpert::createNub( OSDictionary * from )
225{
226 IOService * nub;
227
228 nub = new IOPlatformDevice;
229 if (nub) {
230 if (!nub->init( from )) {
231 nub->release();
232 nub = NULL;
233 }
234 }
235 return nub;
236}
237
238bool
239IOPlatformExpert::compareNubName( const IOService * nub,
240 OSString * name, OSString ** matched ) const
241{
242 return nub->IORegistryEntry::compareName( name, matched );
243}
244
245bool
246IOPlatformExpert::compareNubName( const IOService * nub,
247 OSString * name, OSSharedPtr<OSString>& matched ) const
248{
249 OSString* matchedRaw = NULL;
250 bool result = compareNubName(nub, name, &matchedRaw);
251 matched.reset(matchedRaw, OSNoRetain);
252 return result;
253}
254
255IOReturn
256IOPlatformExpert::getNubResources( IOService * nub )
257{
258 return kIOReturnSuccess;
259}
260
261long
262IOPlatformExpert::getBootROMType(void)
263{
264 return _peBootROMType;
265}
266
267long
268IOPlatformExpert::getChipSetType(void)
269{
270 return _peChipSetType;
271}
272
273long
274IOPlatformExpert::getMachineType(void)
275{
276 return _peMachineType;
277}
278
279void
280IOPlatformExpert::setBootROMType(long peBootROMType)
281{
282 _peBootROMType = peBootROMType;
283}
284
285void
286IOPlatformExpert::setChipSetType(long peChipSetType)
287{
288 _peChipSetType = peChipSetType;
289}
290
291void
292IOPlatformExpert::setMachineType(long peMachineType)
293{
294 _peMachineType = peMachineType;
295}
296
297bool
298IOPlatformExpert::getMachineName( char * /*name*/, int /*maxLength*/)
299{
300 return false;
301}
302
303bool
304IOPlatformExpert::getModelName( char * /*name*/, int /*maxLength*/)
305{
306 return false;
307}
308
309bool
310IOPlatformExpert::getTargetName( char * /*name*/, int /*maxLength*/)
311{
312 return false;
313}
314
315bool
316IOPlatformExpert::getProductName( char * /*name*/, int /*maxLength*/)
317{
318 return false;
319}
320
321OSString*
322IOPlatformExpert::createSystemSerialNumberString(OSData* myProperty)
323{
324 return NULL;
325}
326
327IORangeAllocator *
328IOPlatformExpert::getPhysicalRangeAllocator(void)
329{
330 return OSDynamicCast(IORangeAllocator,
331 getProperty("Platform Memory Ranges"));
332}
333
334int (*PE_halt_restart)(unsigned int type) = NULL;
335
336int
337IOPlatformExpert::haltRestart(unsigned int type)
338{
339 if (type == kPEPanicSync) {
340 return 0;
341 }
342
343 if (type == kPEHangCPU) {
344 while (true) {
345 }
346 }
347
348 if (type == kPEUPSDelayHaltCPU) {
349 // RestartOnPowerLoss feature was turned on, proceed with shutdown.
350 type = kPEHaltCPU;
351 }
352
353#if defined (__x86_64__)
354 // On ARM kPEPanicRestartCPU is supported in the drivers
355 if (type == kPEPanicRestartCPU) {
356 type = kPERestartCPU;
357 }
358#endif
359
360 if (PE_halt_restart) {
361 return (*PE_halt_restart)(type);
362 } else {
363 return -1;
364 }
365}
366
367void
368IOPlatformExpert::sleepKernel(void)
369{
370#if 0
371 long cnt;
372 boolean_t intState;
373
374 intState = ml_set_interrupts_enabled(false);
375
376 for (cnt = 0; cnt < 10000; cnt++) {
377 IODelay(1000);
378 }
379
380 ml_set_interrupts_enabled(intState);
381#else
382// PE_initialize_console(0, kPEDisableScreen);
383
384 IOCPUSleepKernel();
385
386// PE_initialize_console(0, kPEEnableScreen);
387#endif
388}
389
390long
391IOPlatformExpert::getGMTTimeOfDay(void)
392{
393 return 0;
394}
395
396void
397IOPlatformExpert::setGMTTimeOfDay(long secs)
398{
399}
400
401
402IOReturn
403IOPlatformExpert::getConsoleInfo( PE_Video * consoleInfo )
404{
405 return PE_current_console( consoleInfo);
406}
407
408IOReturn
409IOPlatformExpert::setConsoleInfo( PE_Video * consoleInfo,
410 unsigned int op)
411{
412 return PE_initialize_console( consoleInfo, op );
413}
414
415IOReturn
416IOPlatformExpert::registerInterruptController(OSSymbol *name, IOInterruptController *interruptController)
417{
418 IOLockLock(gIOInterruptControllersLock);
419
420 gIOInterruptControllers->setObject(name, interruptController);
421
422 IOLockWakeup(gIOInterruptControllersLock,
423 gIOInterruptControllers, /* one-thread */ false);
424
425 IOLockUnlock(gIOInterruptControllersLock);
426
427 return kIOReturnSuccess;
428}
429
430IOReturn
431IOPlatformExpert::deregisterInterruptController(OSSymbol *name)
432{
433 IOLockLock(gIOInterruptControllersLock);
434
435 gIOInterruptControllers->removeObject(name);
436
437 IOLockUnlock(gIOInterruptControllersLock);
438
439 return kIOReturnSuccess;
440}
441
442IOInterruptController *
443IOPlatformExpert::lookUpInterruptController(OSSymbol *name)
444{
445 OSObject *object;
446
447 IOLockLock(gIOInterruptControllersLock);
448 while (1) {
449 object = gIOInterruptControllers->getObject(name);
450
451 if (object != NULL) {
452 break;
453 }
454
455 IOLockSleep(gIOInterruptControllersLock,
456 gIOInterruptControllers, THREAD_UNINT);
457 }
458
459 IOLockUnlock(gIOInterruptControllersLock);
460 return OSDynamicCast(IOInterruptController, object);
461}
462
463
464void
465IOPlatformExpert::setCPUInterruptProperties(IOService *service)
466{
467 IOInterruptController *controller;
468
469 OSDictionary *matching = serviceMatching("IOInterruptController");
470 matching = propertyMatching(gPlatformInterruptControllerName, kOSBooleanTrue, matching);
471
472 controller = OSDynamicCast(IOInterruptController, waitForService(matching));
473 if (controller) {
474 controller->setCPUInterruptProperties(service);
475 }
476}
477
478bool
479IOPlatformExpert::atInterruptLevel(void)
480{
481 return ml_at_interrupt_context();
482}
483
484bool
485IOPlatformExpert::platformAdjustService(IOService */*service*/)
486{
487 return true;
488}
489
490void
491IOPlatformExpert::getUTCTimeOfDay(clock_sec_t * secs, clock_nsec_t * nsecs)
492{
493 *secs = getGMTTimeOfDay();
494 *nsecs = 0;
495}
496
497void
498IOPlatformExpert::setUTCTimeOfDay(clock_sec_t secs, __unused clock_nsec_t nsecs)
499{
500 setGMTTimeOfDay(secs);
501}
502
503
504//*********************************************************************************
505// PMLog
506//
507//*********************************************************************************
508
509void
510IOPlatformExpert::
511PMLog(const char *who, unsigned long event,
512 unsigned long param1, unsigned long param2)
513{
514 clock_sec_t nows;
515 clock_usec_t nowus;
516 clock_get_system_microtime(&nows, &nowus);
517 nowus += (nows % 1000) * 1000000;
518
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
522}
523
524
525//*********************************************************************************
526// PMInstantiatePowerDomains
527//
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//*********************************************************************************
533
534void
535IOPlatformExpert::PMInstantiatePowerDomains( void )
536{
537 root = new IOPMrootDomain;
538 root->init();
539 root->attach(this);
540 root->start(this);
541}
542
543
544//*********************************************************************************
545// PMRegisterDevice
546//
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//*********************************************************************************
550
551void
552IOPlatformExpert::PMRegisterDevice(IOService * theNub, IOService * theDevice)
553{
554 root->addPowerChild( theDevice );
555}
556
557//*********************************************************************************
558// hasPMFeature
559//
560//*********************************************************************************
561
562bool
563IOPlatformExpert::hasPMFeature(unsigned long featureMask)
564{
565 return (_pePMFeatures & featureMask) != 0;
566}
567
568//*********************************************************************************
569// hasPrivPMFeature
570//
571//*********************************************************************************
572
573bool
574IOPlatformExpert::hasPrivPMFeature(unsigned long privFeatureMask)
575{
576 return (_pePrivPMFeatures & privFeatureMask) != 0;
577}
578
579//*********************************************************************************
580// numBatteriesSupported
581//
582//*********************************************************************************
583
584int
585IOPlatformExpert::numBatteriesSupported(void)
586{
587 return _peNumBatteriesSupported;
588}
589
590//*********************************************************************************
591// CheckSubTree
592//
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//*********************************************************************************
600
601bool
602IOPlatformExpert::CheckSubTree(OSArray * inSubTree, IOService * theNub, IOService * theDevice, OSDictionary * theParent)
603{
604 unsigned int i;
605 unsigned int numPowerTreeNodes;
606 OSDictionary * entry;
607 OSDictionary * matchingDictionary;
608 OSDictionary * providerDictionary;
609 OSDictionary * deviceDictionary;
610 OSDictionary * nubDictionary;
611 OSArray * children;
612 bool nodeFound = false;
613 bool continueSearch = false;
614 bool deviceMatch = false;
615 bool providerMatch = false;
616 bool multiParentMatch = false;
617
618 if ((NULL == theDevice) || (NULL == inSubTree)) {
619 return false;
620 }
621
622 numPowerTreeNodes = inSubTree->getCount();
623
624 // iterate through the power tree to find a home for this device
625
626 for (i = 0; i < numPowerTreeNodes; i++) {
627 entry = (OSDictionary *) inSubTree->getObject(i);
628
629 matchingDictionary = (OSDictionary *) entry->getObject("device");
630 providerDictionary = (OSDictionary *) entry->getObject("provider");
631
632 deviceMatch = true; // if no matching dictionary, this is not a criteria and so must match
633 if (matchingDictionary) {
634 deviceMatch = false;
635 if (NULL != (deviceDictionary = theDevice->dictionaryWithProperties())) {
636 deviceMatch = deviceDictionary->isEqualTo( matchingDictionary, matchingDictionary );
637 deviceDictionary->release();
638 }
639 }
640
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();
647 }
648 }
649
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;
655 }
656 }
657
658 nodeFound = (deviceMatch && providerMatch && multiParentMatch);
659
660 // if the power tree specifies a provider dictionary but theNub is
661 // NULL then we cannot match with this entry.
662
663 if (theNub == NULL && providerDictionary != NULL) {
664 nodeFound = false;
665 }
666
667 // if this node is THE ONE...then register the device
668
669 if (nodeFound) {
670 if (RegisterServiceInTree(theDevice, entry, theParent, theNub)) {
671 if (kIOLogPower & gIOKitDebug) {
672 IOLog("PMRegisterDevice/CheckSubTree - service registered!\n");
673 }
674
675 numInstancesRegistered++;
676
677 // determine if we need to search for additional nodes for this item
678 multipleParentKeyValue = (OSNumber *) entry->getObject("multiple-parent");
679 } else {
680 nodeFound = false;
681 }
682 }
683
684 continueSearch = ((false == nodeFound) || (NULL != multipleParentKeyValue));
685
686 if (continueSearch && (NULL != (children = (OSArray *) entry->getObject("children")))) {
687 nodeFound = CheckSubTree( children, theNub, theDevice, entry );
688 continueSearch = ((false == nodeFound) || (NULL != multipleParentKeyValue));
689 }
690
691 if (false == continueSearch) {
692 break;
693 }
694 }
695
696 return nodeFound;
697}
698
699//*********************************************************************************
700// RegisterServiceInTree
701//
702// Register a device at the specified node of our power tree.
703//*********************************************************************************
704
705bool
706IOPlatformExpert::RegisterServiceInTree(IOService * theService, OSDictionary * theTreeNode, OSDictionary * theTreeParentNode, IOService * theProvider)
707{
708 IOService * aService;
709 bool registered = false;
710 OSArray * children;
711 unsigned int numChildren;
712 OSDictionary * child;
713
714 // make sure someone is not already registered here
715
716 if (NULL == theTreeNode->getObject("service")) {
717 if (theTreeNode->setObject("service", OSDynamicCast( OSObject, theService))) {
718 // 1. CHILDREN ------------------
719
720 // we registered the node in the tree...now if the node has children
721 // registered we must tell this service to add them.
722
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);
729 }
730 }
731 }
732 }
733
734 // 2. PARENT --------------------
735
736 // also we must notify the parent of this node (if a registered service
737 // exists there) of a new child.
738
739 if (theTreeParentNode) {
740 if (NULL != (aService = (IOService *) theTreeParentNode->getObject("service"))) {
741 if (aService != theProvider) {
742 aService->addPowerChild(theService);
743 }
744 }
745 }
746
747 registered = true;
748 }
749 }
750
751 return registered;
752}
753
754//*********************************************************************************
755// printDictionaryKeys
756//
757// Print the keys for the given dictionary and selected contents.
758//*********************************************************************************
759void
760printDictionaryKeys(OSDictionary * inDictionary, char * inMsg)
761{
762 OSCollectionIterator * mcoll = OSCollectionIterator::withCollection(inDictionary);
763 OSSymbol * mkey;
764 OSString * ioClass;
765 unsigned int i = 0;
766
767 mcoll->reset();
768
769 mkey = OSDynamicCast(OSSymbol, mcoll->getNextObject());
770
771 while (mkey) {
772 // kprintf ("dictionary key #%d: %s\n", i, mkey->getCStringNoCopy () );
773
774 // if this is the IOClass key, print it's contents
775
776 if (mkey->isEqualTo("IOClass")) {
777 ioClass = (OSString *) inDictionary->getObject("IOClass");
778 if (ioClass) {
779 IOLog("%s IOClass is %s\n", inMsg, ioClass->getCStringNoCopy());
780 }
781 }
782
783 // if this is an IOProviderClass key print it
784
785 if (mkey->isEqualTo("IOProviderClass")) {
786 ioClass = (OSString *) inDictionary->getObject("IOProviderClass");
787 if (ioClass) {
788 IOLog("%s IOProviderClass is %s\n", inMsg, ioClass->getCStringNoCopy());
789 }
790 }
791
792 // also print IONameMatch keys
793 if (mkey->isEqualTo("IONameMatch")) {
794 ioClass = (OSString *) inDictionary->getObject("IONameMatch");
795 if (ioClass) {
796 IOLog("%s IONameMatch is %s\n", inMsg, ioClass->getCStringNoCopy());
797 }
798 }
799
800 // also print IONameMatched keys
801
802 if (mkey->isEqualTo("IONameMatched")) {
803 ioClass = (OSString *) inDictionary->getObject("IONameMatched");
804 if (ioClass) {
805 IOLog("%s IONameMatched is %s\n", inMsg, ioClass->getCStringNoCopy());
806 }
807 }
808
809#if 0
810 // print clock-id
811
812 if (mkey->isEqualTo("AAPL,clock-id")) {
813 char * cstr;
814 cstr = getCStringForObject(inDictionary->getObject("AAPL,clock-id"));
815 if (cstr) {
816 kprintf(" ===> AAPL,clock-id is %s\n", cstr );
817 }
818 }
819#endif
820
821 // print name
822
823 if (mkey->isEqualTo("name")) {
824 char nameStr[64];
825 nameStr[0] = 0;
826 getCStringForObject(inDictionary->getObject("name"), nameStr,
827 sizeof(nameStr));
828 if (strlen(nameStr) > 0) {
829 IOLog("%s name is %s\n", inMsg, nameStr);
830 }
831 }
832
833 mkey = (OSSymbol *) mcoll->getNextObject();
834
835 i++;
836 }
837
838 mcoll->release();
839}
840
841static void
842getCStringForObject(OSObject *inObj, char *outStr, size_t outStrLen)
843{
844 char * buffer;
845 unsigned int len, i;
846
847 if ((NULL == inObj) || (NULL == outStr)) {
848 return;
849 }
850
851 char * objString = (char *) (inObj->getMetaClass())->getClassName();
852
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];
862 }
863 outStr[len] = 0;
864 }
865 }
866}
867
868/* IOShutdownNotificationsTimedOut
869 * - Called from a timer installed by PEHaltRestart
870 */
871#if !defined(__x86_64)
872__abortlike
873#endif
874static void
875IOShutdownNotificationsTimedOut(
876 thread_call_param_t p0,
877 thread_call_param_t p1)
878{
879#if !defined(__x86_64__)
880 /* 30 seconds has elapsed - panic */
881 panic("Halt/Restart Timed Out");
882
883#else /* !defined(__x86_64__) */
884 int type = (int)(long)p0;
885 uint32_t timeout = (uint32_t)(uintptr_t)p1;
886
887 IOPMrootDomain *pmRootDomain = IOService::getPMRootDomain();
888 if (pmRootDomain) {
889 if ((PEGetCoprocessorVersion() >= kCoprocessorVersion2) || pmRootDomain->checkShutdownTimeout()) {
890 pmRootDomain->panicWithShutdownLog(timeout * 1000);
891 }
892 }
893
894 /* 30 seconds has elapsed - resume shutdown */
895 if (gIOPlatform) {
896 gIOPlatform->haltRestart(type);
897 }
898#endif /* defined(__x86_64__) */
899}
900
901
902extern "C" {
903/*
904 * Callouts from BSD for machine name & model
905 */
906
907/*
908 * PEGetMachineName() and PEGetModelName() are inconsistent across
909 * architectures, and considered deprecated. Use PEGetTargetName() and
910 * PEGetProductName() instead.
911 */
912boolean_t
913PEGetMachineName( char * name, int maxLength )
914{
915 if (gIOPlatform) {
916 return gIOPlatform->getMachineName( name, maxLength );
917 } else {
918 return false;
919 }
920}
921
922/*
923 * PEGetMachineName() and PEGetModelName() are inconsistent across
924 * architectures, and considered deprecated. Use PEGetTargetName() and
925 * PEGetProductName() instead.
926 */
927boolean_t
928PEGetModelName( char * name, int maxLength )
929{
930 if (gIOPlatform) {
931 return gIOPlatform->getModelName( name, maxLength );
932 } else {
933 return false;
934 }
935}
936
937boolean_t
938PEGetTargetName( char * name, int maxLength )
939{
940 if (gIOPlatform) {
941 return gIOPlatform->getTargetName( name, maxLength );
942 } else {
943 return false;
944 }
945}
946
947boolean_t
948PEGetProductName( char * name, int maxLength )
949{
950 if (gIOPlatform) {
951 return gIOPlatform->getProductName( name, maxLength );
952 } else {
953 return false;
954 }
955}
956
957int
958PEGetPlatformEpoch(void)
959{
960 if (gIOPlatform) {
961 return (int) gIOPlatform->getBootROMType();
962 } else {
963 return -1;
964 }
965}
966
967/* Handle necessary platform specific actions prior to panic */
968void
969PEInitiatePanic(void)
970{
971#if defined(__arm64__)
972 /*
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)
975 */
976 flush_mmu_tlb_entry(0);
977#endif
978}
979
980int
981PEHaltRestartInternal(unsigned int type, uint32_t details)
982{
983 IOPMrootDomain *pmRootDomain;
984 AbsoluteTime deadline;
985 thread_call_t shutdown_hang;
986 IORegistryEntry *node;
987 OSData *data;
988 uint32_t timeout = kShutdownTimeout;
989 static boolean_t panic_begin_called = FALSE;
990
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.
994 */
995 if (panic_begin_called) {
996 goto skip_to_haltRestart;
997 }
998
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()
1003 */
1004
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.
1009 */
1010#if defined(__arm__) || defined(__arm64__)
1011#define RESTART_NODE_PATH "/defaults"
1012#else
1013#define RESTART_NODE_PATH "/chosen"
1014#endif
1015 node = IORegistryEntry::fromPath( RESTART_NODE_PATH, gIODTPlane );
1016 if (node) {
1017 data = OSDynamicCast( OSData, node->getProperty( "halt-restart-timeout" ));
1018 if (data && data->getLength() == 4) {
1019 timeout = *((uint32_t *) data->getBytesNoCopy());
1020 }
1021 }
1022
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;
1028 }
1029#endif
1030
1031 if (timeout) {
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 );
1036 }
1037
1038 pmRootDomain->handlePlatformHaltRestart(type);
1039 /* This notification should have few clients who all do
1040 * their work synchronously.
1041 *
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
1045 * replies.
1046 */
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)
1053#endif
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;
1059 }
1060
1061
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)
1072#endif
1073 IOCPURunPlatformPanicActions(type, details);
1074 } else if (type == kPEPanicBegin) {
1075#if defined(__x86_64__)
1076 if (coprocessor_cross_panic_enabled)
1077#endif
1078 {
1079 // Only call the kPEPanicBegin callout once
1080 if (!panic_begin_called) {
1081 panic_begin_called = TRUE;
1082 IOCPURunPlatformPanicActions(type, details);
1083 }
1084 }
1085 } else if (type == kPEPanicDiagnosticsDone) {
1086 IOCPURunPlatformPanicActions(type, details);
1087 }
1088
1089skip_to_haltRestart:
1090 if (gIOPlatform) {
1091 return gIOPlatform->haltRestart(type);
1092 } else {
1093 return -1;
1094 }
1095}
1096
1097int
1098PEHaltRestart(unsigned int type)
1099{
1100 return PEHaltRestartInternal(type, 0);
1101}
1102
1103UInt32
1104PESavePanicInfo(UInt8 *buffer, UInt32 length)
1105{
1106 if (gIOPlatform != NULL) {
1107 return (UInt32) gIOPlatform->savePanicInfo(buffer, length);
1108 } else {
1109 return 0;
1110 }
1111}
1112
1113void
1114PESavePanicInfoAction(void *buffer, UInt32 offset, UInt32 length)
1115{
1116 IOCPURunPlatformPanicSyncAction(buffer, offset, length);
1117 return;
1118}
1119
1120
1121/*
1122 * Depending on the platform, the /options node may not be created
1123 * until after IOKit matching has started, by an externally-supplied
1124 * platform expert subclass. Therefore, we must check for its presence
1125 * here and update gIOOptionsEntry for the platform code as necessary.
1126 */
1127inline static int
1128init_gIOOptionsEntry(void)
1129{
1130 IORegistryEntry *entry;
1131 void *nvram_entry;
1132 volatile void **options;
1133 int ret = -1;
1134
1135 if (gIOOptionsEntry) {
1136 return 0;
1137 }
1138
1139 entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
1140 if (!entry) {
1141 return -1;
1142 }
1143
1144 nvram_entry = (void *) OSDynamicCast(IODTNVRAM, entry);
1145 if (!nvram_entry) {
1146 goto release;
1147 }
1148
1149 options = (volatile void **) &gIOOptionsEntry;
1150 if (!OSCompareAndSwapPtr(NULL, nvram_entry, options)) {
1151 ret = 0;
1152 goto release;
1153 }
1154
1155 return 0;
1156
1157release:
1158 entry->release();
1159 return ret;
1160}
1161
1162/* pass in a NULL value if you just want to figure out the len */
1163boolean_t
1164PEReadNVRAMProperty(const char *symbol, void *value,
1165 unsigned int *len)
1166{
1167 OSObject *obj;
1168 OSData *data;
1169 unsigned int vlen;
1170
1171 if (!symbol || !len) {
1172 goto err;
1173 }
1174
1175 if (init_gIOOptionsEntry() < 0) {
1176 goto err;
1177 }
1178
1179 vlen = *len;
1180 *len = 0;
1181
1182 obj = gIOOptionsEntry->getProperty(symbol);
1183 if (!obj) {
1184 goto err;
1185 }
1186
1187 /* convert to data */
1188 data = OSDynamicCast(OSData, obj);
1189 if (!data) {
1190 goto err;
1191 }
1192
1193 *len = data->getLength();
1194 vlen = min(vlen, *len);
1195 if (value && vlen) {
1196 memcpy((void *) value, data->getBytesNoCopy(), vlen);
1197 }
1198
1199 return TRUE;
1200
1201err:
1202 return FALSE;
1203}
1204
1205boolean_t
1206PEWriteNVRAMBooleanProperty(const char *symbol, boolean_t value)
1207{
1208 const OSSymbol *sym = NULL;
1209 OSBoolean *data = NULL;
1210 bool ret = false;
1211
1212 if (symbol == NULL) {
1213 goto exit;
1214 }
1215
1216 if (init_gIOOptionsEntry() < 0) {
1217 goto exit;
1218 }
1219
1220 if ((sym = OSSymbol::withCStringNoCopy(symbol)) == NULL) {
1221 goto exit;
1222 }
1223
1224 data = value ? kOSBooleanTrue : kOSBooleanFalse;
1225 ret = gIOOptionsEntry->setProperty(sym, data);
1226
1227 sym->release();
1228
1229 /* success, force the NVRAM to flush writes */
1230 if (ret == true) {
1231 gIOOptionsEntry->sync();
1232 }
1233
1234exit:
1235 return ret;
1236}
1237
1238static boolean_t
1239PEWriteNVRAMPropertyInternal(const char *symbol, boolean_t copySymbol, const void *value,
1240 const unsigned int len)
1241{
1242 const OSSymbol *sym;
1243 OSData *data;
1244 bool ret = false;
1245
1246 if (!symbol || !value || !len) {
1247 goto err;
1248 }
1249
1250 if (init_gIOOptionsEntry() < 0) {
1251 goto err;
1252 }
1253
1254 if (copySymbol == TRUE) {
1255 sym = OSSymbol::withCString(symbol);
1256 } else {
1257 sym = OSSymbol::withCStringNoCopy(symbol);
1258 }
1259
1260 if (!sym) {
1261 goto err;
1262 }
1263
1264 data = OSData::withBytes((void *) value, len);
1265 if (!data) {
1266 goto sym_done;
1267 }
1268
1269 ret = gIOOptionsEntry->setProperty(sym, data);
1270 data->release();
1271
1272sym_done:
1273 sym->release();
1274
1275 if (ret == true) {
1276 gIOOptionsEntry->sync();
1277 return TRUE;
1278 }
1279
1280err:
1281 return FALSE;
1282}
1283
1284boolean_t
1285PEWriteNVRAMProperty(const char *symbol, const void *value,
1286 const unsigned int len)
1287{
1288 return PEWriteNVRAMPropertyInternal(symbol, FALSE, value, len);
1289}
1290
1291boolean_t
1292PEWriteNVRAMPropertyWithCopy(const char *symbol, const void *value,
1293 const unsigned int len)
1294{
1295 return PEWriteNVRAMPropertyInternal(symbol, TRUE, value, len);
1296}
1297
1298boolean_t
1299PERemoveNVRAMProperty(const char *symbol)
1300{
1301 const OSSymbol *sym;
1302
1303 if (!symbol) {
1304 goto err;
1305 }
1306
1307 if (init_gIOOptionsEntry() < 0) {
1308 goto err;
1309 }
1310
1311 sym = OSSymbol::withCStringNoCopy(symbol);
1312 if (!sym) {
1313 goto err;
1314 }
1315
1316 gIOOptionsEntry->removeProperty(sym);
1317
1318 sym->release();
1319
1320 gIOOptionsEntry->sync();
1321 return TRUE;
1322
1323err:
1324 return FALSE;
1325}
1326
1327long
1328PEGetGMTTimeOfDay(void)
1329{
1330 clock_sec_t secs;
1331 clock_usec_t usecs;
1332
1333 PEGetUTCTimeOfDay(&secs, &usecs);
1334 return secs;
1335}
1336
1337void
1338PESetGMTTimeOfDay(long secs)
1339{
1340 PESetUTCTimeOfDay(secs, 0);
1341}
1342
1343void
1344PEGetUTCTimeOfDay(clock_sec_t * secs, clock_usec_t * usecs)
1345{
1346 clock_nsec_t nsecs = 0;
1347
1348 *secs = 0;
1349 if (gIOPlatform) {
1350 gIOPlatform->getUTCTimeOfDay(secs, &nsecs);
1351 }
1352
1353 assert(nsecs < NSEC_PER_SEC);
1354 *usecs = nsecs / NSEC_PER_USEC;
1355}
1356
1357void
1358PESetUTCTimeOfDay(clock_sec_t secs, clock_usec_t usecs)
1359{
1360 assert(usecs < USEC_PER_SEC);
1361 if (gIOPlatform) {
1362 gIOPlatform->setUTCTimeOfDay(secs, usecs * NSEC_PER_USEC);
1363 }
1364}
1365
1366coprocessor_type_t
1367PEGetCoprocessorVersion( void )
1368{
1369 coprocessor_type_t coprocessor_version = kCoprocessorVersionNone;
1370#if defined(__x86_64__)
1371 IORegistryEntry *platform_entry = NULL;
1372 OSData *coprocessor_version_obj = NULL;
1373
1374 platform_entry = IORegistryEntry::fromPath(kIODeviceTreePlane ":/efi/platform");
1375 if (platform_entry != NULL) {
1376 coprocessor_version_obj = OSDynamicCast(OSData, platform_entry->getProperty("apple-coprocessor-version"));
1377 if ((coprocessor_version_obj != NULL) && (coprocessor_version_obj->getLength() <= sizeof(uint64_t))) {
1378 memcpy(&coprocessor_version, coprocessor_version_obj->getBytesNoCopy(), coprocessor_version_obj->getLength());
1379 }
1380 platform_entry->release();
1381 }
1382#endif
1383 return coprocessor_version;
1384}
1385} /* extern "C" */
1386
1387bool gIOPlatformUUIDAndSerialDone = false;
1388
1389void
1390IOPlatformExpert::publishPlatformUUIDAndSerial( void )
1391{
1392 if (!gIOPlatformUUIDAndSerialDone) {
1393 // Parse the serial-number data and publish a user-readable string
1394 if (NULL == getProvider()->getProperty(kIOPlatformSerialNumberKey)) {
1395 OSData* mydata = (OSData*) (getProvider()->getProperty("serial-number"));
1396 if (mydata != NULL) {
1397 OSString *serNoString = createSystemSerialNumberString(mydata);
1398 if (serNoString != NULL) {
1399 getProvider()->setProperty(kIOPlatformSerialNumberKey, serNoString);
1400 serNoString->release();
1401 }
1402 }
1403 }
1404 IOPlatformExpertDevice *provider = OSDynamicCast(IOPlatformExpertDevice, getProvider());
1405 assert(provider != NULL);
1406 provider->generatePlatformUUID();
1407 }
1408
1409 if (gIOPlatformUUIDAndSerialDone) {
1410 publishResource(kIOPlatformUUIDKey, getProvider()->getProperty(kIOPlatformUUIDKey));
1411 }
1412}
1413
1414void
1415IOPlatformExpert::publishNVRAM( void )
1416{
1417 if (init_gIOOptionsEntry() < 0) {
1418 IOPlatformExpertDevice *provider = OSDynamicCast(IOPlatformExpertDevice, getProvider());
1419 assert(provider != NULL);
1420 provider->createNVRAM();
1421 }
1422 if (gIOOptionsEntry != NULL) {
1423 gIOOptionsEntry->registerService();
1424 }
1425}
1426
1427void
1428IOPlatformExpert::registerNVRAMController(IONVRAMController * caller)
1429{
1430#if defined(__x86_64__)
1431 OSData * data;
1432 IORegistryEntry * entry;
1433
1434 /*
1435 * If we have panic debugging enabled and a prod-fused coprocessor,
1436 * disable cross panics so that the co-processor doesn't cause the system
1437 * to reset when we enter the debugger or hit a panic on the x86 side.
1438 */
1439 if (panicDebugging) {
1440 entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
1441 if (entry) {
1442 data = OSDynamicCast( OSData, entry->getProperty( APPLE_VENDOR_VARIABLE_GUID":BridgeOSPanicWatchdogEnabled" ));
1443 if (data && (data->getLength() == sizeof(UInt8))) {
1444 UInt8 *panicWatchdogEnabled = (UInt8 *) data->getBytesNoCopy();
1445 UInt32 debug_flags = 0;
1446 if (*panicWatchdogEnabled || (PE_i_can_has_debugger(&debug_flags) &&
1447 (debug_flags & DB_DISABLE_CROSS_PANIC))) {
1448 coprocessor_cross_panic_enabled = FALSE;
1449 }
1450 }
1451 entry->release();
1452 }
1453 }
1454
1455#if (DEVELOPMENT || DEBUG)
1456 entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
1457 if (entry) {
1458 data = OSDynamicCast( OSData, entry->getProperty(nvram_osenvironment));
1459 if (data) {
1460 sysctl_set_osenvironment(data->getLength(), data->getBytesNoCopy());
1461 entry->removeProperty(nvram_osenvironment);
1462 IODTNVRAM * nvramOptionsEntry = OSDynamicCast(IODTNVRAM, entry);
1463 if (nvramOptionsEntry) {
1464 nvramOptionsEntry->sync();
1465 }
1466 }
1467 entry->release();
1468 }
1469 sysctl_unblock_osenvironment();
1470#endif
1471 /* on intel the UUID must be published after nvram is available */
1472 publishPlatformUUIDAndSerial();
1473
1474#endif /* defined(__x86_64__) */
1475
1476 publishResource("IONVRAM");
1477}
1478
1479IOReturn
1480IOPlatformExpert::callPlatformFunction(const OSSymbol *functionName,
1481 bool waitForFunction,
1482 void *param1, void *param2,
1483 void *param3, void *param4)
1484{
1485 IOService *service, *_resources;
1486
1487 if (functionName == gIOPlatformQuiesceActionKey ||
1488 functionName == gIOPlatformActiveActionKey) {
1489 /*
1490 * Services which register for IOPlatformQuiesceAction / IOPlatformActiveAction
1491 * must consume that event themselves, without passing it up to super/IOPlatformExpert.
1492 */
1493 if (gEnforceQuiesceSafety) {
1494 panic("Class %s passed the quiesce/active action to IOPlatformExpert",
1495 getMetaClass()->getClassName());
1496 }
1497 }
1498
1499 if (waitForFunction) {
1500 _resources = waitForService(resourceMatching(functionName));
1501 } else {
1502 _resources = getResourceService();
1503 }
1504 if (_resources == NULL) {
1505 return kIOReturnUnsupported;
1506 }
1507
1508 service = OSDynamicCast(IOService, _resources->getProperty(functionName));
1509 if (service == NULL) {
1510 return kIOReturnUnsupported;
1511 }
1512
1513 return service->callPlatformFunction(functionName, waitForFunction,
1514 param1, param2, param3, param4);
1515}
1516
1517IOByteCount
1518IOPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length)
1519{
1520 return 0;
1521}
1522
1523/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1524
1525#undef super
1526#define super IOPlatformExpert
1527
1528OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert, IOPlatformExpert )
1529
1530OSMetaClassDefineReservedUnused(IODTPlatformExpert, 0);
1531OSMetaClassDefineReservedUnused(IODTPlatformExpert, 1);
1532OSMetaClassDefineReservedUnused(IODTPlatformExpert, 2);
1533OSMetaClassDefineReservedUnused(IODTPlatformExpert, 3);
1534OSMetaClassDefineReservedUnused(IODTPlatformExpert, 4);
1535OSMetaClassDefineReservedUnused(IODTPlatformExpert, 5);
1536OSMetaClassDefineReservedUnused(IODTPlatformExpert, 6);
1537OSMetaClassDefineReservedUnused(IODTPlatformExpert, 7);
1538
1539/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1540
1541IOService *
1542IODTPlatformExpert::probe( IOService * provider,
1543 SInt32 * score )
1544{
1545 if (!super::probe( provider, score)) {
1546 return NULL;
1547 }
1548
1549 // check machine types
1550 if (!provider->compareNames( getProperty( gIONameMatchKey ))) {
1551 return NULL;
1552 }
1553
1554 return this;
1555}
1556
1557bool
1558IODTPlatformExpert::configure( IOService * provider )
1559{
1560 if (!super::configure( provider)) {
1561 return false;
1562 }
1563
1564 processTopLevel( provider );
1565
1566 return true;
1567}
1568
1569IOService *
1570IODTPlatformExpert::createNub( IORegistryEntry * from )
1571{
1572 IOService * nub;
1573
1574 nub = new IOPlatformDevice;
1575 if (nub) {
1576 if (!nub->init( from, gIODTPlane )) {
1577 nub->free();
1578 nub = NULL;
1579 }
1580 }
1581 return nub;
1582}
1583
1584bool
1585IODTPlatformExpert::createNubs( IOService * parent, OSIterator * iter )
1586{
1587 IORegistryEntry * next;
1588 IOService * nub;
1589 bool ok = true;
1590
1591 if (iter) {
1592 while ((next = (IORegistryEntry *) iter->getNextObject())) {
1593 if (NULL == (nub = createNub( next ))) {
1594 continue;
1595 }
1596
1597 nub->attach( parent );
1598#if !defined(__x86_64__)
1599 OSData *tmpData = (OSData *)next->getProperty("device_type");
1600 if (tmpData == NULL) {
1601 nub->registerService();
1602 continue;
1603 }
1604
1605 char *device_type = (char *)tmpData->getBytesNoCopy();
1606 if (strcmp(device_type, "cpu") != 0) {
1607 nub->registerService();
1608 continue;
1609 }
1610
1611 tmpData = (OSData *)next->getProperty("reg");
1612 assert(tmpData != NULL);
1613 assert(tmpData->getLength() >= sizeof(UInt32));
1614
1615 uint32_t phys_id = *(UInt32 *)tmpData->getBytesNoCopy();
1616 int logical_cpu_id = ml_get_cpu_number(phys_id);
1617 int logical_cluster_id = ml_get_cluster_number(phys_id);
1618
1619 /*
1620 * If the following condition triggers, it means that a CPU that was present in the DT
1621 * was ignored by XNU at topology parsing time. This can happen currently when using the
1622 * cpus=N boot-arg; for example, cpus=1 will cause XNU to parse and enable a single CPU.
1623 *
1624 * Note that this condition will not trigger for harvested cores because these do not show up
1625 * in the DT/IORegistry in the first place.
1626 */
1627 if (logical_cpu_id < 0) {
1628 nub->registerService();
1629 continue;
1630 }
1631
1632 __assert_only bool logical_id_added_to_ioreg = nub->setProperty("logical-cpu-id", logical_cpu_id, 32U);
1633 assert(logical_id_added_to_ioreg == true);
1634 logical_id_added_to_ioreg = nub->setProperty("logical-cluster-id", logical_cluster_id, 32U);
1635 assert(logical_id_added_to_ioreg == true);
1636#endif
1637 nub->registerService();
1638 }
1639 iter->release();
1640 }
1641
1642 return ok;
1643}
1644
1645void
1646IODTPlatformExpert::processTopLevel( IORegistryEntry * rootEntry )
1647{
1648 OSIterator * kids;
1649 IORegistryEntry * next;
1650 IORegistryEntry * cpus;
1651
1652 // infanticide
1653 kids = IODTFindMatchingEntries( rootEntry, 0, deleteList());
1654 if (kids) {
1655 while ((next = (IORegistryEntry *)kids->getNextObject())) {
1656 next->detachAll( gIODTPlane);
1657 }
1658 kids->release();
1659 }
1660
1661 publishNVRAM();
1662 assert(gIOOptionsEntry != NULL); // subclasses that do their own NVRAM initialization shouldn't be calling this
1663 dtNVRAM = gIOOptionsEntry;
1664
1665 // Publish the cpus.
1666 cpus = rootEntry->childFromPath( "cpus", gIODTPlane);
1667 if (cpus) {
1668 createNubs( this, IODTFindMatchingEntries( cpus, kIODTExclusive, NULL));
1669 cpus->release();
1670 }
1671
1672 // publish top level, minus excludeList
1673 createNubs( this, IODTFindMatchingEntries( rootEntry, kIODTExclusive, excludeList()));
1674}
1675
1676IOReturn
1677IODTPlatformExpert::getNubResources( IOService * nub )
1678{
1679 if (nub->getDeviceMemory()) {
1680 return kIOReturnSuccess;
1681 }
1682
1683 IODTResolveAddressing( nub, "reg", NULL);
1684
1685 return kIOReturnSuccess;
1686}
1687
1688bool
1689IODTPlatformExpert::compareNubName( const IOService * nub,
1690 OSString * name, OSString ** matched ) const
1691{
1692 return IODTCompareNubName( nub, name, matched )
1693 || super::compareNubName( nub, name, matched);
1694}
1695
1696
1697/*
1698 * Do not use this method directly, it returns inconsistent results
1699 * across architectures and is considered deprecated.
1700 *
1701 * Use getTargetName and getProductName respectively. For example:
1702 *
1703 * targetName: J137AP
1704 * productName: iMacPro1,1
1705 *
1706 * targetName: D331pAP
1707 * productName: iPhone11,6
1708 */
1709
1710bool
1711IODTPlatformExpert::getModelName( char * name, int maxLength )
1712{
1713 OSData * prop;
1714 const char * str;
1715 int len;
1716 char c;
1717 bool ok = false;
1718
1719 maxLength--;
1720
1721 prop = (OSData *) getProvider()->getProperty( gIODTCompatibleKey );
1722 if (prop) {
1723 str = (const char *) prop->getBytesNoCopy();
1724
1725 if (0 == strncmp( str, "AAPL,", strlen( "AAPL," ))) {
1726 str += strlen( "AAPL," );
1727 }
1728
1729 len = 0;
1730 while ((c = *str++)) {
1731 if ((c == '/') || (c == ' ')) {
1732 c = '-';
1733 }
1734
1735 name[len++] = c;
1736 if (len >= maxLength) {
1737 break;
1738 }
1739 }
1740
1741 name[len] = 0;
1742 ok = true;
1743 }
1744 return ok;
1745}
1746
1747/*
1748 * Do not use this method directly, it returns inconsistent results
1749 * across architectures and is considered deprecated.
1750 *
1751 * Use getTargetName and getProductName respectively. For example:
1752 *
1753 * targetName: J137AP
1754 * productName: iMacPro1,1
1755 *
1756 * targetName: D331pAP
1757 * productName: iPhone11,6
1758 */
1759
1760bool
1761IODTPlatformExpert::getMachineName( char * name, int maxLength )
1762{
1763 OSData * prop;
1764 bool ok = false;
1765
1766 maxLength--;
1767 prop = (OSData *) getProvider()->getProperty( gIODTModelKey );
1768 ok = (NULL != prop);
1769
1770 if (ok) {
1771 strlcpy( name, (const char *) prop->getBytesNoCopy(), maxLength );
1772 }
1773
1774 return ok;
1775}
1776
1777/* Examples: J137AP, D331pAP... */
1778
1779bool
1780IODTPlatformExpert::getTargetName( char * name, int maxLength )
1781{
1782#if __x86_64__
1783 OSData * prop;
1784
1785 const OSSymbol * key = gIODTBridgeModelKey;
1786
1787 maxLength--;
1788 prop = (OSData *) getProvider()->getProperty( key );
1789
1790 if (prop == NULL) {
1791 // This happens if there is no bridge.
1792 char const * const unknown = "";
1793
1794 strlcpy( name, unknown, maxLength );
1795 } else {
1796 strlcpy( name, (const char *)prop->getBytesNoCopy(), maxLength );
1797 }
1798
1799 return true;
1800#else
1801 return getModelName( name, maxLength );
1802#endif
1803}
1804
1805/* Examples: iMacPro1,1, iPhone11,6... */
1806
1807bool
1808IODTPlatformExpert::getProductName( char * name, int maxLength )
1809{
1810#if __x86_64__
1811 return getModelName( name, maxLength );
1812#else
1813 return getMachineName( name, maxLength );
1814#endif
1815}
1816
1817/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1818
1819void
1820IODTPlatformExpert::registerNVRAMController( IONVRAMController * nvram )
1821{
1822 if (dtNVRAM) {
1823 dtNVRAM->registerNVRAMController(nvram);
1824 }
1825
1826 super::registerNVRAMController(nvram);
1827}
1828
1829int
1830IODTPlatformExpert::haltRestart(unsigned int type)
1831{
1832 if (dtNVRAM) {
1833 dtNVRAM->sync();
1834 }
1835
1836 return super::haltRestart(type);
1837}
1838
1839IOReturn
1840IODTPlatformExpert::readXPRAM(IOByteCount offset, UInt8 * buffer,
1841 IOByteCount length)
1842{
1843 if (dtNVRAM) {
1844 return dtNVRAM->readXPRAM(offset, buffer, length);
1845 } else {
1846 return kIOReturnNotReady;
1847 }
1848}
1849
1850IOReturn
1851IODTPlatformExpert::writeXPRAM(IOByteCount offset, UInt8 * buffer,
1852 IOByteCount length)
1853{
1854 if (dtNVRAM) {
1855 return dtNVRAM->writeXPRAM(offset, buffer, length);
1856 } else {
1857 return kIOReturnNotReady;
1858 }
1859}
1860
1861IOReturn
1862IODTPlatformExpert::readNVRAMProperty(
1863 IORegistryEntry * entry,
1864 const OSSymbol ** name, OSData ** value )
1865{
1866 if (dtNVRAM) {
1867 return dtNVRAM->readNVRAMProperty(entry, name, value);
1868 } else {
1869 return kIOReturnNotReady;
1870 }
1871}
1872
1873IOReturn
1874IODTPlatformExpert::readNVRAMProperty(
1875 IORegistryEntry * entry,
1876 OSSharedPtr<const OSSymbol>& name, OSSharedPtr<OSData>& value )
1877{
1878 const OSSymbol* nameRaw = NULL;
1879 OSData* valueRaw = NULL;
1880
1881 IOReturn result = readNVRAMProperty(entry, &nameRaw, &valueRaw);
1882
1883 name.reset(nameRaw, OSNoRetain);
1884 value.reset(valueRaw, OSNoRetain);
1885
1886 return result;
1887}
1888
1889IOReturn
1890IODTPlatformExpert::writeNVRAMProperty(
1891 IORegistryEntry * entry,
1892 const OSSymbol * name, OSData * value )
1893{
1894 if (dtNVRAM) {
1895 return dtNVRAM->writeNVRAMProperty(entry, name, value);
1896 } else {
1897 return kIOReturnNotReady;
1898 }
1899}
1900
1901OSDictionary *
1902IODTPlatformExpert::getNVRAMPartitions(void)
1903{
1904 if (dtNVRAM) {
1905 return dtNVRAM->getNVRAMPartitions();
1906 } else {
1907 return NULL;
1908 }
1909}
1910
1911IOReturn
1912IODTPlatformExpert::readNVRAMPartition(const OSSymbol * partitionID,
1913 IOByteCount offset, UInt8 * buffer,
1914 IOByteCount length)
1915{
1916 if (dtNVRAM) {
1917 return dtNVRAM->readNVRAMPartition(partitionID, offset,
1918 buffer, length);
1919 } else {
1920 return kIOReturnNotReady;
1921 }
1922}
1923
1924IOReturn
1925IODTPlatformExpert::writeNVRAMPartition(const OSSymbol * partitionID,
1926 IOByteCount offset, UInt8 * buffer,
1927 IOByteCount length)
1928{
1929 if (dtNVRAM) {
1930 return dtNVRAM->writeNVRAMPartition(partitionID, offset,
1931 buffer, length);
1932 } else {
1933 return kIOReturnNotReady;
1934 }
1935}
1936
1937IOByteCount
1938IODTPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length)
1939{
1940 IOByteCount lengthSaved = 0;
1941
1942 if (dtNVRAM) {
1943 lengthSaved = dtNVRAM->savePanicInfo(buffer, length);
1944 }
1945
1946 if (lengthSaved == 0) {
1947 lengthSaved = super::savePanicInfo(buffer, length);
1948 }
1949
1950 return lengthSaved;
1951}
1952
1953OSString*
1954IODTPlatformExpert::createSystemSerialNumberString(OSData* myProperty)
1955{
1956 UInt8* serialNumber;
1957 unsigned int serialNumberSize;
1958 unsigned short pos = 0;
1959 char* temp;
1960 char SerialNo[30];
1961
1962 if (myProperty != NULL) {
1963 serialNumberSize = myProperty->getLength();
1964 serialNumber = (UInt8*)(myProperty->getBytesNoCopy());
1965 temp = (char*)serialNumber;
1966 if (serialNumberSize > 0) {
1967 // check to see if this is a CTO serial number...
1968 while (pos < serialNumberSize && temp[pos] != '-') {
1969 pos++;
1970 }
1971
1972 if (pos < serialNumberSize) { // there was a hyphen, so it's a CTO serial number
1973 memcpy(SerialNo, serialNumber + 12, 8);
1974 memcpy(&SerialNo[8], serialNumber, 3);
1975 SerialNo[11] = '-';
1976 memcpy(&SerialNo[12], serialNumber + 3, 8);
1977 SerialNo[20] = 0;
1978 } else { // just a normal serial number
1979 memcpy(SerialNo, serialNumber + 13, 8);
1980 memcpy(&SerialNo[8], serialNumber, 3);
1981 SerialNo[11] = 0;
1982 }
1983 return OSString::withCString(SerialNo);
1984 }
1985 }
1986 return NULL;
1987}
1988
1989
1990/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1991
1992#undef super
1993#define super IOService
1994
1995OSDefineMetaClassAndStructors(IOPlatformExpertDevice, IOService)
1996
1997OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 0);
1998OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 1);
1999OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 2);
2000OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 3);
2001
2002/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003
2004bool
2005IOPlatformExpertDevice::compareName( OSString * name,
2006 OSString ** matched ) const
2007{
2008 return IODTCompareNubName( this, name, matched );
2009}
2010
2011bool
2012IOPlatformExpertDevice::init(void *dtRoot)
2013{
2014 IORegistryEntry * dt = NULL;
2015 bool ok;
2016
2017 if ((dtRoot != NULL) && (dt = IODeviceTreeAlloc(dtRoot))) {
2018 ok = super::init( dt, gIODTPlane );
2019 } else {
2020 ok = super::init();
2021 }
2022
2023 if (!ok) {
2024 return false;
2025 }
2026
2027 return true;
2028}
2029
2030bool
2031IOPlatformExpertDevice::startIOServiceMatching(void)
2032{
2033 workLoop = IOWorkLoop::workLoop();
2034 if (!workLoop) {
2035 return false;
2036 }
2037
2038 registerService();
2039
2040 return true;
2041}
2042
2043IOWorkLoop *
2044IOPlatformExpertDevice::getWorkLoop() const
2045{
2046 return workLoop;
2047}
2048
2049IOReturn
2050IOPlatformExpertDevice::setProperties( OSObject * properties )
2051{
2052 return kIOReturnUnsupported;
2053}
2054
2055IOReturn
2056IOPlatformExpertDevice::newUserClient( task_t owningTask, void * securityID,
2057 UInt32 type, OSDictionary * properties,
2058 IOUserClient ** handler )
2059{
2060 IOReturn err = kIOReturnSuccess;
2061 IOUserClient * newConnect = NULL;
2062 IOUserClient * theConnect = NULL;
2063
2064 switch (type) {
2065 case kIOKitDiagnosticsClientType:
2066 newConnect = IOKitDiagnosticsClient::withTask(owningTask);
2067 if (!newConnect) {
2068 err = kIOReturnNotPermitted;
2069 }
2070 break;
2071 case kIOKitUserServerClientType:
2072 newConnect = IOUserServer::withTask(owningTask);
2073 if (!newConnect) {
2074 err = kIOReturnNotPermitted;
2075 }
2076 break;
2077 default:
2078 err = kIOReturnBadArgument;
2079 }
2080
2081 if (newConnect) {
2082 if ((false == newConnect->attach(this))
2083 || (false == newConnect->start(this))) {
2084 newConnect->detach( this );
2085 newConnect->release();
2086 err = kIOReturnNotPermitted;
2087 } else {
2088 theConnect = newConnect;
2089 }
2090 }
2091
2092 *handler = theConnect;
2093 return err;
2094}
2095
2096void
2097IOPlatformExpertDevice::free()
2098{
2099 if (workLoop) {
2100 workLoop->release();
2101 }
2102}
2103
2104void
2105IOPlatformExpertDevice::configureDefaults( void )
2106{
2107 createNVRAM();
2108 // Parse the serial-number data and publish a user-readable string
2109 OSData* mydata = (OSData*) (getProperty("serial-number"));
2110 if (mydata != NULL) {
2111 OSString *serNoString = OSString::withCString((const char *)mydata->getBytesNoCopy());
2112 if (serNoString != NULL) {
2113 setProperty(kIOPlatformSerialNumberKey, serNoString);
2114 serNoString->release();
2115 }
2116 }
2117 generatePlatformUUID();
2118}
2119
2120void
2121IOPlatformExpertDevice::createNVRAM( void )
2122{
2123 /*
2124 * Publish an IODTNVRAM class on /options, if present.
2125 * DT-based platforms may need NVRAM access prior to the start
2126 * of IOKit matching, to support security-related operations
2127 * that must happen before machine_lockdown().
2128 */
2129 IORegistryEntry *options = IORegistryEntry::fromPath("/options", gIODTPlane);
2130 if (options == NULL) {
2131 return; // /options may not be present
2132 }
2133
2134 assert(gIOOptionsEntry == NULL);
2135 gIOOptionsEntry = new IODTNVRAM;
2136
2137 assert(gIOOptionsEntry != NULL);
2138
2139 gIOOptionsEntry->init(options, gIODTPlane);
2140
2141 gIOOptionsEntry->attach(this);
2142 options->release();
2143}
2144
2145void
2146IOPlatformExpertDevice::generatePlatformUUID( void )
2147{
2148 IORegistryEntry * entry;
2149 OSString * string = NULL;
2150 uuid_string_t uuid;
2151
2152#if !defined(__x86_64__)
2153 entry = IORegistryEntry::fromPath( "/chosen", gIODTPlane );
2154 if (entry) {
2155 OSData * data1;
2156
2157 data1 = OSDynamicCast( OSData, entry->getProperty( "unique-chip-id" ));
2158 if (data1 && data1->getLength() == 8) {
2159 OSData * data2;
2160
2161 data2 = OSDynamicCast( OSData, entry->getProperty( "chip-id" ));
2162 if (data2 && data2->getLength() == 4) {
2163 SHA1_CTX context;
2164 uint8_t digest[SHA_DIGEST_LENGTH];
2165 const uuid_t space = { 0xA6, 0xDD, 0x4C, 0xCB, 0xB5, 0xE8, 0x4A, 0xF5, 0xAC, 0xDD, 0xB6, 0xDC, 0x6A, 0x05, 0x42, 0xB8 };
2166
2167 SHA1Init( &context );
2168 SHA1Update( &context, space, sizeof(space));
2169 SHA1Update( &context, data1->getBytesNoCopy(), data1->getLength());
2170 SHA1Update( &context, data2->getBytesNoCopy(), data2->getLength());
2171 SHA1Final( digest, &context );
2172
2173 digest[6] = (digest[6] & 0x0F) | 0x50;
2174 digest[8] = (digest[8] & 0x3F) | 0x80;
2175
2176 uuid_unparse( digest, uuid );
2177 string = OSString::withCString( uuid );
2178 }
2179 }
2180
2181 entry->release();
2182 }
2183#else /* !defined(__x86_64__) */
2184 OSData * data;
2185
2186 entry = IORegistryEntry::fromPath( "/efi/platform", gIODTPlane );
2187 if (entry) {
2188 data = OSDynamicCast( OSData, entry->getProperty( "system-id" ));
2189 if (data && data->getLength() == 16) {
2190 SHA1_CTX context;
2191 uint8_t digest[SHA_DIGEST_LENGTH];
2192 const uuid_t space = { 0x2A, 0x06, 0x19, 0x90, 0xD3, 0x8D, 0x44, 0x40, 0xA1, 0x39, 0xC4, 0x97, 0x70, 0x37, 0x65, 0xAC };
2193
2194 SHA1Init( &context );
2195 SHA1Update( &context, space, sizeof(space));
2196 SHA1Update( &context, data->getBytesNoCopy(), data->getLength());
2197 SHA1Final( digest, &context );
2198
2199 digest[6] = (digest[6] & 0x0F) | 0x50;
2200 digest[8] = (digest[8] & 0x3F) | 0x80;
2201
2202 uuid_unparse( digest, uuid );
2203 string = OSString::withCString( uuid );
2204 }
2205
2206 entry->release();
2207 }
2208 if (!string) {
2209 /* vmware still runs this path */
2210 entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
2211 if (entry) {
2212 data = OSDynamicCast( OSData, entry->getProperty( "platform-uuid" ));
2213 if (data && data->getLength() == sizeof(uuid_t)) {
2214 uuid_unparse((uint8_t *) data->getBytesNoCopy(), uuid );
2215 string = OSString::withCString( uuid );
2216 }
2217 entry->release();
2218 }
2219 }
2220#endif /* defined(__x86_64__) */
2221
2222 if (string) {
2223 setProperty( kIOPlatformUUIDKey, string );
2224 gIOPlatformUUIDAndSerialDone = true;
2225
2226 string->release();
2227 }
2228}
2229/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2230
2231#undef super
2232#define super IOService
2233
2234OSDefineMetaClassAndStructors(IOPlatformDevice, IOService)
2235
2236OSMetaClassDefineReservedUnused(IOPlatformDevice, 0);
2237OSMetaClassDefineReservedUnused(IOPlatformDevice, 1);
2238OSMetaClassDefineReservedUnused(IOPlatformDevice, 2);
2239OSMetaClassDefineReservedUnused(IOPlatformDevice, 3);
2240
2241/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2242
2243bool
2244IOPlatformDevice::compareName( OSString * name,
2245 OSString ** matched ) const
2246{
2247 return ((IOPlatformExpert *)getProvider())->
2248 compareNubName( this, name, matched );
2249}
2250
2251IOService *
2252IOPlatformDevice::matchLocation( IOService * /* client */ )
2253{
2254 return this;
2255}
2256
2257IOReturn
2258IOPlatformDevice::getResources( void )
2259{
2260 return ((IOPlatformExpert *)getProvider())->getNubResources( this );
2261}
2262
2263/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2264
2265/*********************************************************************
2266* IOPanicPlatform class
2267*
2268* If no legitimate IOPlatformDevice matches, this one does and panics
2269* the kernel with a suitable message.
2270*********************************************************************/
2271
2272class IOPanicPlatform : IOPlatformExpert {
2273 OSDeclareDefaultStructors(IOPanicPlatform);
2274
2275public:
2276 bool start(IOService * provider) APPLE_KEXT_OVERRIDE;
2277};
2278
2279
2280OSDefineMetaClassAndStructors(IOPanicPlatform, IOPlatformExpert);
2281
2282
2283bool
2284IOPanicPlatform::start(IOService * provider)
2285{
2286 const char * platform_name = "(unknown platform name)";
2287
2288 if (provider) {
2289 platform_name = provider->getName();
2290 }
2291
2292 panic("Unable to find driver for this platform: \"%s\".\n",
2293 platform_name);
2294
2295 return false;
2296}