]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOPlatformExpert.cpp
xnu-7195.60.75.tar.gz
[apple/xnu.git] / iokit / Kernel / IOPlatformExpert.cpp
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
60 extern "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
71 boolean_t coprocessor_cross_panic_enabled = TRUE;
72 #define APPLE_VENDOR_VARIABLE_GUID "4d1ede05-38c7-4a6a-9cc6-4bcca8b38c14"
73 #endif /* defined(XNU_TARGET_OS_OSX) */
74
75 void printDictionaryKeys(OSDictionary * inDictionary, char * inMsg);
76 static 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 */
87 uint32_t gEnforceQuiesceSafety = 0;
88
89 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
90
91 #define super IOService
92
93 OSDefineMetaClassAndStructors(IOPlatformExpert, IOService)
94
95 OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 0);
96 OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 1);
97 OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 2);
98 OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 3);
99 OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 4);
100 OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 5);
101 OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 6);
102
103 OSMetaClassDefineReservedUnused(IOPlatformExpert, 7);
104 OSMetaClassDefineReservedUnused(IOPlatformExpert, 8);
105 OSMetaClassDefineReservedUnused(IOPlatformExpert, 9);
106 OSMetaClassDefineReservedUnused(IOPlatformExpert, 10);
107 OSMetaClassDefineReservedUnused(IOPlatformExpert, 11);
108
109 static IOPlatformExpert * gIOPlatform;
110 static OSDictionary * gIOInterruptControllers;
111 static IOLock * gIOInterruptControllersLock;
112 static IODTNVRAM *gIOOptionsEntry;
113
114 OSSymbol * gPlatformInterruptControllerName;
115
116 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
117
118 bool
119 IOPlatformExpert::attach( IOService * provider )
120 {
121 if (!super::attach( provider )) {
122 return false;
123 }
124
125 return true;
126 }
127
128 bool
129 IOPlatformExpert::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
196 bool
197 IOPlatformExpert::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
223 IOService *
224 IOPlatformExpert::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
238 bool
239 IOPlatformExpert::compareNubName( const IOService * nub,
240 OSString * name, OSString ** matched ) const
241 {
242 return nub->IORegistryEntry::compareName( name, matched );
243 }
244
245 bool
246 IOPlatformExpert::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
255 IOReturn
256 IOPlatformExpert::getNubResources( IOService * nub )
257 {
258 return kIOReturnSuccess;
259 }
260
261 long
262 IOPlatformExpert::getBootROMType(void)
263 {
264 return _peBootROMType;
265 }
266
267 long
268 IOPlatformExpert::getChipSetType(void)
269 {
270 return _peChipSetType;
271 }
272
273 long
274 IOPlatformExpert::getMachineType(void)
275 {
276 return _peMachineType;
277 }
278
279 void
280 IOPlatformExpert::setBootROMType(long peBootROMType)
281 {
282 _peBootROMType = peBootROMType;
283 }
284
285 void
286 IOPlatformExpert::setChipSetType(long peChipSetType)
287 {
288 _peChipSetType = peChipSetType;
289 }
290
291 void
292 IOPlatformExpert::setMachineType(long peMachineType)
293 {
294 _peMachineType = peMachineType;
295 }
296
297 bool
298 IOPlatformExpert::getMachineName( char * /*name*/, int /*maxLength*/)
299 {
300 return false;
301 }
302
303 bool
304 IOPlatformExpert::getModelName( char * /*name*/, int /*maxLength*/)
305 {
306 return false;
307 }
308
309 bool
310 IOPlatformExpert::getTargetName( char * /*name*/, int /*maxLength*/)
311 {
312 return false;
313 }
314
315 bool
316 IOPlatformExpert::getProductName( char * /*name*/, int /*maxLength*/)
317 {
318 return false;
319 }
320
321 OSString*
322 IOPlatformExpert::createSystemSerialNumberString(OSData* myProperty)
323 {
324 return NULL;
325 }
326
327 IORangeAllocator *
328 IOPlatformExpert::getPhysicalRangeAllocator(void)
329 {
330 return OSDynamicCast(IORangeAllocator,
331 getProperty("Platform Memory Ranges"));
332 }
333
334 int (*PE_halt_restart)(unsigned int type) = NULL;
335
336 int
337 IOPlatformExpert::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
367 void
368 IOPlatformExpert::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
390 long
391 IOPlatformExpert::getGMTTimeOfDay(void)
392 {
393 return 0;
394 }
395
396 void
397 IOPlatformExpert::setGMTTimeOfDay(long secs)
398 {
399 }
400
401
402 IOReturn
403 IOPlatformExpert::getConsoleInfo( PE_Video * consoleInfo )
404 {
405 return PE_current_console( consoleInfo);
406 }
407
408 IOReturn
409 IOPlatformExpert::setConsoleInfo( PE_Video * consoleInfo,
410 unsigned int op)
411 {
412 return PE_initialize_console( consoleInfo, op );
413 }
414
415 IOReturn
416 IOPlatformExpert::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
430 IOReturn
431 IOPlatformExpert::deregisterInterruptController(OSSymbol *name)
432 {
433 IOLockLock(gIOInterruptControllersLock);
434
435 gIOInterruptControllers->removeObject(name);
436
437 IOLockUnlock(gIOInterruptControllersLock);
438
439 return kIOReturnSuccess;
440 }
441
442 IOInterruptController *
443 IOPlatformExpert::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
464 void
465 IOPlatformExpert::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
478 bool
479 IOPlatformExpert::atInterruptLevel(void)
480 {
481 return ml_at_interrupt_context();
482 }
483
484 bool
485 IOPlatformExpert::platformAdjustService(IOService */*service*/)
486 {
487 return true;
488 }
489
490 void
491 IOPlatformExpert::getUTCTimeOfDay(clock_sec_t * secs, clock_nsec_t * nsecs)
492 {
493 *secs = getGMTTimeOfDay();
494 *nsecs = 0;
495 }
496
497 void
498 IOPlatformExpert::setUTCTimeOfDay(clock_sec_t secs, __unused clock_nsec_t nsecs)
499 {
500 setGMTTimeOfDay(secs);
501 }
502
503
504 //*********************************************************************************
505 // PMLog
506 //
507 //*********************************************************************************
508
509 void
510 IOPlatformExpert::
511 PMLog(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
534 void
535 IOPlatformExpert::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
551 void
552 IOPlatformExpert::PMRegisterDevice(IOService * theNub, IOService * theDevice)
553 {
554 root->addPowerChild( theDevice );
555 }
556
557 //*********************************************************************************
558 // hasPMFeature
559 //
560 //*********************************************************************************
561
562 bool
563 IOPlatformExpert::hasPMFeature(unsigned long featureMask)
564 {
565 return (_pePMFeatures & featureMask) != 0;
566 }
567
568 //*********************************************************************************
569 // hasPrivPMFeature
570 //
571 //*********************************************************************************
572
573 bool
574 IOPlatformExpert::hasPrivPMFeature(unsigned long privFeatureMask)
575 {
576 return (_pePrivPMFeatures & privFeatureMask) != 0;
577 }
578
579 //*********************************************************************************
580 // numBatteriesSupported
581 //
582 //*********************************************************************************
583
584 int
585 IOPlatformExpert::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
601 bool
602 IOPlatformExpert::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
705 bool
706 IOPlatformExpert::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 //*********************************************************************************
759 void
760 printDictionaryKeys(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
841 static void
842 getCStringForObject(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
874 static void
875 IOShutdownNotificationsTimedOut(
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
902 extern "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 */
912 boolean_t
913 PEGetMachineName( 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 */
927 boolean_t
928 PEGetModelName( char * name, int maxLength )
929 {
930 if (gIOPlatform) {
931 return gIOPlatform->getModelName( name, maxLength );
932 } else {
933 return false;
934 }
935 }
936
937 boolean_t
938 PEGetTargetName( char * name, int maxLength )
939 {
940 if (gIOPlatform) {
941 return gIOPlatform->getTargetName( name, maxLength );
942 } else {
943 return false;
944 }
945 }
946
947 boolean_t
948 PEGetProductName( char * name, int maxLength )
949 {
950 if (gIOPlatform) {
951 return gIOPlatform->getProductName( name, maxLength );
952 } else {
953 return false;
954 }
955 }
956
957 int
958 PEGetPlatformEpoch(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 */
968 void
969 PEInitiatePanic(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
980 int
981 PEHaltRestartInternal(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 }
1086
1087 skip_to_haltRestart:
1088 if (gIOPlatform) {
1089 return gIOPlatform->haltRestart(type);
1090 } else {
1091 return -1;
1092 }
1093 }
1094
1095 int
1096 PEHaltRestart(unsigned int type)
1097 {
1098 return PEHaltRestartInternal(type, 0);
1099 }
1100
1101 UInt32
1102 PESavePanicInfo(UInt8 *buffer, UInt32 length)
1103 {
1104 if (gIOPlatform != NULL) {
1105 return (UInt32) gIOPlatform->savePanicInfo(buffer, length);
1106 } else {
1107 return 0;
1108 }
1109 }
1110
1111 void
1112 PESavePanicInfoAction(void *buffer, UInt32 offset, UInt32 length)
1113 {
1114 IOCPURunPlatformPanicSyncAction(buffer, offset, length);
1115 return;
1116 }
1117
1118
1119 /*
1120 * Depending on the platform, the /options node may not be created
1121 * until after IOKit matching has started, by an externally-supplied
1122 * platform expert subclass. Therefore, we must check for its presence
1123 * here and update gIOOptionsEntry for the platform code as necessary.
1124 */
1125 inline static int
1126 init_gIOOptionsEntry(void)
1127 {
1128 IORegistryEntry *entry;
1129 void *nvram_entry;
1130 volatile void **options;
1131 int ret = -1;
1132
1133 if (gIOOptionsEntry) {
1134 return 0;
1135 }
1136
1137 entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
1138 if (!entry) {
1139 return -1;
1140 }
1141
1142 nvram_entry = (void *) OSDynamicCast(IODTNVRAM, entry);
1143 if (!nvram_entry) {
1144 goto release;
1145 }
1146
1147 options = (volatile void **) &gIOOptionsEntry;
1148 if (!OSCompareAndSwapPtr(NULL, nvram_entry, options)) {
1149 ret = 0;
1150 goto release;
1151 }
1152
1153 return 0;
1154
1155 release:
1156 entry->release();
1157 return ret;
1158 }
1159
1160 /* pass in a NULL value if you just want to figure out the len */
1161 boolean_t
1162 PEReadNVRAMProperty(const char *symbol, void *value,
1163 unsigned int *len)
1164 {
1165 OSObject *obj;
1166 OSData *data;
1167 unsigned int vlen;
1168
1169 if (!symbol || !len) {
1170 goto err;
1171 }
1172
1173 if (init_gIOOptionsEntry() < 0) {
1174 goto err;
1175 }
1176
1177 vlen = *len;
1178 *len = 0;
1179
1180 obj = gIOOptionsEntry->getProperty(symbol);
1181 if (!obj) {
1182 goto err;
1183 }
1184
1185 /* convert to data */
1186 data = OSDynamicCast(OSData, obj);
1187 if (!data) {
1188 goto err;
1189 }
1190
1191 *len = data->getLength();
1192 vlen = min(vlen, *len);
1193 if (value && vlen) {
1194 memcpy((void *) value, data->getBytesNoCopy(), vlen);
1195 }
1196
1197 return TRUE;
1198
1199 err:
1200 return FALSE;
1201 }
1202
1203 boolean_t
1204 PEWriteNVRAMBooleanProperty(const char *symbol, boolean_t value)
1205 {
1206 const OSSymbol *sym = NULL;
1207 OSBoolean *data = NULL;
1208 bool ret = false;
1209
1210 if (symbol == NULL) {
1211 goto exit;
1212 }
1213
1214 if (init_gIOOptionsEntry() < 0) {
1215 goto exit;
1216 }
1217
1218 if ((sym = OSSymbol::withCStringNoCopy(symbol)) == NULL) {
1219 goto exit;
1220 }
1221
1222 data = value ? kOSBooleanTrue : kOSBooleanFalse;
1223 ret = gIOOptionsEntry->setProperty(sym, data);
1224
1225 sym->release();
1226
1227 /* success, force the NVRAM to flush writes */
1228 if (ret == true) {
1229 gIOOptionsEntry->sync();
1230 }
1231
1232 exit:
1233 return ret;
1234 }
1235
1236 static boolean_t
1237 PEWriteNVRAMPropertyInternal(const char *symbol, boolean_t copySymbol, const void *value,
1238 const unsigned int len)
1239 {
1240 const OSSymbol *sym;
1241 OSData *data;
1242 bool ret = false;
1243
1244 if (!symbol || !value || !len) {
1245 goto err;
1246 }
1247
1248 if (init_gIOOptionsEntry() < 0) {
1249 goto err;
1250 }
1251
1252 if (copySymbol == TRUE) {
1253 sym = OSSymbol::withCString(symbol);
1254 } else {
1255 sym = OSSymbol::withCStringNoCopy(symbol);
1256 }
1257
1258 if (!sym) {
1259 goto err;
1260 }
1261
1262 data = OSData::withBytes((void *) value, len);
1263 if (!data) {
1264 goto sym_done;
1265 }
1266
1267 ret = gIOOptionsEntry->setProperty(sym, data);
1268 data->release();
1269
1270 sym_done:
1271 sym->release();
1272
1273 if (ret == true) {
1274 gIOOptionsEntry->sync();
1275 return TRUE;
1276 }
1277
1278 err:
1279 return FALSE;
1280 }
1281
1282 boolean_t
1283 PEWriteNVRAMProperty(const char *symbol, const void *value,
1284 const unsigned int len)
1285 {
1286 return PEWriteNVRAMPropertyInternal(symbol, FALSE, value, len);
1287 }
1288
1289 boolean_t
1290 PEWriteNVRAMPropertyWithCopy(const char *symbol, const void *value,
1291 const unsigned int len)
1292 {
1293 return PEWriteNVRAMPropertyInternal(symbol, TRUE, value, len);
1294 }
1295
1296 boolean_t
1297 PERemoveNVRAMProperty(const char *symbol)
1298 {
1299 const OSSymbol *sym;
1300
1301 if (!symbol) {
1302 goto err;
1303 }
1304
1305 if (init_gIOOptionsEntry() < 0) {
1306 goto err;
1307 }
1308
1309 sym = OSSymbol::withCStringNoCopy(symbol);
1310 if (!sym) {
1311 goto err;
1312 }
1313
1314 gIOOptionsEntry->removeProperty(sym);
1315
1316 sym->release();
1317
1318 gIOOptionsEntry->sync();
1319 return TRUE;
1320
1321 err:
1322 return FALSE;
1323 }
1324
1325 long
1326 PEGetGMTTimeOfDay(void)
1327 {
1328 clock_sec_t secs;
1329 clock_usec_t usecs;
1330
1331 PEGetUTCTimeOfDay(&secs, &usecs);
1332 return secs;
1333 }
1334
1335 void
1336 PESetGMTTimeOfDay(long secs)
1337 {
1338 PESetUTCTimeOfDay(secs, 0);
1339 }
1340
1341 void
1342 PEGetUTCTimeOfDay(clock_sec_t * secs, clock_usec_t * usecs)
1343 {
1344 clock_nsec_t nsecs = 0;
1345
1346 *secs = 0;
1347 if (gIOPlatform) {
1348 gIOPlatform->getUTCTimeOfDay(secs, &nsecs);
1349 }
1350
1351 assert(nsecs < NSEC_PER_SEC);
1352 *usecs = nsecs / NSEC_PER_USEC;
1353 }
1354
1355 void
1356 PESetUTCTimeOfDay(clock_sec_t secs, clock_usec_t usecs)
1357 {
1358 assert(usecs < USEC_PER_SEC);
1359 if (gIOPlatform) {
1360 gIOPlatform->setUTCTimeOfDay(secs, usecs * NSEC_PER_USEC);
1361 }
1362 }
1363
1364 coprocessor_type_t
1365 PEGetCoprocessorVersion( void )
1366 {
1367 coprocessor_type_t coprocessor_version = kCoprocessorVersionNone;
1368 #if defined(__x86_64__)
1369 IORegistryEntry *platform_entry = NULL;
1370 OSData *coprocessor_version_obj = NULL;
1371
1372 platform_entry = IORegistryEntry::fromPath(kIODeviceTreePlane ":/efi/platform");
1373 if (platform_entry != NULL) {
1374 coprocessor_version_obj = OSDynamicCast(OSData, platform_entry->getProperty("apple-coprocessor-version"));
1375 if ((coprocessor_version_obj != NULL) && (coprocessor_version_obj->getLength() <= sizeof(uint64_t))) {
1376 memcpy(&coprocessor_version, coprocessor_version_obj->getBytesNoCopy(), coprocessor_version_obj->getLength());
1377 }
1378 platform_entry->release();
1379 }
1380 #endif
1381 return coprocessor_version;
1382 }
1383 } /* extern "C" */
1384
1385 bool gIOPlatformUUIDAndSerialDone = false;
1386
1387 void
1388 IOPlatformExpert::publishPlatformUUIDAndSerial( void )
1389 {
1390 if (!gIOPlatformUUIDAndSerialDone) {
1391 // Parse the serial-number data and publish a user-readable string
1392 if (NULL == getProvider()->getProperty(kIOPlatformSerialNumberKey)) {
1393 OSData* mydata = (OSData*) (getProvider()->getProperty("serial-number"));
1394 if (mydata != NULL) {
1395 OSString *serNoString = createSystemSerialNumberString(mydata);
1396 if (serNoString != NULL) {
1397 getProvider()->setProperty(kIOPlatformSerialNumberKey, serNoString);
1398 serNoString->release();
1399 }
1400 }
1401 }
1402 IOPlatformExpertDevice *provider = OSDynamicCast(IOPlatformExpertDevice, getProvider());
1403 assert(provider != NULL);
1404 provider->generatePlatformUUID();
1405 }
1406
1407 if (gIOPlatformUUIDAndSerialDone) {
1408 publishResource(kIOPlatformUUIDKey, getProvider()->getProperty(kIOPlatformUUIDKey));
1409 }
1410 }
1411
1412 void
1413 IOPlatformExpert::publishNVRAM( void )
1414 {
1415 if (init_gIOOptionsEntry() < 0) {
1416 IOPlatformExpertDevice *provider = OSDynamicCast(IOPlatformExpertDevice, getProvider());
1417 assert(provider != NULL);
1418 provider->createNVRAM();
1419 }
1420 if (gIOOptionsEntry != NULL) {
1421 gIOOptionsEntry->registerService();
1422 }
1423 }
1424
1425 void
1426 IOPlatformExpert::registerNVRAMController(IONVRAMController * caller)
1427 {
1428 #if defined(__x86_64__)
1429 OSData * data;
1430 IORegistryEntry * entry;
1431
1432 /*
1433 * If we have panic debugging enabled and a prod-fused coprocessor,
1434 * disable cross panics so that the co-processor doesn't cause the system
1435 * to reset when we enter the debugger or hit a panic on the x86 side.
1436 */
1437 if (panicDebugging) {
1438 entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
1439 if (entry) {
1440 data = OSDynamicCast( OSData, entry->getProperty( APPLE_VENDOR_VARIABLE_GUID":BridgeOSPanicWatchdogEnabled" ));
1441 if (data && (data->getLength() == sizeof(UInt8))) {
1442 UInt8 *panicWatchdogEnabled = (UInt8 *) data->getBytesNoCopy();
1443 UInt32 debug_flags = 0;
1444 if (*panicWatchdogEnabled || (PE_i_can_has_debugger(&debug_flags) &&
1445 (debug_flags & DB_DISABLE_CROSS_PANIC))) {
1446 coprocessor_cross_panic_enabled = FALSE;
1447 }
1448 }
1449 entry->release();
1450 }
1451 }
1452
1453 #if (DEVELOPMENT || DEBUG)
1454 entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
1455 if (entry) {
1456 data = OSDynamicCast( OSData, entry->getProperty(nvram_osenvironment));
1457 if (data) {
1458 sysctl_set_osenvironment(data->getLength(), data->getBytesNoCopy());
1459 entry->removeProperty(nvram_osenvironment);
1460 IODTNVRAM * nvramOptionsEntry = OSDynamicCast(IODTNVRAM, entry);
1461 if (nvramOptionsEntry) {
1462 nvramOptionsEntry->sync();
1463 }
1464 }
1465 entry->release();
1466 }
1467 sysctl_unblock_osenvironment();
1468 #endif
1469 /* on intel the UUID must be published after nvram is available */
1470 publishPlatformUUIDAndSerial();
1471
1472 #endif /* defined(__x86_64__) */
1473
1474 publishResource("IONVRAM");
1475 }
1476
1477 IOReturn
1478 IOPlatformExpert::callPlatformFunction(const OSSymbol *functionName,
1479 bool waitForFunction,
1480 void *param1, void *param2,
1481 void *param3, void *param4)
1482 {
1483 IOService *service, *_resources;
1484
1485 if (functionName == gIOPlatformQuiesceActionKey ||
1486 functionName == gIOPlatformActiveActionKey) {
1487 /*
1488 * Services which register for IOPlatformQuiesceAction / IOPlatformActiveAction
1489 * must consume that event themselves, without passing it up to super/IOPlatformExpert.
1490 */
1491 if (gEnforceQuiesceSafety) {
1492 panic("Class %s passed the quiesce/active action to IOPlatformExpert",
1493 getMetaClass()->getClassName());
1494 }
1495 }
1496
1497 if (waitForFunction) {
1498 _resources = waitForService(resourceMatching(functionName));
1499 } else {
1500 _resources = getResourceService();
1501 }
1502 if (_resources == NULL) {
1503 return kIOReturnUnsupported;
1504 }
1505
1506 service = OSDynamicCast(IOService, _resources->getProperty(functionName));
1507 if (service == NULL) {
1508 return kIOReturnUnsupported;
1509 }
1510
1511 return service->callPlatformFunction(functionName, waitForFunction,
1512 param1, param2, param3, param4);
1513 }
1514
1515 IOByteCount
1516 IOPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length)
1517 {
1518 return 0;
1519 }
1520
1521 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1522
1523 #undef super
1524 #define super IOPlatformExpert
1525
1526 OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert, IOPlatformExpert )
1527
1528 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 0);
1529 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 1);
1530 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 2);
1531 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 3);
1532 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 4);
1533 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 5);
1534 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 6);
1535 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 7);
1536
1537 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1538
1539 IOService *
1540 IODTPlatformExpert::probe( IOService * provider,
1541 SInt32 * score )
1542 {
1543 if (!super::probe( provider, score)) {
1544 return NULL;
1545 }
1546
1547 // check machine types
1548 if (!provider->compareNames( getProperty( gIONameMatchKey ))) {
1549 return NULL;
1550 }
1551
1552 return this;
1553 }
1554
1555 bool
1556 IODTPlatformExpert::configure( IOService * provider )
1557 {
1558 if (!super::configure( provider)) {
1559 return false;
1560 }
1561
1562 processTopLevel( provider );
1563
1564 return true;
1565 }
1566
1567 IOService *
1568 IODTPlatformExpert::createNub( IORegistryEntry * from )
1569 {
1570 IOService * nub;
1571
1572 nub = new IOPlatformDevice;
1573 if (nub) {
1574 if (!nub->init( from, gIODTPlane )) {
1575 nub->free();
1576 nub = NULL;
1577 }
1578 }
1579 return nub;
1580 }
1581
1582 bool
1583 IODTPlatformExpert::createNubs( IOService * parent, OSIterator * iter )
1584 {
1585 IORegistryEntry * next;
1586 IOService * nub;
1587 bool ok = true;
1588
1589 if (iter) {
1590 while ((next = (IORegistryEntry *) iter->getNextObject())) {
1591 if (NULL == (nub = createNub( next ))) {
1592 continue;
1593 }
1594
1595 nub->attach( parent );
1596 #if !defined(__x86_64__)
1597 OSData *tmpData = (OSData *)next->getProperty("device_type");
1598 if (tmpData == NULL) {
1599 nub->registerService();
1600 continue;
1601 }
1602
1603 char *device_type = (char *)tmpData->getBytesNoCopy();
1604 if (strcmp(device_type, "cpu") != 0) {
1605 nub->registerService();
1606 continue;
1607 }
1608
1609 tmpData = (OSData *)next->getProperty("reg");
1610 assert(tmpData != NULL);
1611 assert(tmpData->getLength() >= sizeof(UInt32));
1612
1613 uint32_t phys_id = *(UInt32 *)tmpData->getBytesNoCopy();
1614 int logical_cpu_id = ml_get_cpu_number(phys_id);
1615 int logical_cluster_id = ml_get_cluster_number(phys_id);
1616
1617 /*
1618 * If the following condition triggers, it means that a CPU that was present in the DT
1619 * was ignored by XNU at topology parsing time. This can happen currently when using the
1620 * cpus=N boot-arg; for example, cpus=1 will cause XNU to parse and enable a single CPU.
1621 *
1622 * Note that this condition will not trigger for harvested cores because these do not show up
1623 * in the DT/IORegistry in the first place.
1624 */
1625 if (logical_cpu_id < 0) {
1626 nub->registerService();
1627 continue;
1628 }
1629
1630 __assert_only bool logical_id_added_to_ioreg = nub->setProperty("logical-cpu-id", logical_cpu_id, 32U);
1631 assert(logical_id_added_to_ioreg == true);
1632 logical_id_added_to_ioreg = nub->setProperty("logical-cluster-id", logical_cluster_id, 32U);
1633 assert(logical_id_added_to_ioreg == true);
1634 #endif
1635 nub->registerService();
1636 }
1637 iter->release();
1638 }
1639
1640 return ok;
1641 }
1642
1643 void
1644 IODTPlatformExpert::processTopLevel( IORegistryEntry * rootEntry )
1645 {
1646 OSIterator * kids;
1647 IORegistryEntry * next;
1648 IORegistryEntry * cpus;
1649
1650 // infanticide
1651 kids = IODTFindMatchingEntries( rootEntry, 0, deleteList());
1652 if (kids) {
1653 while ((next = (IORegistryEntry *)kids->getNextObject())) {
1654 next->detachAll( gIODTPlane);
1655 }
1656 kids->release();
1657 }
1658
1659 publishNVRAM();
1660 assert(gIOOptionsEntry != NULL); // subclasses that do their own NVRAM initialization shouldn't be calling this
1661 dtNVRAM = gIOOptionsEntry;
1662
1663 // Publish the cpus.
1664 cpus = rootEntry->childFromPath( "cpus", gIODTPlane);
1665 if (cpus) {
1666 createNubs( this, IODTFindMatchingEntries( cpus, kIODTExclusive, NULL));
1667 cpus->release();
1668 }
1669
1670 // publish top level, minus excludeList
1671 createNubs( this, IODTFindMatchingEntries( rootEntry, kIODTExclusive, excludeList()));
1672 }
1673
1674 IOReturn
1675 IODTPlatformExpert::getNubResources( IOService * nub )
1676 {
1677 if (nub->getDeviceMemory()) {
1678 return kIOReturnSuccess;
1679 }
1680
1681 IODTResolveAddressing( nub, "reg", NULL);
1682
1683 return kIOReturnSuccess;
1684 }
1685
1686 bool
1687 IODTPlatformExpert::compareNubName( const IOService * nub,
1688 OSString * name, OSString ** matched ) const
1689 {
1690 return IODTCompareNubName( nub, name, matched )
1691 || super::compareNubName( nub, name, matched);
1692 }
1693
1694
1695 /*
1696 * Do not use this method directly, it returns inconsistent results
1697 * across architectures and is considered deprecated.
1698 *
1699 * Use getTargetName and getProductName respectively. For example:
1700 *
1701 * targetName: J137AP
1702 * productName: iMacPro1,1
1703 *
1704 * targetName: D331pAP
1705 * productName: iPhone11,6
1706 */
1707
1708 bool
1709 IODTPlatformExpert::getModelName( char * name, int maxLength )
1710 {
1711 OSData * prop;
1712 const char * str;
1713 int len;
1714 char c;
1715 bool ok = false;
1716
1717 maxLength--;
1718
1719 prop = (OSData *) getProvider()->getProperty( gIODTCompatibleKey );
1720 if (prop) {
1721 str = (const char *) prop->getBytesNoCopy();
1722
1723 if (0 == strncmp( str, "AAPL,", strlen( "AAPL," ))) {
1724 str += strlen( "AAPL," );
1725 }
1726
1727 len = 0;
1728 while ((c = *str++)) {
1729 if ((c == '/') || (c == ' ')) {
1730 c = '-';
1731 }
1732
1733 name[len++] = c;
1734 if (len >= maxLength) {
1735 break;
1736 }
1737 }
1738
1739 name[len] = 0;
1740 ok = true;
1741 }
1742 return ok;
1743 }
1744
1745 /*
1746 * Do not use this method directly, it returns inconsistent results
1747 * across architectures and is considered deprecated.
1748 *
1749 * Use getTargetName and getProductName respectively. For example:
1750 *
1751 * targetName: J137AP
1752 * productName: iMacPro1,1
1753 *
1754 * targetName: D331pAP
1755 * productName: iPhone11,6
1756 */
1757
1758 bool
1759 IODTPlatformExpert::getMachineName( char * name, int maxLength )
1760 {
1761 OSData * prop;
1762 bool ok = false;
1763
1764 maxLength--;
1765 prop = (OSData *) getProvider()->getProperty( gIODTModelKey );
1766 ok = (NULL != prop);
1767
1768 if (ok) {
1769 strlcpy( name, (const char *) prop->getBytesNoCopy(), maxLength );
1770 }
1771
1772 return ok;
1773 }
1774
1775 /* Examples: J137AP, D331pAP... */
1776
1777 bool
1778 IODTPlatformExpert::getTargetName( char * name, int maxLength )
1779 {
1780 #if __x86_64__
1781 OSData * prop;
1782
1783 const OSSymbol * key = gIODTBridgeModelKey;
1784
1785 maxLength--;
1786 prop = (OSData *) getProvider()->getProperty( key );
1787
1788 if (prop == NULL) {
1789 // This happens if there is no bridge.
1790 char const * const unknown = "";
1791
1792 strlcpy( name, unknown, maxLength );
1793 } else {
1794 strlcpy( name, (const char *)prop->getBytesNoCopy(), maxLength );
1795 }
1796
1797 return true;
1798 #else
1799 return getModelName( name, maxLength );
1800 #endif
1801 }
1802
1803 /* Examples: iMacPro1,1, iPhone11,6... */
1804
1805 bool
1806 IODTPlatformExpert::getProductName( char * name, int maxLength )
1807 {
1808 #if __x86_64__
1809 return getModelName( name, maxLength );
1810 #else
1811 return getMachineName( name, maxLength );
1812 #endif
1813 }
1814
1815 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1816
1817 void
1818 IODTPlatformExpert::registerNVRAMController( IONVRAMController * nvram )
1819 {
1820 if (dtNVRAM) {
1821 dtNVRAM->registerNVRAMController(nvram);
1822 }
1823
1824 super::registerNVRAMController(nvram);
1825 }
1826
1827 int
1828 IODTPlatformExpert::haltRestart(unsigned int type)
1829 {
1830 if (dtNVRAM) {
1831 dtNVRAM->sync();
1832 }
1833
1834 return super::haltRestart(type);
1835 }
1836
1837 IOReturn
1838 IODTPlatformExpert::readXPRAM(IOByteCount offset, UInt8 * buffer,
1839 IOByteCount length)
1840 {
1841 if (dtNVRAM) {
1842 return dtNVRAM->readXPRAM(offset, buffer, length);
1843 } else {
1844 return kIOReturnNotReady;
1845 }
1846 }
1847
1848 IOReturn
1849 IODTPlatformExpert::writeXPRAM(IOByteCount offset, UInt8 * buffer,
1850 IOByteCount length)
1851 {
1852 if (dtNVRAM) {
1853 return dtNVRAM->writeXPRAM(offset, buffer, length);
1854 } else {
1855 return kIOReturnNotReady;
1856 }
1857 }
1858
1859 IOReturn
1860 IODTPlatformExpert::readNVRAMProperty(
1861 IORegistryEntry * entry,
1862 const OSSymbol ** name, OSData ** value )
1863 {
1864 if (dtNVRAM) {
1865 return dtNVRAM->readNVRAMProperty(entry, name, value);
1866 } else {
1867 return kIOReturnNotReady;
1868 }
1869 }
1870
1871 IOReturn
1872 IODTPlatformExpert::readNVRAMProperty(
1873 IORegistryEntry * entry,
1874 OSSharedPtr<const OSSymbol>& name, OSSharedPtr<OSData>& value )
1875 {
1876 const OSSymbol* nameRaw = NULL;
1877 OSData* valueRaw = NULL;
1878
1879 IOReturn result = readNVRAMProperty(entry, &nameRaw, &valueRaw);
1880
1881 name.reset(nameRaw, OSNoRetain);
1882 value.reset(valueRaw, OSNoRetain);
1883
1884 return result;
1885 }
1886
1887 IOReturn
1888 IODTPlatformExpert::writeNVRAMProperty(
1889 IORegistryEntry * entry,
1890 const OSSymbol * name, OSData * value )
1891 {
1892 if (dtNVRAM) {
1893 return dtNVRAM->writeNVRAMProperty(entry, name, value);
1894 } else {
1895 return kIOReturnNotReady;
1896 }
1897 }
1898
1899 OSDictionary *
1900 IODTPlatformExpert::getNVRAMPartitions(void)
1901 {
1902 if (dtNVRAM) {
1903 return dtNVRAM->getNVRAMPartitions();
1904 } else {
1905 return NULL;
1906 }
1907 }
1908
1909 IOReturn
1910 IODTPlatformExpert::readNVRAMPartition(const OSSymbol * partitionID,
1911 IOByteCount offset, UInt8 * buffer,
1912 IOByteCount length)
1913 {
1914 if (dtNVRAM) {
1915 return dtNVRAM->readNVRAMPartition(partitionID, offset,
1916 buffer, length);
1917 } else {
1918 return kIOReturnNotReady;
1919 }
1920 }
1921
1922 IOReturn
1923 IODTPlatformExpert::writeNVRAMPartition(const OSSymbol * partitionID,
1924 IOByteCount offset, UInt8 * buffer,
1925 IOByteCount length)
1926 {
1927 if (dtNVRAM) {
1928 return dtNVRAM->writeNVRAMPartition(partitionID, offset,
1929 buffer, length);
1930 } else {
1931 return kIOReturnNotReady;
1932 }
1933 }
1934
1935 IOByteCount
1936 IODTPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length)
1937 {
1938 IOByteCount lengthSaved = 0;
1939
1940 if (dtNVRAM) {
1941 lengthSaved = dtNVRAM->savePanicInfo(buffer, length);
1942 }
1943
1944 if (lengthSaved == 0) {
1945 lengthSaved = super::savePanicInfo(buffer, length);
1946 }
1947
1948 return lengthSaved;
1949 }
1950
1951 OSString*
1952 IODTPlatformExpert::createSystemSerialNumberString(OSData* myProperty)
1953 {
1954 UInt8* serialNumber;
1955 unsigned int serialNumberSize;
1956 unsigned short pos = 0;
1957 char* temp;
1958 char SerialNo[30];
1959
1960 if (myProperty != NULL) {
1961 serialNumberSize = myProperty->getLength();
1962 serialNumber = (UInt8*)(myProperty->getBytesNoCopy());
1963 temp = (char*)serialNumber;
1964 if (serialNumberSize > 0) {
1965 // check to see if this is a CTO serial number...
1966 while (pos < serialNumberSize && temp[pos] != '-') {
1967 pos++;
1968 }
1969
1970 if (pos < serialNumberSize) { // there was a hyphen, so it's a CTO serial number
1971 memcpy(SerialNo, serialNumber + 12, 8);
1972 memcpy(&SerialNo[8], serialNumber, 3);
1973 SerialNo[11] = '-';
1974 memcpy(&SerialNo[12], serialNumber + 3, 8);
1975 SerialNo[20] = 0;
1976 } else { // just a normal serial number
1977 memcpy(SerialNo, serialNumber + 13, 8);
1978 memcpy(&SerialNo[8], serialNumber, 3);
1979 SerialNo[11] = 0;
1980 }
1981 return OSString::withCString(SerialNo);
1982 }
1983 }
1984 return NULL;
1985 }
1986
1987
1988 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1989
1990 #undef super
1991 #define super IOService
1992
1993 OSDefineMetaClassAndStructors(IOPlatformExpertDevice, IOService)
1994
1995 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 0);
1996 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 1);
1997 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 2);
1998 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 3);
1999
2000 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001
2002 bool
2003 IOPlatformExpertDevice::compareName( OSString * name,
2004 OSString ** matched ) const
2005 {
2006 return IODTCompareNubName( this, name, matched );
2007 }
2008
2009 bool
2010 IOPlatformExpertDevice::init(void *dtRoot)
2011 {
2012 IORegistryEntry * dt = NULL;
2013 bool ok;
2014
2015 if ((dtRoot != NULL) && (dt = IODeviceTreeAlloc(dtRoot))) {
2016 ok = super::init( dt, gIODTPlane );
2017 } else {
2018 ok = super::init();
2019 }
2020
2021 if (!ok) {
2022 return false;
2023 }
2024
2025 return true;
2026 }
2027
2028 bool
2029 IOPlatformExpertDevice::startIOServiceMatching(void)
2030 {
2031 workLoop = IOWorkLoop::workLoop();
2032 if (!workLoop) {
2033 return false;
2034 }
2035
2036 registerService();
2037
2038 return true;
2039 }
2040
2041 IOWorkLoop *
2042 IOPlatformExpertDevice::getWorkLoop() const
2043 {
2044 return workLoop;
2045 }
2046
2047 IOReturn
2048 IOPlatformExpertDevice::setProperties( OSObject * properties )
2049 {
2050 return kIOReturnUnsupported;
2051 }
2052
2053 IOReturn
2054 IOPlatformExpertDevice::newUserClient( task_t owningTask, void * securityID,
2055 UInt32 type, OSDictionary * properties,
2056 IOUserClient ** handler )
2057 {
2058 IOReturn err = kIOReturnSuccess;
2059 IOUserClient * newConnect = NULL;
2060 IOUserClient * theConnect = NULL;
2061
2062 switch (type) {
2063 case kIOKitDiagnosticsClientType:
2064 newConnect = IOKitDiagnosticsClient::withTask(owningTask);
2065 if (!newConnect) {
2066 err = kIOReturnNotPermitted;
2067 }
2068 break;
2069 case kIOKitUserServerClientType:
2070 newConnect = IOUserServer::withTask(owningTask);
2071 if (!newConnect) {
2072 err = kIOReturnNotPermitted;
2073 }
2074 break;
2075 default:
2076 err = kIOReturnBadArgument;
2077 }
2078
2079 if (newConnect) {
2080 if ((false == newConnect->attach(this))
2081 || (false == newConnect->start(this))) {
2082 newConnect->detach( this );
2083 newConnect->release();
2084 err = kIOReturnNotPermitted;
2085 } else {
2086 theConnect = newConnect;
2087 }
2088 }
2089
2090 *handler = theConnect;
2091 return err;
2092 }
2093
2094 void
2095 IOPlatformExpertDevice::free()
2096 {
2097 if (workLoop) {
2098 workLoop->release();
2099 }
2100 }
2101
2102 void
2103 IOPlatformExpertDevice::configureDefaults( void )
2104 {
2105 createNVRAM();
2106 // Parse the serial-number data and publish a user-readable string
2107 OSData* mydata = (OSData*) (getProperty("serial-number"));
2108 if (mydata != NULL) {
2109 OSString *serNoString = OSString::withCString((const char *)mydata->getBytesNoCopy());
2110 if (serNoString != NULL) {
2111 setProperty(kIOPlatformSerialNumberKey, serNoString);
2112 serNoString->release();
2113 }
2114 }
2115 generatePlatformUUID();
2116 }
2117
2118 void
2119 IOPlatformExpertDevice::createNVRAM( void )
2120 {
2121 /*
2122 * Publish an IODTNVRAM class on /options, if present.
2123 * DT-based platforms may need NVRAM access prior to the start
2124 * of IOKit matching, to support security-related operations
2125 * that must happen before machine_lockdown().
2126 */
2127 IORegistryEntry *options = IORegistryEntry::fromPath("/options", gIODTPlane);
2128 if (options == NULL) {
2129 return; // /options may not be present
2130 }
2131
2132 assert(gIOOptionsEntry == NULL);
2133 gIOOptionsEntry = new IODTNVRAM;
2134
2135 assert(gIOOptionsEntry != NULL);
2136
2137 gIOOptionsEntry->init(options, gIODTPlane);
2138
2139 gIOOptionsEntry->attach(this);
2140 options->release();
2141 }
2142
2143 void
2144 IOPlatformExpertDevice::generatePlatformUUID( void )
2145 {
2146 IORegistryEntry * entry;
2147 OSString * string = NULL;
2148 uuid_string_t uuid;
2149
2150 #if !defined(__x86_64__)
2151 entry = IORegistryEntry::fromPath( "/chosen", gIODTPlane );
2152 if (entry) {
2153 OSData * data1;
2154
2155 data1 = OSDynamicCast( OSData, entry->getProperty( "unique-chip-id" ));
2156 if (data1 && data1->getLength() == 8) {
2157 OSData * data2;
2158
2159 data2 = OSDynamicCast( OSData, entry->getProperty( "chip-id" ));
2160 if (data2 && data2->getLength() == 4) {
2161 SHA1_CTX context;
2162 uint8_t digest[SHA_DIGEST_LENGTH];
2163 const uuid_t space = { 0xA6, 0xDD, 0x4C, 0xCB, 0xB5, 0xE8, 0x4A, 0xF5, 0xAC, 0xDD, 0xB6, 0xDC, 0x6A, 0x05, 0x42, 0xB8 };
2164
2165 SHA1Init( &context );
2166 SHA1Update( &context, space, sizeof(space));
2167 SHA1Update( &context, data1->getBytesNoCopy(), data1->getLength());
2168 SHA1Update( &context, data2->getBytesNoCopy(), data2->getLength());
2169 SHA1Final( digest, &context );
2170
2171 digest[6] = (digest[6] & 0x0F) | 0x50;
2172 digest[8] = (digest[8] & 0x3F) | 0x80;
2173
2174 uuid_unparse( digest, uuid );
2175 string = OSString::withCString( uuid );
2176 }
2177 }
2178
2179 entry->release();
2180 }
2181 #else /* !defined(__x86_64__) */
2182 OSData * data;
2183
2184 entry = IORegistryEntry::fromPath( "/efi/platform", gIODTPlane );
2185 if (entry) {
2186 data = OSDynamicCast( OSData, entry->getProperty( "system-id" ));
2187 if (data && data->getLength() == 16) {
2188 SHA1_CTX context;
2189 uint8_t digest[SHA_DIGEST_LENGTH];
2190 const uuid_t space = { 0x2A, 0x06, 0x19, 0x90, 0xD3, 0x8D, 0x44, 0x40, 0xA1, 0x39, 0xC4, 0x97, 0x70, 0x37, 0x65, 0xAC };
2191
2192 SHA1Init( &context );
2193 SHA1Update( &context, space, sizeof(space));
2194 SHA1Update( &context, data->getBytesNoCopy(), data->getLength());
2195 SHA1Final( digest, &context );
2196
2197 digest[6] = (digest[6] & 0x0F) | 0x50;
2198 digest[8] = (digest[8] & 0x3F) | 0x80;
2199
2200 uuid_unparse( digest, uuid );
2201 string = OSString::withCString( uuid );
2202 }
2203
2204 entry->release();
2205 }
2206 if (!string) {
2207 /* vmware still runs this path */
2208 entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
2209 if (entry) {
2210 data = OSDynamicCast( OSData, entry->getProperty( "platform-uuid" ));
2211 if (data && data->getLength() == sizeof(uuid_t)) {
2212 uuid_unparse((uint8_t *) data->getBytesNoCopy(), uuid );
2213 string = OSString::withCString( uuid );
2214 }
2215 entry->release();
2216 }
2217 }
2218 #endif /* defined(__x86_64__) */
2219
2220 if (string) {
2221 setProperty( kIOPlatformUUIDKey, string );
2222 gIOPlatformUUIDAndSerialDone = true;
2223
2224 string->release();
2225 }
2226 }
2227 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2228
2229 #undef super
2230 #define super IOService
2231
2232 OSDefineMetaClassAndStructors(IOPlatformDevice, IOService)
2233
2234 OSMetaClassDefineReservedUnused(IOPlatformDevice, 0);
2235 OSMetaClassDefineReservedUnused(IOPlatformDevice, 1);
2236 OSMetaClassDefineReservedUnused(IOPlatformDevice, 2);
2237 OSMetaClassDefineReservedUnused(IOPlatformDevice, 3);
2238
2239 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2240
2241 bool
2242 IOPlatformDevice::compareName( OSString * name,
2243 OSString ** matched ) const
2244 {
2245 return ((IOPlatformExpert *)getProvider())->
2246 compareNubName( this, name, matched );
2247 }
2248
2249 IOService *
2250 IOPlatformDevice::matchLocation( IOService * /* client */ )
2251 {
2252 return this;
2253 }
2254
2255 IOReturn
2256 IOPlatformDevice::getResources( void )
2257 {
2258 return ((IOPlatformExpert *)getProvider())->getNubResources( this );
2259 }
2260
2261 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2262
2263 /*********************************************************************
2264 * IOPanicPlatform class
2265 *
2266 * If no legitimate IOPlatformDevice matches, this one does and panics
2267 * the kernel with a suitable message.
2268 *********************************************************************/
2269
2270 class IOPanicPlatform : IOPlatformExpert {
2271 OSDeclareDefaultStructors(IOPanicPlatform);
2272
2273 public:
2274 bool start(IOService * provider) APPLE_KEXT_OVERRIDE;
2275 };
2276
2277
2278 OSDefineMetaClassAndStructors(IOPanicPlatform, IOPlatformExpert);
2279
2280
2281 bool
2282 IOPanicPlatform::start(IOService * provider)
2283 {
2284 const char * platform_name = "(unknown platform name)";
2285
2286 if (provider) {
2287 platform_name = provider->getName();
2288 }
2289
2290 panic("Unable to find driver for this platform: \"%s\".\n",
2291 platform_name);
2292
2293 return false;
2294 }