xref: /xnu-8020.140.41/iokit/Kernel/IOPlatformExpert.cpp (revision 27b03b360a988dfd3dfdf34262bb0042026747cc)
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 boolean_t
PESyncNVRAM(void)1331 PESyncNVRAM(void)
1332 {
1333 	if (gIOOptionsEntry != nullptr) {
1334 		gIOOptionsEntry->sync();
1335 	}
1336 
1337 	return TRUE;
1338 }
1339 
1340 long
PEGetGMTTimeOfDay(void)1341 PEGetGMTTimeOfDay(void)
1342 {
1343 	clock_sec_t     secs;
1344 	clock_usec_t    usecs;
1345 
1346 	PEGetUTCTimeOfDay(&secs, &usecs);
1347 	return secs;
1348 }
1349 
1350 void
PESetGMTTimeOfDay(long secs)1351 PESetGMTTimeOfDay(long secs)
1352 {
1353 	PESetUTCTimeOfDay(secs, 0);
1354 }
1355 
1356 void
PEGetUTCTimeOfDay(clock_sec_t * secs,clock_usec_t * usecs)1357 PEGetUTCTimeOfDay(clock_sec_t * secs, clock_usec_t * usecs)
1358 {
1359 	clock_nsec_t    nsecs = 0;
1360 
1361 	*secs = 0;
1362 	if (gIOPlatform) {
1363 		gIOPlatform->getUTCTimeOfDay(secs, &nsecs);
1364 	}
1365 
1366 	assert(nsecs < NSEC_PER_SEC);
1367 	*usecs = nsecs / NSEC_PER_USEC;
1368 }
1369 
1370 void
PESetUTCTimeOfDay(clock_sec_t secs,clock_usec_t usecs)1371 PESetUTCTimeOfDay(clock_sec_t secs, clock_usec_t usecs)
1372 {
1373 	assert(usecs < USEC_PER_SEC);
1374 	if (gIOPlatform) {
1375 		gIOPlatform->setUTCTimeOfDay(secs, usecs * NSEC_PER_USEC);
1376 	}
1377 }
1378 
1379 coprocessor_type_t
PEGetCoprocessorVersion(void)1380 PEGetCoprocessorVersion( void )
1381 {
1382 	coprocessor_type_t coprocessor_version = kCoprocessorVersionNone;
1383 #if defined(__x86_64__)
1384 	IORegistryEntry     *platform_entry = NULL;
1385 	OSData              *coprocessor_version_obj = NULL;
1386 
1387 	platform_entry = IORegistryEntry::fromPath(kIODeviceTreePlane ":/efi/platform");
1388 	if (platform_entry != NULL) {
1389 		coprocessor_version_obj = OSDynamicCast(OSData, platform_entry->getProperty("apple-coprocessor-version"));
1390 		if ((coprocessor_version_obj != NULL) && (coprocessor_version_obj->getLength() <= sizeof(uint64_t))) {
1391 			memcpy(&coprocessor_version, coprocessor_version_obj->getBytesNoCopy(), coprocessor_version_obj->getLength());
1392 		}
1393 		platform_entry->release();
1394 	}
1395 #endif
1396 	return coprocessor_version;
1397 }
1398 } /* extern "C" */
1399 
1400 bool gIOPlatformUUIDAndSerialDone = false;
1401 
1402 void
publishPlatformUUIDAndSerial(void)1403 IOPlatformExpert::publishPlatformUUIDAndSerial( void )
1404 {
1405 	if (!gIOPlatformUUIDAndSerialDone) {
1406 		// Parse the serial-number data and publish a user-readable string
1407 		if (NULL == getProvider()->getProperty(kIOPlatformSerialNumberKey)) {
1408 			OSData* mydata = (OSData*) (getProvider()->getProperty("serial-number"));
1409 			if (mydata != NULL) {
1410 				OSString *serNoString = createSystemSerialNumberString(mydata);
1411 				if (serNoString != NULL) {
1412 					getProvider()->setProperty(kIOPlatformSerialNumberKey, serNoString);
1413 					serNoString->release();
1414 				}
1415 			}
1416 		}
1417 		IOPlatformExpertDevice *provider = OSDynamicCast(IOPlatformExpertDevice, getProvider());
1418 		assert(provider != NULL);
1419 		provider->generatePlatformUUID();
1420 	}
1421 
1422 	if (gIOPlatformUUIDAndSerialDone) {
1423 		publishResource(kIOPlatformUUIDKey, getProvider()->getProperty(kIOPlatformUUIDKey));
1424 	}
1425 }
1426 
1427 void
publishNVRAM(void)1428 IOPlatformExpert::publishNVRAM( void )
1429 {
1430 	if (init_gIOOptionsEntry() < 0) {
1431 		IOPlatformExpertDevice *provider = OSDynamicCast(IOPlatformExpertDevice, getProvider());
1432 		assert(provider != NULL);
1433 		provider->createNVRAM();
1434 	}
1435 	if (gIOOptionsEntry != NULL) {
1436 		gIOOptionsEntry->registerService();
1437 	}
1438 }
1439 
1440 void
registerNVRAMController(IONVRAMController * caller)1441 IOPlatformExpert::registerNVRAMController(IONVRAMController * caller)
1442 {
1443 #if defined(__x86_64__)
1444 	OSData *          data;
1445 	IORegistryEntry * entry;
1446 
1447 	/*
1448 	 * If we have panic debugging enabled WITHOUT behavior to reboot after any crash (DB_REBOOT_ALWAYS)
1449 	 * and we are on a co-processor system that has the panic SoC watchdog enabled, disable
1450 	 * cross panics so that the co-processor doesn't cause the system
1451 	 * to reset when we enter the debugger or hit a panic on the x86 side.
1452 	 */
1453 	if (panicDebugging && !(debug_boot_arg & DB_REBOOT_ALWAYS)) {
1454 		entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
1455 		if (entry) {
1456 			data = OSDynamicCast( OSData, entry->getProperty( APPLE_VENDOR_VARIABLE_GUID":BridgeOSPanicWatchdogEnabled" ));
1457 			if (data && (data->getLength() == sizeof(UInt8))) {
1458 				UInt8 *panicWatchdogEnabled = (UInt8 *) data->getBytesNoCopy();
1459 				UInt32 debug_flags = 0;
1460 				if (*panicWatchdogEnabled || (PE_i_can_has_debugger(&debug_flags) &&
1461 				    (debug_flags & DB_DISABLE_CROSS_PANIC))) {
1462 					coprocessor_cross_panic_enabled = FALSE;
1463 				}
1464 			}
1465 			entry->release();
1466 		}
1467 	}
1468 
1469 #if (DEVELOPMENT || DEBUG)
1470 	entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
1471 	if (entry) {
1472 		data = OSDynamicCast( OSData, entry->getProperty(nvram_osenvironment));
1473 		if (data) {
1474 			sysctl_set_osenvironment(data->getLength(), data->getBytesNoCopy());
1475 			entry->removeProperty(nvram_osenvironment);
1476 			IODTNVRAM * nvramOptionsEntry = OSDynamicCast(IODTNVRAM, entry);
1477 			if (nvramOptionsEntry) {
1478 				nvramOptionsEntry->sync();
1479 			}
1480 		}
1481 		entry->release();
1482 	}
1483 	sysctl_unblock_osenvironment();
1484 #endif
1485 	/* on intel the UUID must be published after nvram is available */
1486 	publishPlatformUUIDAndSerial();
1487 
1488 #endif /* defined(__x86_64__) */
1489 
1490 	publishResource("IONVRAM");
1491 }
1492 
1493 IOReturn
callPlatformFunction(const OSSymbol * functionName,bool waitForFunction,void * param1,void * param2,void * param3,void * param4)1494 IOPlatformExpert::callPlatformFunction(const OSSymbol *functionName,
1495     bool waitForFunction,
1496     void *param1, void *param2,
1497     void *param3, void *param4)
1498 {
1499 	IOService *service, *_resources;
1500 	OSObject  *prop = NULL;
1501 	IOReturn   ret;
1502 
1503 	if (functionName == gIOPlatformQuiesceActionKey ||
1504 	    functionName == gIOPlatformActiveActionKey) {
1505 		/*
1506 		 * Services which register for IOPlatformQuiesceAction / IOPlatformActiveAction
1507 		 * must consume that event themselves, without passing it up to super/IOPlatformExpert.
1508 		 */
1509 		if (gEnforceQuiesceSafety) {
1510 			panic("Class %s passed the quiesce/active action to IOPlatformExpert",
1511 			    getMetaClass()->getClassName());
1512 		}
1513 	}
1514 
1515 	if (waitForFunction) {
1516 		_resources = waitForService(resourceMatching(functionName));
1517 	} else {
1518 		_resources = getResourceService();
1519 	}
1520 	if (_resources == NULL) {
1521 		return kIOReturnUnsupported;
1522 	}
1523 
1524 	prop = _resources->copyProperty(functionName);
1525 	service = OSDynamicCast(IOService, prop);
1526 	if (service == NULL) {
1527 		ret = kIOReturnUnsupported;
1528 		goto finish;
1529 	}
1530 
1531 	ret = service->callPlatformFunction(functionName, waitForFunction,
1532 	    param1, param2, param3, param4);
1533 
1534 finish:
1535 	OSSafeReleaseNULL(prop);
1536 	return ret;
1537 }
1538 
1539 IOByteCount
savePanicInfo(UInt8 * buffer,IOByteCount length)1540 IOPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length)
1541 {
1542 	return 0;
1543 }
1544 
1545 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1546 
1547 #undef super
1548 #define super IOPlatformExpert
1549 
1550 OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert, IOPlatformExpert )
1551 
1552 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 0);
1553 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 1);
1554 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 2);
1555 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 3);
1556 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 4);
1557 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 5);
1558 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 6);
1559 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 7);
1560 
1561 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1562 
1563 IOService *
probe(IOService * provider,SInt32 * score)1564 IODTPlatformExpert::probe( IOService * provider,
1565     SInt32 * score )
1566 {
1567 	if (!super::probe( provider, score)) {
1568 		return NULL;
1569 	}
1570 
1571 	// check machine types
1572 	if (!provider->compareNames( getProperty( gIONameMatchKey ))) {
1573 		return NULL;
1574 	}
1575 
1576 	return this;
1577 }
1578 
1579 bool
configure(IOService * provider)1580 IODTPlatformExpert::configure( IOService * provider )
1581 {
1582 	if (!super::configure( provider)) {
1583 		return false;
1584 	}
1585 
1586 	processTopLevel( provider );
1587 
1588 	return true;
1589 }
1590 
1591 IOService *
createNub(IORegistryEntry * from)1592 IODTPlatformExpert::createNub( IORegistryEntry * from )
1593 {
1594 	IOService *         nub;
1595 
1596 	nub = new IOPlatformDevice;
1597 	if (nub) {
1598 		if (!nub->init( from, gIODTPlane )) {
1599 			nub->free();
1600 			nub = NULL;
1601 		}
1602 	}
1603 	return nub;
1604 }
1605 
1606 bool
createNubs(IOService * parent,OSIterator * iter)1607 IODTPlatformExpert::createNubs( IOService * parent, OSIterator * iter )
1608 {
1609 	IORegistryEntry *   next;
1610 	IOService *         nub = NULL;
1611 	bool                ok = true;
1612 
1613 	if (iter) {
1614 		while ((next = (IORegistryEntry *) iter->getNextObject())) {
1615 			OSSafeReleaseNULL(nub);
1616 
1617 			if (NULL == (nub = createNub( next ))) {
1618 				continue;
1619 			}
1620 
1621 			nub->attach( parent );
1622 #if !defined(__x86_64__)
1623 			OSData *tmpData = (OSData *)next->getProperty("device_type");
1624 			if (tmpData == NULL) {
1625 				nub->registerService();
1626 				continue;
1627 			}
1628 
1629 			char *device_type = (char *)tmpData->getBytesNoCopy();
1630 			if (strcmp(device_type, "cpu") != 0) {
1631 				nub->registerService();
1632 				continue;
1633 			}
1634 
1635 			tmpData = (OSData *)next->getProperty("reg");
1636 			assert(tmpData != NULL);
1637 			assert(tmpData->getLength() >= sizeof(UInt32));
1638 
1639 			uint32_t phys_id = *(UInt32 *)tmpData->getBytesNoCopy();
1640 			int logical_cpu_id = ml_get_cpu_number(phys_id);
1641 			int logical_cluster_id = ml_get_cluster_number(phys_id);
1642 
1643 			/*
1644 			 * If the following condition triggers, it means that a CPU that was present in the DT
1645 			 * was ignored by XNU at topology parsing time. This can happen currently when using the
1646 			 * cpus=N boot-arg; for example, cpus=1 will cause XNU to parse and enable a single CPU.
1647 			 *
1648 			 * Note that this condition will not trigger for harvested cores because these do not show up
1649 			 * in the DT/IORegistry in the first place.
1650 			 */
1651 			if (logical_cpu_id < 0) {
1652 				nub->registerService();
1653 				continue;
1654 			}
1655 
1656 			__assert_only bool logical_id_added_to_ioreg = nub->setProperty("logical-cpu-id", logical_cpu_id, 32U);
1657 			assert(logical_id_added_to_ioreg == true);
1658 			logical_id_added_to_ioreg = nub->setProperty("logical-cluster-id", logical_cluster_id, 32U);
1659 			assert(logical_id_added_to_ioreg == true);
1660 #endif
1661 			nub->registerService();
1662 		}
1663 		OSSafeReleaseNULL(nub);
1664 		iter->release();
1665 	}
1666 
1667 	return ok;
1668 }
1669 
1670 void
processTopLevel(IORegistryEntry * rootEntry)1671 IODTPlatformExpert::processTopLevel( IORegistryEntry * rootEntry )
1672 {
1673 	OSIterator *        kids;
1674 	IORegistryEntry *   next;
1675 	IORegistryEntry *   cpus;
1676 
1677 	// infanticide
1678 	kids = IODTFindMatchingEntries( rootEntry, 0, deleteList());
1679 	if (kids) {
1680 		while ((next = (IORegistryEntry *)kids->getNextObject())) {
1681 			next->detachAll( gIODTPlane);
1682 		}
1683 		kids->release();
1684 	}
1685 
1686 	publishNVRAM();
1687 	assert(gIOOptionsEntry != NULL); // subclasses that do their own NVRAM initialization shouldn't be calling this
1688 	dtNVRAM = gIOOptionsEntry;
1689 
1690 	// Publish the cpus.
1691 	cpus = rootEntry->childFromPath( "cpus", gIODTPlane);
1692 	if (cpus) {
1693 		createNubs( this, IODTFindMatchingEntries( cpus, kIODTExclusive, NULL));
1694 		cpus->release();
1695 	}
1696 
1697 	// publish top level, minus excludeList
1698 	createNubs( this, IODTFindMatchingEntries( rootEntry, kIODTExclusive, excludeList()));
1699 }
1700 
1701 IOReturn
getNubResources(IOService * nub)1702 IODTPlatformExpert::getNubResources( IOService * nub )
1703 {
1704 	if (nub->getDeviceMemory()) {
1705 		return kIOReturnSuccess;
1706 	}
1707 
1708 	IODTResolveAddressing( nub, "reg", NULL);
1709 
1710 	return kIOReturnSuccess;
1711 }
1712 
1713 bool
compareNubName(const IOService * nub,OSString * name,OSString ** matched) const1714 IODTPlatformExpert::compareNubName( const IOService * nub,
1715     OSString * name, OSString ** matched ) const
1716 {
1717 	return IODTCompareNubName( nub, name, matched )
1718 	       || super::compareNubName( nub, name, matched);
1719 }
1720 
1721 
1722 /*
1723  * Do not use this method directly, it returns inconsistent results
1724  * across architectures and is considered deprecated.
1725  *
1726  * Use getTargetName and getProductName respectively.  For example:
1727  *
1728  * targetName: J137AP
1729  * productName: iMacPro1,1
1730  *
1731  * targetName: D331pAP
1732  * productName: iPhone11,6
1733  */
1734 
1735 bool
getModelName(char * name,int maxLength)1736 IODTPlatformExpert::getModelName( char * name, int maxLength )
1737 {
1738 	OSData *            prop;
1739 	const char *        str;
1740 	int                 len;
1741 	char                c;
1742 	bool                ok = false;
1743 
1744 	maxLength--;
1745 
1746 	prop = (OSData *) getProvider()->getProperty( gIODTCompatibleKey );
1747 	if (prop) {
1748 		str = (const char *) prop->getBytesNoCopy();
1749 
1750 		if (0 == strncmp( str, "AAPL,", strlen( "AAPL," ))) {
1751 			str += strlen( "AAPL," );
1752 		}
1753 
1754 		len = 0;
1755 		while ((c = *str++)) {
1756 			if ((c == '/') || (c == ' ')) {
1757 				c = '-';
1758 			}
1759 
1760 			name[len++] = c;
1761 			if (len >= maxLength) {
1762 				break;
1763 			}
1764 		}
1765 
1766 		name[len] = 0;
1767 		ok = true;
1768 	}
1769 	return ok;
1770 }
1771 
1772 /*
1773  * Do not use this method directly, it returns inconsistent results
1774  * across architectures and is considered deprecated.
1775  *
1776  * Use getTargetName and getProductName respectively.  For example:
1777  *
1778  * targetName: J137AP
1779  * productName: iMacPro1,1
1780  *
1781  * targetName: D331pAP
1782  * productName: iPhone11,6
1783  */
1784 
1785 bool
getMachineName(char * name,int maxLength)1786 IODTPlatformExpert::getMachineName( char * name, int maxLength )
1787 {
1788 	OSData *            prop;
1789 	bool                ok = false;
1790 
1791 	maxLength--;
1792 	prop = (OSData *) getProvider()->getProperty( gIODTModelKey );
1793 	ok = (NULL != prop);
1794 
1795 	if (ok) {
1796 		strlcpy( name, (const char *) prop->getBytesNoCopy(), maxLength );
1797 	}
1798 
1799 	return ok;
1800 }
1801 
1802 /* Examples: J137AP, D331pAP... */
1803 
1804 bool
getTargetName(char * name,int maxLength)1805 IODTPlatformExpert::getTargetName( char * name, int maxLength )
1806 {
1807 #if __x86_64__
1808 	OSData *            prop;
1809 
1810 	const OSSymbol *        key = gIODTBridgeModelKey;
1811 
1812 	maxLength--;
1813 	prop = (OSData *) getProvider()->getProperty( key );
1814 
1815 	if (prop == NULL) {
1816 		// This happens if there is no bridge.
1817 		char const * const  unknown = "";
1818 
1819 		strlcpy( name, unknown, maxLength );
1820 	} else {
1821 		strlcpy( name, (const char *)prop->getBytesNoCopy(), maxLength );
1822 	}
1823 
1824 	return true;
1825 #else
1826 	return getModelName( name, maxLength );
1827 #endif
1828 }
1829 
1830 /* Examples: iMacPro1,1, iPhone11,6... */
1831 
1832 bool
getProductName(char * name,int maxLength)1833 IODTPlatformExpert::getProductName( char * name, int maxLength )
1834 {
1835 #if __x86_64__
1836 	return getModelName( name, maxLength );
1837 #else
1838 	return getMachineName( name, maxLength );
1839 #endif
1840 }
1841 
1842 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1843 
1844 void
registerNVRAMController(IONVRAMController * nvram)1845 IODTPlatformExpert::registerNVRAMController( IONVRAMController * nvram )
1846 {
1847 	if (dtNVRAM) {
1848 		dtNVRAM->registerNVRAMController(nvram);
1849 	}
1850 
1851 	super::registerNVRAMController(nvram);
1852 }
1853 
1854 int
haltRestart(unsigned int type)1855 IODTPlatformExpert::haltRestart(unsigned int type)
1856 {
1857 	return super::haltRestart(type);
1858 }
1859 
1860 IOReturn
readXPRAM(IOByteCount offset,UInt8 * buffer,IOByteCount length)1861 IODTPlatformExpert::readXPRAM(IOByteCount offset, UInt8 * buffer,
1862     IOByteCount length)
1863 {
1864 	if (dtNVRAM) {
1865 		return dtNVRAM->readXPRAM(offset, buffer, length);
1866 	} else {
1867 		return kIOReturnNotReady;
1868 	}
1869 }
1870 
1871 IOReturn
writeXPRAM(IOByteCount offset,UInt8 * buffer,IOByteCount length)1872 IODTPlatformExpert::writeXPRAM(IOByteCount offset, UInt8 * buffer,
1873     IOByteCount length)
1874 {
1875 	if (dtNVRAM) {
1876 		return dtNVRAM->writeXPRAM(offset, buffer, length);
1877 	} else {
1878 		return kIOReturnNotReady;
1879 	}
1880 }
1881 
1882 IOReturn
readNVRAMProperty(IORegistryEntry * entry,const OSSymbol ** name,OSData ** value)1883 IODTPlatformExpert::readNVRAMProperty(
1884 	IORegistryEntry * entry,
1885 	const OSSymbol ** name, OSData ** value )
1886 {
1887 	if (dtNVRAM) {
1888 		return dtNVRAM->readNVRAMProperty(entry, name, value);
1889 	} else {
1890 		return kIOReturnNotReady;
1891 	}
1892 }
1893 
1894 IOReturn
readNVRAMProperty(IORegistryEntry * entry,OSSharedPtr<const OSSymbol> & name,OSSharedPtr<OSData> & value)1895 IODTPlatformExpert::readNVRAMProperty(
1896 	IORegistryEntry * entry,
1897 	OSSharedPtr<const OSSymbol>& name, OSSharedPtr<OSData>& value )
1898 {
1899 	const OSSymbol* nameRaw = NULL;
1900 	OSData* valueRaw = NULL;
1901 
1902 	IOReturn result = readNVRAMProperty(entry, &nameRaw, &valueRaw);
1903 
1904 	name.reset(nameRaw, OSNoRetain);
1905 	value.reset(valueRaw, OSNoRetain);
1906 
1907 	return result;
1908 }
1909 
1910 IOReturn
writeNVRAMProperty(IORegistryEntry * entry,const OSSymbol * name,OSData * value)1911 IODTPlatformExpert::writeNVRAMProperty(
1912 	IORegistryEntry * entry,
1913 	const OSSymbol * name, OSData * value )
1914 {
1915 	if (dtNVRAM) {
1916 		return dtNVRAM->writeNVRAMProperty(entry, name, value);
1917 	} else {
1918 		return kIOReturnNotReady;
1919 	}
1920 }
1921 
1922 OSDictionary *
getNVRAMPartitions(void)1923 IODTPlatformExpert::getNVRAMPartitions(void)
1924 {
1925 	if (dtNVRAM) {
1926 		return dtNVRAM->getNVRAMPartitions();
1927 	} else {
1928 		return NULL;
1929 	}
1930 }
1931 
1932 IOReturn
readNVRAMPartition(const OSSymbol * partitionID,IOByteCount offset,UInt8 * buffer,IOByteCount length)1933 IODTPlatformExpert::readNVRAMPartition(const OSSymbol * partitionID,
1934     IOByteCount offset, UInt8 * buffer,
1935     IOByteCount length)
1936 {
1937 	if (dtNVRAM) {
1938 		return dtNVRAM->readNVRAMPartition(partitionID, offset,
1939 		           buffer, length);
1940 	} else {
1941 		return kIOReturnNotReady;
1942 	}
1943 }
1944 
1945 IOReturn
writeNVRAMPartition(const OSSymbol * partitionID,IOByteCount offset,UInt8 * buffer,IOByteCount length)1946 IODTPlatformExpert::writeNVRAMPartition(const OSSymbol * partitionID,
1947     IOByteCount offset, UInt8 * buffer,
1948     IOByteCount length)
1949 {
1950 	if (dtNVRAM) {
1951 		return dtNVRAM->writeNVRAMPartition(partitionID, offset,
1952 		           buffer, length);
1953 	} else {
1954 		return kIOReturnNotReady;
1955 	}
1956 }
1957 
1958 IOByteCount
savePanicInfo(UInt8 * buffer,IOByteCount length)1959 IODTPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length)
1960 {
1961 	IOByteCount lengthSaved = 0;
1962 
1963 	if (dtNVRAM) {
1964 		lengthSaved = dtNVRAM->savePanicInfo(buffer, length);
1965 	}
1966 
1967 	if (lengthSaved == 0) {
1968 		lengthSaved = super::savePanicInfo(buffer, length);
1969 	}
1970 
1971 	return lengthSaved;
1972 }
1973 
1974 OSString*
createSystemSerialNumberString(OSData * myProperty)1975 IODTPlatformExpert::createSystemSerialNumberString(OSData* myProperty)
1976 {
1977 	UInt8* serialNumber;
1978 	unsigned int serialNumberSize;
1979 	unsigned short pos = 0;
1980 	char* temp;
1981 	char SerialNo[30];
1982 
1983 	if (myProperty != NULL) {
1984 		serialNumberSize = myProperty->getLength();
1985 		serialNumber = (UInt8*)(myProperty->getBytesNoCopy());
1986 		temp = (char*)serialNumber;
1987 		if (serialNumberSize > 0) {
1988 			// check to see if this is a CTO serial number...
1989 			while (pos < serialNumberSize && temp[pos] != '-') {
1990 				pos++;
1991 			}
1992 
1993 			if (pos < serialNumberSize) { // there was a hyphen, so it's a CTO serial number
1994 				memcpy(SerialNo, serialNumber + 12, 8);
1995 				memcpy(&SerialNo[8], serialNumber, 3);
1996 				SerialNo[11] = '-';
1997 				memcpy(&SerialNo[12], serialNumber + 3, 8);
1998 				SerialNo[20] = 0;
1999 			} else { // just a normal serial number
2000 				memcpy(SerialNo, serialNumber + 13, 8);
2001 				memcpy(&SerialNo[8], serialNumber, 3);
2002 				SerialNo[11] = 0;
2003 			}
2004 			return OSString::withCString(SerialNo);
2005 		}
2006 	}
2007 	return NULL;
2008 }
2009 
2010 
2011 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012 
2013 #undef super
2014 #define super IOService
2015 
2016 OSDefineMetaClassAndStructors(IOPlatformExpertDevice, IOService)
2017 
2018 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 0);
2019 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 1);
2020 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 2);
2021 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 3);
2022 
2023 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2024 
2025 bool
compareName(OSString * name,OSString ** matched) const2026 IOPlatformExpertDevice::compareName( OSString * name,
2027     OSString ** matched ) const
2028 {
2029 	return IODTCompareNubName( this, name, matched );
2030 }
2031 
2032 bool
init(void * dtRoot)2033 IOPlatformExpertDevice::init(void *dtRoot)
2034 {
2035 	IORegistryEntry *   dt = NULL;
2036 	bool                ok;
2037 
2038 	if ((dtRoot != NULL) && (dt = IODeviceTreeAlloc(dtRoot))) {
2039 		ok = super::init( dt, gIODTPlane );
2040 	} else {
2041 		ok = super::init();
2042 	}
2043 
2044 	if (!ok) {
2045 		return false;
2046 	}
2047 
2048 	return true;
2049 }
2050 
2051 bool
startIOServiceMatching(void)2052 IOPlatformExpertDevice::startIOServiceMatching(void)
2053 {
2054 	workLoop = IOWorkLoop::workLoop();
2055 	if (!workLoop) {
2056 		return false;
2057 	}
2058 
2059 	registerService();
2060 
2061 	return true;
2062 }
2063 
2064 IOWorkLoop *
getWorkLoop() const2065 IOPlatformExpertDevice::getWorkLoop() const
2066 {
2067 	return workLoop;
2068 }
2069 
2070 IOReturn
setProperties(OSObject * properties)2071 IOPlatformExpertDevice::setProperties( OSObject * properties )
2072 {
2073 	return kIOReturnUnsupported;
2074 }
2075 
2076 IOReturn
newUserClient(task_t owningTask,void * securityID,UInt32 type,OSDictionary * properties,IOUserClient ** handler)2077 IOPlatformExpertDevice::newUserClient( task_t owningTask, void * securityID,
2078     UInt32 type, OSDictionary * properties,
2079     IOUserClient ** handler )
2080 {
2081 	IOReturn            err = kIOReturnSuccess;
2082 	IOUserClient *      newConnect = NULL;
2083 	IOUserClient *      theConnect = NULL;
2084 
2085 	switch (type) {
2086 	case kIOKitDiagnosticsClientType:
2087 		newConnect = IOKitDiagnosticsClient::withTask(owningTask);
2088 		if (!newConnect) {
2089 			err = kIOReturnNotPermitted;
2090 		}
2091 		break;
2092 	case kIOKitUserServerClientType:
2093 		newConnect = IOUserServer::withTask(owningTask);
2094 		if (!newConnect) {
2095 			err = kIOReturnNotPermitted;
2096 		}
2097 		break;
2098 	default:
2099 		err = kIOReturnBadArgument;
2100 	}
2101 
2102 	if (newConnect) {
2103 		if ((false == newConnect->attach(this))
2104 		    || (false == newConnect->start(this))) {
2105 			newConnect->detach( this );
2106 			newConnect->release();
2107 			err = kIOReturnNotPermitted;
2108 		} else {
2109 			theConnect = newConnect;
2110 		}
2111 	}
2112 
2113 	*handler = theConnect;
2114 	return err;
2115 }
2116 
2117 void
free()2118 IOPlatformExpertDevice::free()
2119 {
2120 	if (workLoop) {
2121 		workLoop->release();
2122 	}
2123 }
2124 
2125 void
configureDefaults(void)2126 IOPlatformExpertDevice::configureDefaults( void )
2127 {
2128 	createNVRAM();
2129 	// Parse the serial-number data and publish a user-readable string
2130 	OSData* mydata = (OSData*) (getProperty("serial-number"));
2131 	if (mydata != NULL) {
2132 		OSString *serNoString = OSString::withCString((const char *)mydata->getBytesNoCopy());
2133 		if (serNoString != NULL) {
2134 			setProperty(kIOPlatformSerialNumberKey, serNoString);
2135 			serNoString->release();
2136 		}
2137 	}
2138 	generatePlatformUUID();
2139 }
2140 
2141 void
createNVRAM(void)2142 IOPlatformExpertDevice::createNVRAM( void )
2143 {
2144 	/*
2145 	 * Publish an IODTNVRAM class on /options, if present.
2146 	 * DT-based platforms may need NVRAM access prior to the start
2147 	 * of IOKit matching, to support security-related operations
2148 	 * that must happen before machine_lockdown().
2149 	 */
2150 	IORegistryEntry *options = IORegistryEntry::fromPath("/options", gIODTPlane);
2151 	if (options == NULL) {
2152 		return; // /options may not be present
2153 	}
2154 
2155 	assert(gIOOptionsEntry == NULL);
2156 	gIOOptionsEntry = new IODTNVRAM;
2157 
2158 	assert(gIOOptionsEntry != NULL);
2159 
2160 	gIOOptionsEntry->init(options, gIODTPlane);
2161 	gIOOptionsEntry->attach(this);
2162 	gIOOptionsEntry->start(this);
2163 	options->release();
2164 }
2165 
2166 void
generatePlatformUUID(void)2167 IOPlatformExpertDevice::generatePlatformUUID( void )
2168 {
2169 	IORegistryEntry * entry;
2170 	OSString *        string = NULL;
2171 	uuid_string_t     uuid;
2172 
2173 #if !defined(__x86_64__)
2174 	entry = IORegistryEntry::fromPath( "/chosen", gIODTPlane );
2175 	if (entry) {
2176 		OSData * data1;
2177 
2178 		data1 = OSDynamicCast( OSData, entry->getProperty( "unique-chip-id" ));
2179 		if (data1 && data1->getLength() == 8) {
2180 			OSData * data2;
2181 
2182 			data2 = OSDynamicCast( OSData, entry->getProperty( "chip-id" ));
2183 			if (data2 && data2->getLength() == 4) {
2184 				SHA1_CTX     context;
2185 				uint8_t      digest[SHA_DIGEST_LENGTH];
2186 				const uuid_t space = { 0xA6, 0xDD, 0x4C, 0xCB, 0xB5, 0xE8, 0x4A, 0xF5, 0xAC, 0xDD, 0xB6, 0xDC, 0x6A, 0x05, 0x42, 0xB8 };
2187 
2188 				SHA1Init( &context );
2189 				SHA1Update( &context, space, sizeof(space));
2190 				SHA1Update( &context, data1->getBytesNoCopy(), data1->getLength());
2191 				SHA1Update( &context, data2->getBytesNoCopy(), data2->getLength());
2192 				SHA1Final( digest, &context );
2193 
2194 				digest[6] = (digest[6] & 0x0F) | 0x50;
2195 				digest[8] = (digest[8] & 0x3F) | 0x80;
2196 
2197 				uuid_unparse( digest, uuid );
2198 				string = OSString::withCString( uuid );
2199 			}
2200 		}
2201 
2202 		entry->release();
2203 	}
2204 #else /* !defined(__x86_64__) */
2205 	OSData * data;
2206 
2207 	entry = IORegistryEntry::fromPath( "/efi/platform", gIODTPlane );
2208 	if (entry) {
2209 		data = OSDynamicCast( OSData, entry->getProperty( "system-id" ));
2210 		if (data && data->getLength() == 16) {
2211 			SHA1_CTX     context;
2212 			uint8_t      digest[SHA_DIGEST_LENGTH];
2213 			const uuid_t space = { 0x2A, 0x06, 0x19, 0x90, 0xD3, 0x8D, 0x44, 0x40, 0xA1, 0x39, 0xC4, 0x97, 0x70, 0x37, 0x65, 0xAC };
2214 
2215 			SHA1Init( &context );
2216 			SHA1Update( &context, space, sizeof(space));
2217 			SHA1Update( &context, data->getBytesNoCopy(), data->getLength());
2218 			SHA1Final( digest, &context );
2219 
2220 			digest[6] = (digest[6] & 0x0F) | 0x50;
2221 			digest[8] = (digest[8] & 0x3F) | 0x80;
2222 
2223 			uuid_unparse( digest, uuid );
2224 			string = OSString::withCString( uuid );
2225 		}
2226 
2227 		entry->release();
2228 	}
2229 	if (!string) {
2230 		/* vmware still runs this path */
2231 		entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
2232 		if (entry) {
2233 			data = OSDynamicCast( OSData, entry->getProperty( "platform-uuid" ));
2234 			if (data && data->getLength() == sizeof(uuid_t)) {
2235 				uuid_unparse((uint8_t *) data->getBytesNoCopy(), uuid );
2236 				string = OSString::withCString( uuid );
2237 			}
2238 			entry->release();
2239 		}
2240 	}
2241 #endif /* defined(__x86_64__) */
2242 
2243 	if (string) {
2244 		setProperty( kIOPlatformUUIDKey, string );
2245 		gIOPlatformUUIDAndSerialDone = true;
2246 
2247 		string->release();
2248 	}
2249 }
2250 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2251 
2252 #undef super
2253 #define super IOService
2254 
2255 OSDefineMetaClassAndStructors(IOPlatformDevice, IOService)
2256 
2257 OSMetaClassDefineReservedUnused(IOPlatformDevice, 0);
2258 OSMetaClassDefineReservedUnused(IOPlatformDevice, 1);
2259 OSMetaClassDefineReservedUnused(IOPlatformDevice, 2);
2260 OSMetaClassDefineReservedUnused(IOPlatformDevice, 3);
2261 
2262 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2263 
2264 bool
compareName(OSString * name,OSString ** matched) const2265 IOPlatformDevice::compareName( OSString * name,
2266     OSString ** matched ) const
2267 {
2268 	return ((IOPlatformExpert *)getProvider())->
2269 	       compareNubName( this, name, matched );
2270 }
2271 
2272 IOService *
matchLocation(IOService *)2273 IOPlatformDevice::matchLocation( IOService * /* client */ )
2274 {
2275 	return this;
2276 }
2277 
2278 IOReturn
getResources(void)2279 IOPlatformDevice::getResources( void )
2280 {
2281 	return ((IOPlatformExpert *)getProvider())->getNubResources( this );
2282 }
2283 
2284 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2285 
2286 /*********************************************************************
2287 * IOPanicPlatform class
2288 *
2289 * If no legitimate IOPlatformDevice matches, this one does and panics
2290 * the kernel with a suitable message.
2291 *********************************************************************/
2292 
2293 class IOPanicPlatform : IOPlatformExpert {
2294 	OSDeclareDefaultStructors(IOPanicPlatform);
2295 
2296 public:
2297 	bool start(IOService * provider) APPLE_KEXT_OVERRIDE;
2298 };
2299 
2300 
2301 OSDefineMetaClassAndStructors(IOPanicPlatform, IOPlatformExpert);
2302 
2303 
2304 bool
start(IOService * provider)2305 IOPanicPlatform::start(IOService * provider)
2306 {
2307 	const char * platform_name = "(unknown platform name)";
2308 
2309 	if (provider) {
2310 		platform_name = provider->getName();
2311 	}
2312 
2313 	panic("Unable to find driver for this platform: \"%s\".",
2314 	    platform_name);
2315 
2316 	return false;
2317 }
2318