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