]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOPlatformExpert.cpp
xnu-7195.101.1.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 } else if (type == kPEPanicDiagnosticsDone) {
1086 IOCPURunPlatformPanicActions(type, details);
1087 }
1088
1089 skip_to_haltRestart:
1090 if (gIOPlatform) {
1091 return gIOPlatform->haltRestart(type);
1092 } else {
1093 return -1;
1094 }
1095 }
1096
1097 int
1098 PEHaltRestart(unsigned int type)
1099 {
1100 return PEHaltRestartInternal(type, 0);
1101 }
1102
1103 UInt32
1104 PESavePanicInfo(UInt8 *buffer, UInt32 length)
1105 {
1106 if (gIOPlatform != NULL) {
1107 return (UInt32) gIOPlatform->savePanicInfo(buffer, length);
1108 } else {
1109 return 0;
1110 }
1111 }
1112
1113 void
1114 PESavePanicInfoAction(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 */
1127 inline static int
1128 init_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
1157 release:
1158 entry->release();
1159 return ret;
1160 }
1161
1162 /* pass in a NULL value if you just want to figure out the len */
1163 boolean_t
1164 PEReadNVRAMProperty(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
1201 err:
1202 return FALSE;
1203 }
1204
1205 boolean_t
1206 PEWriteNVRAMBooleanProperty(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
1234 exit:
1235 return ret;
1236 }
1237
1238 static boolean_t
1239 PEWriteNVRAMPropertyInternal(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
1272 sym_done:
1273 sym->release();
1274
1275 if (ret == true) {
1276 gIOOptionsEntry->sync();
1277 return TRUE;
1278 }
1279
1280 err:
1281 return FALSE;
1282 }
1283
1284 boolean_t
1285 PEWriteNVRAMProperty(const char *symbol, const void *value,
1286 const unsigned int len)
1287 {
1288 return PEWriteNVRAMPropertyInternal(symbol, FALSE, value, len);
1289 }
1290
1291 boolean_t
1292 PEWriteNVRAMPropertyWithCopy(const char *symbol, const void *value,
1293 const unsigned int len)
1294 {
1295 return PEWriteNVRAMPropertyInternal(symbol, TRUE, value, len);
1296 }
1297
1298 boolean_t
1299 PERemoveNVRAMProperty(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
1323 err:
1324 return FALSE;
1325 }
1326
1327 long
1328 PEGetGMTTimeOfDay(void)
1329 {
1330 clock_sec_t secs;
1331 clock_usec_t usecs;
1332
1333 PEGetUTCTimeOfDay(&secs, &usecs);
1334 return secs;
1335 }
1336
1337 void
1338 PESetGMTTimeOfDay(long secs)
1339 {
1340 PESetUTCTimeOfDay(secs, 0);
1341 }
1342
1343 void
1344 PEGetUTCTimeOfDay(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
1357 void
1358 PESetUTCTimeOfDay(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
1366 coprocessor_type_t
1367 PEGetCoprocessorVersion( 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
1387 bool gIOPlatformUUIDAndSerialDone = false;
1388
1389 void
1390 IOPlatformExpert::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
1414 void
1415 IOPlatformExpert::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
1427 void
1428 IOPlatformExpert::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
1479 IOReturn
1480 IOPlatformExpert::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
1517 IOByteCount
1518 IOPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length)
1519 {
1520 return 0;
1521 }
1522
1523 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1524
1525 #undef super
1526 #define super IOPlatformExpert
1527
1528 OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert, IOPlatformExpert )
1529
1530 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 0);
1531 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 1);
1532 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 2);
1533 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 3);
1534 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 4);
1535 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 5);
1536 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 6);
1537 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 7);
1538
1539 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1540
1541 IOService *
1542 IODTPlatformExpert::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
1557 bool
1558 IODTPlatformExpert::configure( IOService * provider )
1559 {
1560 if (!super::configure( provider)) {
1561 return false;
1562 }
1563
1564 processTopLevel( provider );
1565
1566 return true;
1567 }
1568
1569 IOService *
1570 IODTPlatformExpert::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
1584 bool
1585 IODTPlatformExpert::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
1645 void
1646 IODTPlatformExpert::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
1676 IOReturn
1677 IODTPlatformExpert::getNubResources( IOService * nub )
1678 {
1679 if (nub->getDeviceMemory()) {
1680 return kIOReturnSuccess;
1681 }
1682
1683 IODTResolveAddressing( nub, "reg", NULL);
1684
1685 return kIOReturnSuccess;
1686 }
1687
1688 bool
1689 IODTPlatformExpert::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
1710 bool
1711 IODTPlatformExpert::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
1760 bool
1761 IODTPlatformExpert::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
1779 bool
1780 IODTPlatformExpert::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
1807 bool
1808 IODTPlatformExpert::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
1819 void
1820 IODTPlatformExpert::registerNVRAMController( IONVRAMController * nvram )
1821 {
1822 if (dtNVRAM) {
1823 dtNVRAM->registerNVRAMController(nvram);
1824 }
1825
1826 super::registerNVRAMController(nvram);
1827 }
1828
1829 int
1830 IODTPlatformExpert::haltRestart(unsigned int type)
1831 {
1832 if (dtNVRAM) {
1833 dtNVRAM->sync();
1834 }
1835
1836 return super::haltRestart(type);
1837 }
1838
1839 IOReturn
1840 IODTPlatformExpert::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
1850 IOReturn
1851 IODTPlatformExpert::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
1861 IOReturn
1862 IODTPlatformExpert::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
1873 IOReturn
1874 IODTPlatformExpert::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
1889 IOReturn
1890 IODTPlatformExpert::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
1901 OSDictionary *
1902 IODTPlatformExpert::getNVRAMPartitions(void)
1903 {
1904 if (dtNVRAM) {
1905 return dtNVRAM->getNVRAMPartitions();
1906 } else {
1907 return NULL;
1908 }
1909 }
1910
1911 IOReturn
1912 IODTPlatformExpert::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
1924 IOReturn
1925 IODTPlatformExpert::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
1937 IOByteCount
1938 IODTPlatformExpert::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
1953 OSString*
1954 IODTPlatformExpert::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
1995 OSDefineMetaClassAndStructors(IOPlatformExpertDevice, IOService)
1996
1997 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 0);
1998 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 1);
1999 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 2);
2000 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 3);
2001
2002 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003
2004 bool
2005 IOPlatformExpertDevice::compareName( OSString * name,
2006 OSString ** matched ) const
2007 {
2008 return IODTCompareNubName( this, name, matched );
2009 }
2010
2011 bool
2012 IOPlatformExpertDevice::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
2030 bool
2031 IOPlatformExpertDevice::startIOServiceMatching(void)
2032 {
2033 workLoop = IOWorkLoop::workLoop();
2034 if (!workLoop) {
2035 return false;
2036 }
2037
2038 registerService();
2039
2040 return true;
2041 }
2042
2043 IOWorkLoop *
2044 IOPlatformExpertDevice::getWorkLoop() const
2045 {
2046 return workLoop;
2047 }
2048
2049 IOReturn
2050 IOPlatformExpertDevice::setProperties( OSObject * properties )
2051 {
2052 return kIOReturnUnsupported;
2053 }
2054
2055 IOReturn
2056 IOPlatformExpertDevice::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
2096 void
2097 IOPlatformExpertDevice::free()
2098 {
2099 if (workLoop) {
2100 workLoop->release();
2101 }
2102 }
2103
2104 void
2105 IOPlatformExpertDevice::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
2120 void
2121 IOPlatformExpertDevice::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
2145 void
2146 IOPlatformExpertDevice::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
2234 OSDefineMetaClassAndStructors(IOPlatformDevice, IOService)
2235
2236 OSMetaClassDefineReservedUnused(IOPlatformDevice, 0);
2237 OSMetaClassDefineReservedUnused(IOPlatformDevice, 1);
2238 OSMetaClassDefineReservedUnused(IOPlatformDevice, 2);
2239 OSMetaClassDefineReservedUnused(IOPlatformDevice, 3);
2240
2241 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2242
2243 bool
2244 IOPlatformDevice::compareName( OSString * name,
2245 OSString ** matched ) const
2246 {
2247 return ((IOPlatformExpert *)getProvider())->
2248 compareNubName( this, name, matched );
2249 }
2250
2251 IOService *
2252 IOPlatformDevice::matchLocation( IOService * /* client */ )
2253 {
2254 return this;
2255 }
2256
2257 IOReturn
2258 IOPlatformDevice::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
2272 class IOPanicPlatform : IOPlatformExpert {
2273 OSDeclareDefaultStructors(IOPanicPlatform);
2274
2275 public:
2276 bool start(IOService * provider) APPLE_KEXT_OVERRIDE;
2277 };
2278
2279
2280 OSDefineMetaClassAndStructors(IOPanicPlatform, IOPlatformExpert);
2281
2282
2283 bool
2284 IOPanicPlatform::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 }