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