xref: /xnu-12377.81.4/iokit/Kernel/IOPlatformExpert.cpp (revision 043036a2b3718f7f0be807e2870f8f47d3fa0796)
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 #if defined(__arm64__)
971 __attribute__((noinline))
972 static void
force_hard_hang_if_transaction_pending(void)973 force_hard_hang_if_transaction_pending(void)
974 {
975 	/*
976 	 * Intentionally force a hang if all CPUs cannot complete it
977 	 * so that we get an AP watchdog hang *here*  instead of later in the panic flow.
978 	 */
979 	arm64_sync_tlb(true);
980 }
981 #endif // defined(__arm64__)
982 
983 /* Handle necessary platform specific actions prior to panic */
984 void
PEInitiatePanic(void)985 PEInitiatePanic(void)
986 {
987 #if defined(__arm64__)
988 	/*
989 	 * Trigger a TLB flush so any hard hangs exercise the SoC diagnostic
990 	 * collection flow rather than hanging late in panic (see rdar://58062030)
991 	 */
992 	flush_mmu_tlb_entries_async(0, PAGE_SIZE, PAGE_SIZE, true, true);
993 	force_hard_hang_if_transaction_pending();
994 #endif // defined(__arm64__)
995 }
996 
997 int
PEHaltRestartInternal(unsigned int type,uint32_t details)998 PEHaltRestartInternal(unsigned int type, uint32_t details)
999 {
1000 	IOPMrootDomain    *pmRootDomain;
1001 	AbsoluteTime      deadline;
1002 	thread_call_t     shutdown_hang;
1003 	IORegistryEntry   *node;
1004 	OSData            *data;
1005 	uint32_t          timeout = kShutdownTimeout;
1006 	static boolean_t  panic_begin_called = FALSE;
1007 
1008 	if (type == kPEHaltCPU || type == kPERestartCPU || type == kPEUPSDelayHaltCPU) {
1009 		/* If we're in the panic path, the locks and memory allocations required below
1010 		 *  could fail. So just try to reboot instead of risking a nested panic.
1011 		 */
1012 		if (panic_begin_called) {
1013 			goto skip_to_haltRestart;
1014 		}
1015 
1016 		pmRootDomain = IOService::getPMRootDomain();
1017 		/* Notify IOKit PM clients of shutdown/restart
1018 		 *  Clients subscribe to this message with a call to
1019 		 *  IOService::registerInterest()
1020 		 */
1021 
1022 		/* Spawn a thread that will panic in 30 seconds.
1023 		 *  If all goes well the machine will be off by the time
1024 		 *  the timer expires. If the device wants a different
1025 		 *  timeout, use that value instead of 30 seconds.
1026 		 */
1027 #if  defined(__arm64__)
1028 #define RESTART_NODE_PATH    "/defaults"
1029 #else
1030 #define RESTART_NODE_PATH    "/chosen"
1031 #endif
1032 		node = IORegistryEntry::fromPath( RESTART_NODE_PATH, gIODTPlane );
1033 		if (node) {
1034 			data = OSDynamicCast( OSData, node->getProperty( "halt-restart-timeout" ));
1035 			if (data && data->getLength() == 4) {
1036 				timeout = *((uint32_t *) data->getBytesNoCopy());
1037 			}
1038 			OSSafeReleaseNULL(node);
1039 		}
1040 
1041 #if (DEVELOPMENT || DEBUG)
1042 		/* Override the default timeout via a boot-arg */
1043 		uint32_t boot_arg_val;
1044 		if (PE_parse_boot_argn("halt_restart_timeout", &boot_arg_val, sizeof(boot_arg_val))) {
1045 			timeout = boot_arg_val;
1046 		}
1047 #endif
1048 
1049 		if (timeout) {
1050 			shutdown_hang = thread_call_allocate( &IOShutdownNotificationsTimedOut,
1051 			    (thread_call_param_t)(uintptr_t) type);
1052 			clock_interval_to_deadline( timeout, kSecondScale, &deadline );
1053 			thread_call_enter1_delayed( shutdown_hang, (thread_call_param_t)(uintptr_t)timeout, deadline );
1054 		}
1055 
1056 		pmRootDomain->handlePlatformHaltRestart(type);
1057 		/* This notification should have few clients who all do
1058 		 *  their work synchronously.
1059 		 *
1060 		 *  In this "shutdown notification" context we don't give
1061 		 *  drivers the option of working asynchronously and responding
1062 		 *  later. PM internals make it very hard to wait for asynchronous
1063 		 *  replies.
1064 		 */
1065 	} else if (type == kPEPanicRestartCPU || type == kPEPanicSync || type == kPEPanicRestartCPUNoCallouts) {
1066 		if (type == kPEPanicRestartCPU) {
1067 			// Notify any listeners that we're done collecting
1068 			// panic data before we call through to do the restart
1069 #if defined(__x86_64__)
1070 			if (coprocessor_cross_panic_enabled)
1071 #endif
1072 			IOCPURunPlatformPanicActions(kPEPanicEnd, details);
1073 		} else if (type == kPEPanicRestartCPUNoCallouts) {
1074 			// We skipped the callouts so now set the type to
1075 			// the variant that the platform uses for panic restarts.
1076 			type = kPEPanicRestartCPU;
1077 		}
1078 
1079 
1080 		// Do an initial sync to flush as much panic data as possible,
1081 		// in case we have a problem in one of the platorm panic handlers.
1082 		// After running the platform handlers, do a final sync w/
1083 		// platform hardware quiesced for the panic.
1084 		PE_sync_panic_buffers();
1085 		IOCPURunPlatformPanicActions(type, details);
1086 		PE_sync_panic_buffers();
1087 	} else if (type == kPEPanicEnd) {
1088 #if defined(__x86_64__)
1089 		if (coprocessor_cross_panic_enabled)
1090 #endif
1091 		IOCPURunPlatformPanicActions(type, details);
1092 	} else if (type == kPEPanicBegin) {
1093 #if defined(__x86_64__)
1094 		if (coprocessor_cross_panic_enabled)
1095 #endif
1096 		{
1097 			// Only call the kPEPanicBegin callout once
1098 			if (!panic_begin_called) {
1099 				panic_begin_called = TRUE;
1100 				IOCPURunPlatformPanicActions(type, details);
1101 			}
1102 		}
1103 	} else if (type == kPEPanicDiagnosticsDone || type == kPEPanicDiagnosticsInProgress) {
1104 		IOCPURunPlatformPanicActions(type, details);
1105 	}
1106 
1107 skip_to_haltRestart:
1108 	if (gIOPlatform) {
1109 		// note that this will not necessarily halt or restart the system...
1110 		// Implementors of this function will check the type and take action accordingly
1111 		return gIOPlatform->haltRestart(type);
1112 	} else {
1113 		return -1;
1114 	}
1115 }
1116 
1117 int
PEHaltRestart(unsigned int type)1118 PEHaltRestart(unsigned int type)
1119 {
1120 	return PEHaltRestartInternal(type, 0);
1121 }
1122 
1123 UInt32
PESavePanicInfo(UInt8 * buffer,UInt32 length)1124 PESavePanicInfo(UInt8 *buffer, UInt32 length)
1125 {
1126 	if (gIOPlatform != NULL) {
1127 		return (UInt32) gIOPlatform->savePanicInfo(buffer, length);
1128 	} else {
1129 		return 0;
1130 	}
1131 }
1132 
1133 void
PESavePanicInfoAction(void * buffer,UInt32 offset,UInt32 length)1134 PESavePanicInfoAction(void *buffer, UInt32 offset, UInt32 length)
1135 {
1136 	IOCPURunPlatformPanicSyncAction(buffer, offset, length);
1137 	return;
1138 }
1139 
1140 
1141 /*
1142  * Depending on the platform, the /options node may not be created
1143  * until after IOKit matching has started, by an externally-supplied
1144  * platform expert subclass.  Therefore, we must check for its presence
1145  * here and update gIOOptionsEntry for the platform code as necessary.
1146  */
1147 inline static int
init_gIOOptionsEntry(void)1148 init_gIOOptionsEntry(void)
1149 {
1150 	IORegistryEntry *entry;
1151 	void *nvram_entry;
1152 	volatile void **options;
1153 	int ret = -1;
1154 
1155 	if (gIOOptionsEntry) {
1156 		return 0;
1157 	}
1158 
1159 	entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
1160 	if (!entry) {
1161 		return -1;
1162 	}
1163 
1164 	nvram_entry = (void *) OSDynamicCast(IODTNVRAM, entry);
1165 	if (!nvram_entry) {
1166 		goto release;
1167 	}
1168 
1169 	options = (volatile void **) &gIOOptionsEntry;
1170 	if (!OSCompareAndSwapPtr(NULL, nvram_entry, options)) {
1171 		ret = 0;
1172 		goto release;
1173 	}
1174 
1175 	return 0;
1176 
1177 release:
1178 	entry->release();
1179 	return ret;
1180 }
1181 
1182 /* pass in a NULL value if you just want to figure out the len */
1183 boolean_t
PEReadNVRAMProperty(const char * symbol,void * value,unsigned int * len)1184 PEReadNVRAMProperty(const char *symbol, void *value,
1185     unsigned int *len)
1186 {
1187 	OSObject  *obj;
1188 	OSData *data;
1189 	unsigned int vlen;
1190 
1191 	if (!symbol || !len) {
1192 		goto err;
1193 	}
1194 
1195 	if (init_gIOOptionsEntry() < 0) {
1196 		goto err;
1197 	}
1198 
1199 	vlen = *len;
1200 	*len = 0;
1201 
1202 	obj = gIOOptionsEntry->getProperty(symbol);
1203 	if (!obj) {
1204 		goto err;
1205 	}
1206 
1207 	/* convert to data */
1208 	data = OSDynamicCast(OSData, obj);
1209 	if (!data) {
1210 		goto err;
1211 	}
1212 
1213 	*len  = data->getLength();
1214 	vlen  = min(vlen, *len);
1215 	if (value && vlen) {
1216 		memcpy((void *) value, data->getBytesNoCopy(), vlen);
1217 	}
1218 
1219 	return TRUE;
1220 
1221 err:
1222 	return FALSE;
1223 }
1224 
1225 boolean_t
PEReadNVRAMBooleanProperty(const char * symbol,boolean_t * value)1226 PEReadNVRAMBooleanProperty(const char *symbol, boolean_t *value)
1227 {
1228 	OSObject  *obj;
1229 	OSBoolean *data;
1230 
1231 	if (!symbol || !value) {
1232 		goto err;
1233 	}
1234 
1235 	if (init_gIOOptionsEntry() < 0) {
1236 		goto err;
1237 	}
1238 
1239 	obj = gIOOptionsEntry->getProperty(symbol);
1240 	if (!obj) {
1241 		return TRUE;
1242 	}
1243 
1244 	/* convert to bool */
1245 	data = OSDynamicCast(OSBoolean, obj);
1246 	if (!data) {
1247 		goto err;
1248 	}
1249 
1250 	*value = data->isTrue() ? TRUE : FALSE;
1251 
1252 	return TRUE;
1253 
1254 err:
1255 	return FALSE;
1256 }
1257 
1258 boolean_t
PEWriteNVRAMBooleanProperty(const char * symbol,boolean_t value)1259 PEWriteNVRAMBooleanProperty(const char *symbol, boolean_t value)
1260 {
1261 	const OSSymbol *sym = NULL;
1262 	OSBoolean *data = NULL;
1263 	bool ret = false;
1264 
1265 	if (symbol == NULL) {
1266 		goto exit;
1267 	}
1268 
1269 	if (init_gIOOptionsEntry() < 0) {
1270 		goto exit;
1271 	}
1272 
1273 	if ((sym = OSSymbol::withCStringNoCopy(symbol)) == NULL) {
1274 		goto exit;
1275 	}
1276 
1277 	data  = value ? kOSBooleanTrue : kOSBooleanFalse;
1278 	ret = gIOOptionsEntry->setProperty(sym, data);
1279 
1280 	sym->release();
1281 
1282 	/* success, force the NVRAM to flush writes */
1283 	if (ret == true) {
1284 		gIOOptionsEntry->sync();
1285 	}
1286 
1287 exit:
1288 	return ret;
1289 }
1290 
1291 static boolean_t
PEWriteNVRAMPropertyInternal(const char * symbol,boolean_t copySymbol,const void * value,const unsigned int len)1292 PEWriteNVRAMPropertyInternal(const char *symbol, boolean_t copySymbol, const void *value,
1293     const unsigned int len)
1294 {
1295 	const OSSymbol *sym;
1296 	OSData *data;
1297 	bool ret = false;
1298 
1299 	if (!symbol || !value || !len) {
1300 		goto err;
1301 	}
1302 
1303 	if (init_gIOOptionsEntry() < 0) {
1304 		goto err;
1305 	}
1306 
1307 	if (copySymbol == TRUE) {
1308 		sym = OSSymbol::withCString(symbol);
1309 	} else {
1310 		sym = OSSymbol::withCStringNoCopy(symbol);
1311 	}
1312 
1313 	if (!sym) {
1314 		goto err;
1315 	}
1316 
1317 	data = OSData::withBytes((void *) value, len);
1318 	if (!data) {
1319 		goto sym_done;
1320 	}
1321 
1322 	ret = gIOOptionsEntry->setProperty(sym, data);
1323 	data->release();
1324 
1325 sym_done:
1326 	sym->release();
1327 
1328 	if (ret == true) {
1329 		gIOOptionsEntry->sync();
1330 		return TRUE;
1331 	}
1332 
1333 err:
1334 	return FALSE;
1335 }
1336 
1337 boolean_t
PEWriteNVRAMProperty(const char * symbol,const void * value,const unsigned int len)1338 PEWriteNVRAMProperty(const char *symbol, const void *value,
1339     const unsigned int len)
1340 {
1341 	return PEWriteNVRAMPropertyInternal(symbol, FALSE, value, len);
1342 }
1343 
1344 boolean_t
PEWriteNVRAMPropertyWithCopy(const char * symbol,const void * value,const unsigned int len)1345 PEWriteNVRAMPropertyWithCopy(const char *symbol, const void *value,
1346     const unsigned int len)
1347 {
1348 	return PEWriteNVRAMPropertyInternal(symbol, TRUE, value, len);
1349 }
1350 
1351 boolean_t
PERemoveNVRAMProperty(const char * symbol)1352 PERemoveNVRAMProperty(const char *symbol)
1353 {
1354 	const OSSymbol *sym;
1355 
1356 	if (!symbol) {
1357 		goto err;
1358 	}
1359 
1360 	if (init_gIOOptionsEntry() < 0) {
1361 		goto err;
1362 	}
1363 
1364 	sym = OSSymbol::withCStringNoCopy(symbol);
1365 	if (!sym) {
1366 		goto err;
1367 	}
1368 
1369 	gIOOptionsEntry->removeProperty(sym);
1370 
1371 	sym->release();
1372 
1373 	gIOOptionsEntry->sync();
1374 	return TRUE;
1375 
1376 err:
1377 	return FALSE;
1378 }
1379 
1380 boolean_t
PESyncNVRAM(void)1381 PESyncNVRAM(void)
1382 {
1383 	if (gIOOptionsEntry != nullptr) {
1384 		gIOOptionsEntry->sync();
1385 	}
1386 
1387 	return TRUE;
1388 }
1389 
1390 long
PEGetGMTTimeOfDay(void)1391 PEGetGMTTimeOfDay(void)
1392 {
1393 	clock_sec_t     secs;
1394 	clock_usec_t    usecs;
1395 
1396 	PEGetUTCTimeOfDay(&secs, &usecs);
1397 	return secs;
1398 }
1399 
1400 void
PESetGMTTimeOfDay(long secs)1401 PESetGMTTimeOfDay(long secs)
1402 {
1403 	PESetUTCTimeOfDay(secs, 0);
1404 }
1405 
1406 void
PEGetUTCTimeOfDay(clock_sec_t * secs,clock_usec_t * usecs)1407 PEGetUTCTimeOfDay(clock_sec_t * secs, clock_usec_t * usecs)
1408 {
1409 	clock_nsec_t    nsecs = 0;
1410 
1411 	*secs = 0;
1412 	if (gIOPlatform) {
1413 		gIOPlatform->getUTCTimeOfDay(secs, &nsecs);
1414 	}
1415 
1416 	assert(nsecs < NSEC_PER_SEC);
1417 	*usecs = nsecs / NSEC_PER_USEC;
1418 }
1419 
1420 void
PESetUTCTimeOfDay(clock_sec_t secs,clock_usec_t usecs)1421 PESetUTCTimeOfDay(clock_sec_t secs, clock_usec_t usecs)
1422 {
1423 	assert(usecs < USEC_PER_SEC);
1424 	if (gIOPlatform) {
1425 		gIOPlatform->setUTCTimeOfDay(secs, usecs * NSEC_PER_USEC);
1426 	}
1427 }
1428 
1429 coprocessor_type_t
PEGetCoprocessorVersion(void)1430 PEGetCoprocessorVersion( void )
1431 {
1432 	coprocessor_type_t coprocessor_version = kCoprocessorVersionNone;
1433 #if defined(__x86_64__)
1434 	IORegistryEntry     *platform_entry = NULL;
1435 	OSData              *coprocessor_version_obj = NULL;
1436 
1437 	platform_entry = IORegistryEntry::fromPath(kIODeviceTreePlane ":/efi/platform");
1438 	if (platform_entry != NULL) {
1439 		coprocessor_version_obj = OSDynamicCast(OSData, platform_entry->getProperty("apple-coprocessor-version"));
1440 		if ((coprocessor_version_obj != NULL) && (coprocessor_version_obj->getLength() <= sizeof(uint64_t))) {
1441 			memcpy(&coprocessor_version, coprocessor_version_obj->getBytesNoCopy(), coprocessor_version_obj->getLength());
1442 		}
1443 		platform_entry->release();
1444 	}
1445 #endif
1446 	return coprocessor_version;
1447 }
1448 } /* extern "C" */
1449 
1450 bool gIOPlatformUUIDAndSerialDone = false;
1451 
1452 void
publishPlatformUUIDAndSerial(void)1453 IOPlatformExpert::publishPlatformUUIDAndSerial( void )
1454 {
1455 	if (!gIOPlatformUUIDAndSerialDone) {
1456 		// Parse the serial-number data and publish a user-readable string
1457 		if (NULL == getProvider()->getProperty(kIOPlatformSerialNumberKey)) {
1458 			OSData* mydata = (OSData*) (getProvider()->getProperty("serial-number"));
1459 			if (mydata != NULL) {
1460 				OSString *serNoString = createSystemSerialNumberString(mydata);
1461 				if (serNoString != NULL) {
1462 					getProvider()->setProperty(kIOPlatformSerialNumberKey, serNoString);
1463 					serNoString->release();
1464 				}
1465 			}
1466 		}
1467 		IOPlatformExpertDevice *provider = OSDynamicCast(IOPlatformExpertDevice, getProvider());
1468 		assert(provider != NULL);
1469 		provider->generatePlatformUUID();
1470 	}
1471 
1472 	if (gIOPlatformUUIDAndSerialDone) {
1473 		publishResource(kIOPlatformUUIDKey, getProvider()->getProperty(kIOPlatformUUIDKey));
1474 	}
1475 }
1476 
1477 void
publishNVRAM(void)1478 IOPlatformExpert::publishNVRAM( void )
1479 {
1480 	if (init_gIOOptionsEntry() < 0) {
1481 		IOPlatformExpertDevice *provider = OSDynamicCast(IOPlatformExpertDevice, getProvider());
1482 		assert(provider != NULL);
1483 		provider->createNVRAM();
1484 	}
1485 	if (gIOOptionsEntry != NULL) {
1486 		gIOOptionsEntry->registerService();
1487 	}
1488 }
1489 
1490 void
registerNVRAMController(IONVRAMController * caller)1491 IOPlatformExpert::registerNVRAMController(IONVRAMController * caller)
1492 {
1493 #if defined(__x86_64__)
1494 	OSData *          data;
1495 	IORegistryEntry * entry;
1496 
1497 	/*
1498 	 * If we have panic debugging enabled WITHOUT behavior to reboot after any crash (DB_REBOOT_ALWAYS)
1499 	 * and we are on a co-processor system that has the panic SoC watchdog enabled, disable
1500 	 * cross panics so that the co-processor doesn't cause the system
1501 	 * to reset when we enter the debugger or hit a panic on the x86 side.
1502 	 */
1503 	if (panicDebugging && !(debug_boot_arg & DB_REBOOT_ALWAYS)) {
1504 		entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
1505 		if (entry) {
1506 			data = OSDynamicCast( OSData, entry->getProperty( APPLE_VENDOR_VARIABLE_GUID":BridgeOSPanicWatchdogEnabled" ));
1507 			if (data && (data->getLength() == sizeof(UInt8))) {
1508 				UInt8 *panicWatchdogEnabled = (UInt8 *) data->getBytesNoCopy();
1509 				UInt32 debug_flags = 0;
1510 				if (*panicWatchdogEnabled || (PE_i_can_has_debugger(&debug_flags) &&
1511 				    (debug_flags & DB_DISABLE_CROSS_PANIC))) {
1512 					coprocessor_cross_panic_enabled = FALSE;
1513 				}
1514 			}
1515 			entry->release();
1516 		}
1517 	}
1518 
1519 #if (DEVELOPMENT || DEBUG)
1520 	entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
1521 	if (entry) {
1522 		data = OSDynamicCast( OSData, entry->getProperty(nvram_osenvironment));
1523 		if (data) {
1524 			sysctl_set_osenvironment(data->getLength(), data->getBytesNoCopy());
1525 			entry->removeProperty(nvram_osenvironment);
1526 			IODTNVRAM * nvramOptionsEntry = OSDynamicCast(IODTNVRAM, entry);
1527 			if (nvramOptionsEntry) {
1528 				nvramOptionsEntry->sync();
1529 			}
1530 		}
1531 		entry->release();
1532 	}
1533 	sysctl_unblock_osenvironment();
1534 #endif
1535 	/* on intel the UUID must be published after nvram is available */
1536 	publishPlatformUUIDAndSerial();
1537 
1538 #endif /* defined(__x86_64__) */
1539 
1540 	publishResource("IONVRAM");
1541 }
1542 
1543 IOReturn
callPlatformFunction(const OSSymbol * functionName,bool waitForFunction,void * param1,void * param2,void * param3,void * param4)1544 IOPlatformExpert::callPlatformFunction(const OSSymbol *functionName,
1545     bool waitForFunction,
1546     void *param1, void *param2,
1547     void *param3, void *param4)
1548 {
1549 	IOService *service, *_resources;
1550 	OSObject  *prop = NULL;
1551 	IOReturn   ret;
1552 
1553 	if (functionName == gIOPlatformQuiesceActionKey ||
1554 	    functionName == gIOPlatformActiveActionKey ||
1555 	    functionName == gIOPlatformPanicActionKey) {
1556 		/*
1557 		 * Services which register for IOPlatformQuiesceAction / IOPlatformActiveAction / IOPlatformPanicAction
1558 		 * must consume that event themselves, without passing it up to super/IOPlatformExpert.
1559 		 */
1560 		if (gEnforcePlatformActionSafety) {
1561 			panic("Class %s passed the %s action to IOPlatformExpert",
1562 			    getMetaClass()->getClassName(), functionName->getCStringNoCopy());
1563 		}
1564 	}
1565 
1566 	if (waitForFunction) {
1567 		_resources = waitForService(resourceMatching(functionName));
1568 	} else {
1569 		_resources = getResourceService();
1570 	}
1571 	if (_resources == NULL) {
1572 		return kIOReturnUnsupported;
1573 	}
1574 
1575 	prop = _resources->copyProperty(functionName);
1576 	service = OSDynamicCast(IOService, prop);
1577 	if (service == NULL) {
1578 		ret = kIOReturnUnsupported;
1579 		goto finish;
1580 	}
1581 
1582 	ret = service->callPlatformFunction(functionName, waitForFunction,
1583 	    param1, param2, param3, param4);
1584 
1585 finish:
1586 	OSSafeReleaseNULL(prop);
1587 	return ret;
1588 }
1589 
1590 IOByteCount
savePanicInfo(UInt8 * buffer,IOByteCount length)1591 IOPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length)
1592 {
1593 	return 0;
1594 }
1595 
1596 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1597 
1598 #undef super
1599 #define super IOPlatformExpert
1600 
1601 OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert, IOPlatformExpert )
1602 
1603 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 0);
1604 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 1);
1605 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 2);
1606 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 3);
1607 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 4);
1608 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 5);
1609 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 6);
1610 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 7);
1611 
1612 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1613 
1614 IOService *
probe(IOService * provider,SInt32 * score)1615 IODTPlatformExpert::probe( IOService * provider,
1616     SInt32 * score )
1617 {
1618 	if (!super::probe( provider, score)) {
1619 		return NULL;
1620 	}
1621 
1622 	// check machine types
1623 	if (!provider->compareNames( getProperty( gIONameMatchKey ))) {
1624 		return NULL;
1625 	}
1626 
1627 	return this;
1628 }
1629 
1630 bool
configure(IOService * provider)1631 IODTPlatformExpert::configure( IOService * provider )
1632 {
1633 	if (!super::configure( provider)) {
1634 		return false;
1635 	}
1636 
1637 	processTopLevel( provider );
1638 
1639 	return true;
1640 }
1641 
1642 IOService *
createNub(IORegistryEntry * from)1643 IODTPlatformExpert::createNub( IORegistryEntry * from )
1644 {
1645 	IOService *         nub;
1646 
1647 	nub = new IOPlatformDevice;
1648 	if (nub) {
1649 		if (!nub->init( from, gIODTPlane )) {
1650 			nub->free();
1651 			nub = NULL;
1652 		}
1653 	}
1654 	return nub;
1655 }
1656 
1657 bool
createNubs(IOService * parent,OSIterator * iter)1658 IODTPlatformExpert::createNubs( IOService * parent, OSIterator * iter )
1659 {
1660 	IORegistryEntry *   next;
1661 	IOService *         nub = NULL;
1662 	bool                ok = true;
1663 
1664 	if (iter) {
1665 		while ((next = (IORegistryEntry *) iter->getNextObject())) {
1666 			OSSafeReleaseNULL(nub);
1667 
1668 			if (NULL == (nub = createNub( next ))) {
1669 				continue;
1670 			}
1671 
1672 			nub->attach( parent );
1673 #if !defined(__x86_64__)
1674 			OSData *tmpData = (OSData *)next->getProperty("device_type");
1675 			if (tmpData == NULL) {
1676 				nub->registerService();
1677 				continue;
1678 			}
1679 
1680 			char *device_type = (char *)tmpData->getBytesNoCopy();
1681 			if (strcmp(device_type, "cpu") != 0) {
1682 				nub->registerService();
1683 				continue;
1684 			}
1685 
1686 			tmpData = (OSData *)next->getProperty("reg");
1687 			assert(tmpData != NULL);
1688 			assert(tmpData->getLength() >= sizeof(UInt32));
1689 
1690 			uint32_t phys_id = *(UInt32 *)tmpData->getBytesNoCopy();
1691 			int logical_cpu_id = ml_get_cpu_number(phys_id);
1692 			int logical_cluster_id = ml_get_cluster_number(phys_id);
1693 
1694 			/*
1695 			 * If the following condition triggers, it means that a CPU that was present in the DT
1696 			 * was ignored by XNU at topology parsing time. This can happen currently when using the
1697 			 * cpus=N boot-arg; for example, cpus=1 will cause XNU to parse and enable a single CPU.
1698 			 *
1699 			 * Note that this condition will not trigger for harvested cores because these do not show up
1700 			 * in the DT/IORegistry in the first place.
1701 			 */
1702 			if (logical_cpu_id < 0) {
1703 				nub->registerService();
1704 				continue;
1705 			}
1706 
1707 			__assert_only bool logical_id_added_to_ioreg = nub->setProperty("logical-cpu-id", logical_cpu_id, 32U);
1708 			assert(logical_id_added_to_ioreg == true);
1709 			logical_id_added_to_ioreg = nub->setProperty("logical-cluster-id", logical_cluster_id, 32U);
1710 			assert(logical_id_added_to_ioreg == true);
1711 #endif
1712 			nub->registerService();
1713 		}
1714 		OSSafeReleaseNULL(nub);
1715 		iter->release();
1716 	}
1717 
1718 	return ok;
1719 }
1720 
1721 void
processTopLevel(IORegistryEntry * rootEntry)1722 IODTPlatformExpert::processTopLevel( IORegistryEntry * rootEntry )
1723 {
1724 	OSIterator *        kids;
1725 	IORegistryEntry *   next;
1726 	IORegistryEntry *   cpus;
1727 
1728 	// infanticide
1729 	kids = IODTFindMatchingEntries( rootEntry, 0, deleteList());
1730 	if (kids) {
1731 		while ((next = (IORegistryEntry *)kids->getNextObject())) {
1732 			next->detachAll( gIODTPlane);
1733 		}
1734 		kids->release();
1735 	}
1736 
1737 	publishNVRAM();
1738 	assert(gIOOptionsEntry != NULL); // subclasses that do their own NVRAM initialization shouldn't be calling this
1739 	dtNVRAM = gIOOptionsEntry;
1740 
1741 	// Publish the cpus.
1742 	cpus = rootEntry->childFromPath( "cpus", gIODTPlane);
1743 	if (cpus) {
1744 		createNubs( this, IODTFindMatchingEntries( cpus, kIODTExclusive, NULL));
1745 		cpus->release();
1746 	}
1747 
1748 	// publish top level, minus excludeList
1749 	createNubs( this, IODTFindMatchingEntries( rootEntry, kIODTExclusive, excludeList()));
1750 }
1751 
1752 IOReturn
getNubResources(IOService * nub)1753 IODTPlatformExpert::getNubResources( IOService * nub )
1754 {
1755 	if (nub->getDeviceMemory()) {
1756 		return kIOReturnSuccess;
1757 	}
1758 
1759 	IODTResolveAddressing( nub, "reg", NULL);
1760 
1761 	return kIOReturnSuccess;
1762 }
1763 
1764 bool
compareNubName(const IOService * nub,OSString * name,OSString ** matched) const1765 IODTPlatformExpert::compareNubName( const IOService * nub,
1766     OSString * name, OSString ** matched ) const
1767 {
1768 	return IODTCompareNubName( nub, name, matched )
1769 	       || super::compareNubName( nub, name, matched);
1770 }
1771 
1772 
1773 /*
1774  * Do not use this method directly, it returns inconsistent results
1775  * across architectures and is considered deprecated.
1776  *
1777  * Use getTargetName and getProductName respectively.  For example:
1778  *
1779  * targetName: J137AP
1780  * productName: iMacPro1,1
1781  *
1782  * targetName: D331pAP
1783  * productName: iPhone11,6
1784  */
1785 
1786 bool
getModelName(char * name,int maxLength)1787 IODTPlatformExpert::getModelName( char * name, int maxLength )
1788 {
1789 	OSData *            prop;
1790 	const char *        str;
1791 	int                 len;
1792 	char                c;
1793 	bool                ok = false;
1794 
1795 	maxLength--;
1796 
1797 	prop = (OSData *) getProvider()->getProperty( gIODTCompatibleKey );
1798 	if (prop) {
1799 		str = (const char *) prop->getBytesNoCopy();
1800 
1801 		if (0 == strncmp( str, "AAPL,", strlen( "AAPL," ))) {
1802 			str += strlen( "AAPL," );
1803 		}
1804 
1805 		len = 0;
1806 		while ((c = *str++)) {
1807 			if ((c == '/') || (c == ' ')) {
1808 				c = '-';
1809 			}
1810 
1811 			name[len++] = c;
1812 			if (len >= maxLength) {
1813 				break;
1814 			}
1815 		}
1816 
1817 		name[len] = 0;
1818 		ok = true;
1819 	}
1820 	return ok;
1821 }
1822 
1823 /*
1824  * Do not use this method directly, it returns inconsistent results
1825  * across architectures and is considered deprecated.
1826  *
1827  * Use getTargetName and getProductName respectively.  For example:
1828  *
1829  * targetName: J137AP
1830  * productName: iMacPro1,1
1831  *
1832  * targetName: D331pAP
1833  * productName: iPhone11,6
1834  */
1835 
1836 bool
getMachineName(char * name,int maxLength)1837 IODTPlatformExpert::getMachineName( char * name, int maxLength )
1838 {
1839 	OSData *            prop;
1840 	bool                ok = false;
1841 
1842 	maxLength--;
1843 	prop = (OSData *) getProvider()->getProperty( gIODTModelKey );
1844 	ok = (NULL != prop);
1845 
1846 	if (ok) {
1847 		strlcpy( name, (const char *) prop->getBytesNoCopy(), maxLength );
1848 	}
1849 
1850 	return ok;
1851 }
1852 
1853 /* Examples: J137AP, D331pAP... */
1854 
1855 bool
getTargetName(char * name,int maxLength)1856 IODTPlatformExpert::getTargetName( char * name, int maxLength )
1857 {
1858 #if __x86_64__
1859 	OSData *            prop;
1860 
1861 	const OSSymbol *        key = gIODTBridgeModelKey;
1862 
1863 	maxLength--;
1864 	prop = (OSData *) getProvider()->getProperty( key );
1865 
1866 	if (prop == NULL) {
1867 		// This happens if there is no bridge.
1868 		char const * const  unknown = "";
1869 
1870 		strlcpy( name, unknown, maxLength );
1871 	} else {
1872 		strlcpy( name, (const char *)prop->getBytesNoCopy(), maxLength );
1873 	}
1874 
1875 	return true;
1876 #else
1877 	return getModelName( name, maxLength );
1878 #endif
1879 }
1880 
1881 /* Examples: iMacPro1,1, iPhone11,6... */
1882 
1883 bool
getProductName(char * name,int maxLength)1884 IODTPlatformExpert::getProductName( char * name, int maxLength )
1885 {
1886 #if __x86_64__
1887 	return getModelName( name, maxLength );
1888 #else
1889 	return getMachineName( name, maxLength );
1890 #endif
1891 }
1892 
1893 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1894 
1895 void
registerNVRAMController(IONVRAMController * nvram)1896 IODTPlatformExpert::registerNVRAMController( IONVRAMController * nvram )
1897 {
1898 	if (dtNVRAM) {
1899 		dtNVRAM->registerNVRAMController(nvram);
1900 	}
1901 
1902 	super::registerNVRAMController(nvram);
1903 }
1904 
1905 int
haltRestart(unsigned int type)1906 IODTPlatformExpert::haltRestart(unsigned int type)
1907 {
1908 	return super::haltRestart(type);
1909 }
1910 
1911 IOReturn
readXPRAM(IOByteCount offset,UInt8 * buffer,IOByteCount length)1912 IODTPlatformExpert::readXPRAM(IOByteCount offset, UInt8 * buffer,
1913     IOByteCount length)
1914 {
1915 	if (dtNVRAM) {
1916 		return dtNVRAM->readXPRAM(offset, buffer, length);
1917 	} else {
1918 		return kIOReturnNotReady;
1919 	}
1920 }
1921 
1922 IOReturn
writeXPRAM(IOByteCount offset,UInt8 * buffer,IOByteCount length)1923 IODTPlatformExpert::writeXPRAM(IOByteCount offset, UInt8 * buffer,
1924     IOByteCount length)
1925 {
1926 	if (dtNVRAM) {
1927 		return dtNVRAM->writeXPRAM(offset, buffer, length);
1928 	} else {
1929 		return kIOReturnNotReady;
1930 	}
1931 }
1932 
1933 IOReturn
readNVRAMProperty(IORegistryEntry * entry,const OSSymbol ** name,OSData ** value)1934 IODTPlatformExpert::readNVRAMProperty(
1935 	IORegistryEntry * entry,
1936 	const OSSymbol ** name, OSData ** value )
1937 {
1938 	if (dtNVRAM) {
1939 		return dtNVRAM->readNVRAMProperty(entry, name, value);
1940 	} else {
1941 		return kIOReturnNotReady;
1942 	}
1943 }
1944 
1945 IOReturn
readNVRAMProperty(IORegistryEntry * entry,OSSharedPtr<const OSSymbol> & name,OSSharedPtr<OSData> & value)1946 IODTPlatformExpert::readNVRAMProperty(
1947 	IORegistryEntry * entry,
1948 	OSSharedPtr<const OSSymbol>& name, OSSharedPtr<OSData>& value )
1949 {
1950 	const OSSymbol* nameRaw = NULL;
1951 	OSData* valueRaw = NULL;
1952 
1953 	IOReturn result = readNVRAMProperty(entry, &nameRaw, &valueRaw);
1954 
1955 	name.reset(nameRaw, OSNoRetain);
1956 	value.reset(valueRaw, OSNoRetain);
1957 
1958 	return result;
1959 }
1960 
1961 IOReturn
writeNVRAMProperty(IORegistryEntry * entry,const OSSymbol * name,OSData * value)1962 IODTPlatformExpert::writeNVRAMProperty(
1963 	IORegistryEntry * entry,
1964 	const OSSymbol * name, OSData * value )
1965 {
1966 	if (dtNVRAM) {
1967 		return dtNVRAM->writeNVRAMProperty(entry, name, value);
1968 	} else {
1969 		return kIOReturnNotReady;
1970 	}
1971 }
1972 
1973 OSDictionary *
getNVRAMPartitions(void)1974 IODTPlatformExpert::getNVRAMPartitions(void)
1975 {
1976 	if (dtNVRAM) {
1977 		return dtNVRAM->getNVRAMPartitions();
1978 	} else {
1979 		return NULL;
1980 	}
1981 }
1982 
1983 IOReturn
readNVRAMPartition(const OSSymbol * partitionID,IOByteCount offset,UInt8 * buffer,IOByteCount length)1984 IODTPlatformExpert::readNVRAMPartition(const OSSymbol * partitionID,
1985     IOByteCount offset, UInt8 * buffer,
1986     IOByteCount length)
1987 {
1988 	if (dtNVRAM) {
1989 		return dtNVRAM->readNVRAMPartition(partitionID, offset,
1990 		           buffer, length);
1991 	} else {
1992 		return kIOReturnNotReady;
1993 	}
1994 }
1995 
1996 IOReturn
writeNVRAMPartition(const OSSymbol * partitionID,IOByteCount offset,UInt8 * buffer,IOByteCount length)1997 IODTPlatformExpert::writeNVRAMPartition(const OSSymbol * partitionID,
1998     IOByteCount offset, UInt8 * buffer,
1999     IOByteCount length)
2000 {
2001 	if (dtNVRAM) {
2002 		return dtNVRAM->writeNVRAMPartition(partitionID, offset,
2003 		           buffer, length);
2004 	} else {
2005 		return kIOReturnNotReady;
2006 	}
2007 }
2008 
2009 IOByteCount
savePanicInfo(UInt8 * buffer,IOByteCount length)2010 IODTPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length)
2011 {
2012 	IOByteCount lengthSaved = 0;
2013 
2014 	if (dtNVRAM) {
2015 		lengthSaved = dtNVRAM->savePanicInfo(buffer, length);
2016 	}
2017 
2018 	if (lengthSaved == 0) {
2019 		lengthSaved = super::savePanicInfo(buffer, length);
2020 	}
2021 
2022 	return lengthSaved;
2023 }
2024 
2025 OSString*
createSystemSerialNumberString(OSData * myProperty)2026 IODTPlatformExpert::createSystemSerialNumberString(OSData* myProperty)
2027 {
2028 	UInt8* serialNumber;
2029 	unsigned int serialNumberSize;
2030 	unsigned short pos = 0;
2031 	char* temp;
2032 	char SerialNo[30];
2033 
2034 	if (myProperty != NULL) {
2035 		serialNumberSize = myProperty->getLength();
2036 		serialNumber = (UInt8*)(myProperty->getBytesNoCopy());
2037 		temp = (char*)serialNumber;
2038 		if (serialNumberSize > 0) {
2039 			// check to see if this is a CTO serial number...
2040 			while (pos < serialNumberSize && temp[pos] != '-') {
2041 				pos++;
2042 			}
2043 
2044 			if (pos < serialNumberSize) { // there was a hyphen, so it's a CTO serial number
2045 				memcpy(SerialNo, serialNumber + 12, 8);
2046 				memcpy(&SerialNo[8], serialNumber, 3);
2047 				SerialNo[11] = '-';
2048 				memcpy(&SerialNo[12], serialNumber + 3, 8);
2049 				SerialNo[20] = 0;
2050 			} else { // just a normal serial number
2051 				memcpy(SerialNo, serialNumber + 13, 8);
2052 				memcpy(&SerialNo[8], serialNumber, 3);
2053 				SerialNo[11] = 0;
2054 			}
2055 			return OSString::withCString(SerialNo);
2056 		}
2057 	}
2058 	return NULL;
2059 }
2060 
2061 
2062 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2063 
2064 #undef super
2065 #define super IOService
2066 
2067 OSDefineMetaClassAndStructors(IOPlatformExpertDevice, IOService)
2068 
2069 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 0);
2070 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 1);
2071 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 2);
2072 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 3);
2073 
2074 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2075 
2076 bool
compareName(OSString * name,OSString ** matched) const2077 IOPlatformExpertDevice::compareName( OSString * name,
2078     OSString ** matched ) const
2079 {
2080 	return IODTCompareNubName( this, name, matched );
2081 }
2082 
2083 bool
init(void * dtRoot)2084 IOPlatformExpertDevice::init(void *dtRoot)
2085 {
2086 	IORegistryEntry *   dt = NULL;
2087 	bool                ok;
2088 
2089 	if ((dtRoot != NULL) && (dt = IODeviceTreeAlloc(dtRoot))) {
2090 		ok = super::init( dt, gIODTPlane );
2091 	} else {
2092 		ok = super::init();
2093 	}
2094 
2095 	if (!ok) {
2096 		return false;
2097 	}
2098 
2099 	return true;
2100 }
2101 
2102 bool
startIOServiceMatching(void)2103 IOPlatformExpertDevice::startIOServiceMatching(void)
2104 {
2105 	workLoop = IOWorkLoop::workLoop();
2106 	if (!workLoop) {
2107 		return false;
2108 	}
2109 
2110 	registerService();
2111 
2112 	return true;
2113 }
2114 
2115 IOWorkLoop *
getWorkLoop() const2116 IOPlatformExpertDevice::getWorkLoop() const
2117 {
2118 	return workLoop;
2119 }
2120 
2121 IOReturn
setProperties(OSObject * properties)2122 IOPlatformExpertDevice::setProperties( OSObject * properties )
2123 {
2124 	return kIOReturnUnsupported;
2125 }
2126 
2127 IOReturn
newUserClient(task_t owningTask,void * securityID,UInt32 type,OSDictionary * properties,IOUserClient ** handler)2128 IOPlatformExpertDevice::newUserClient( task_t owningTask, void * securityID,
2129     UInt32 type, OSDictionary * properties,
2130     IOUserClient ** handler )
2131 {
2132 	IOReturn            err = kIOReturnSuccess;
2133 	IOUserClient *      newConnect = NULL;
2134 	IOUserClient *      theConnect = NULL;
2135 
2136 	switch (type) {
2137 	case kIOKitDiagnosticsClientType:
2138 		newConnect = IOKitDiagnosticsClient::withTask(owningTask);
2139 		if (!newConnect) {
2140 			err = kIOReturnNotPermitted;
2141 		}
2142 		break;
2143 	case kIOKitUserServerClientType:
2144 		newConnect = IOUserServer::withTask(owningTask);
2145 		if (!newConnect) {
2146 			err = kIOReturnNotPermitted;
2147 		}
2148 		break;
2149 	default:
2150 		err = kIOReturnBadArgument;
2151 	}
2152 
2153 	if (newConnect) {
2154 		if ((false == newConnect->attach(this))
2155 		    || (false == newConnect->start(this))) {
2156 			newConnect->detach( this );
2157 			newConnect->release();
2158 			err = kIOReturnNotPermitted;
2159 		} else {
2160 			theConnect = newConnect;
2161 		}
2162 	}
2163 
2164 	*handler = theConnect;
2165 	return err;
2166 }
2167 
2168 void
free()2169 IOPlatformExpertDevice::free()
2170 {
2171 	if (workLoop) {
2172 		workLoop->release();
2173 	}
2174 }
2175 
2176 void
configureDefaults(void)2177 IOPlatformExpertDevice::configureDefaults( void )
2178 {
2179 	createNVRAM();
2180 	// Parse the serial-number data and publish a user-readable string
2181 	OSData* mydata = (OSData*) (getProperty("serial-number"));
2182 	if (mydata != NULL) {
2183 		OSString *serNoString = OSString::withCString((const char *)mydata->getBytesNoCopy());
2184 		if (serNoString != NULL) {
2185 			setProperty(kIOPlatformSerialNumberKey, serNoString);
2186 			serNoString->release();
2187 		}
2188 	}
2189 	generatePlatformUUID();
2190 }
2191 
2192 void
createNVRAM(void)2193 IOPlatformExpertDevice::createNVRAM( void )
2194 {
2195 	/*
2196 	 * Publish an IODTNVRAM class on /options, if present.
2197 	 * DT-based platforms may need NVRAM access prior to the start
2198 	 * of IOKit matching, to support security-related operations
2199 	 * that must happen before machine_lockdown().
2200 	 */
2201 	IORegistryEntry *options = IORegistryEntry::fromPath("/options", gIODTPlane);
2202 	if (options == NULL) {
2203 		return; // /options may not be present
2204 	}
2205 
2206 	assert(gIOOptionsEntry == NULL);
2207 	gIOOptionsEntry = new IODTNVRAM;
2208 
2209 	assert(gIOOptionsEntry != NULL);
2210 
2211 	gIOOptionsEntry->init(options, gIODTPlane);
2212 	gIOOptionsEntry->attach(this);
2213 	gIOOptionsEntry->start(this);
2214 	options->release();
2215 }
2216 
2217 void
generatePlatformUUID(void)2218 IOPlatformExpertDevice::generatePlatformUUID( void )
2219 {
2220 	IORegistryEntry * entry;
2221 	OSString *        string = NULL;
2222 	uuid_string_t     uuid;
2223 
2224 #if !defined(__x86_64__)
2225 	entry = IORegistryEntry::fromPath( "/chosen", gIODTPlane );
2226 	if (entry) {
2227 		OSData * data1;
2228 
2229 		data1 = OSDynamicCast( OSData, entry->getProperty( "unique-chip-id" ));
2230 		if (data1 && data1->getLength() == 8) {
2231 			OSData * data2;
2232 
2233 			data2 = OSDynamicCast( OSData, entry->getProperty( "chip-id" ));
2234 			if (data2 && data2->getLength() == 4) {
2235 				SHA1_CTX     context;
2236 				uint8_t      digest[SHA_DIGEST_LENGTH];
2237 				const uuid_t space = { 0xA6, 0xDD, 0x4C, 0xCB, 0xB5, 0xE8, 0x4A, 0xF5, 0xAC, 0xDD, 0xB6, 0xDC, 0x6A, 0x05, 0x42, 0xB8 };
2238 
2239 				SHA1Init( &context );
2240 				SHA1Update( &context, space, sizeof(space));
2241 				SHA1Update( &context, data1->getBytesNoCopy(), data1->getLength());
2242 				SHA1Update( &context, data2->getBytesNoCopy(), data2->getLength());
2243 				SHA1Final( digest, &context );
2244 
2245 				digest[6] = (digest[6] & 0x0F) | 0x50;
2246 				digest[8] = (digest[8] & 0x3F) | 0x80;
2247 
2248 				uuid_unparse( digest, uuid );
2249 				string = OSString::withCString( uuid );
2250 			}
2251 		}
2252 
2253 		entry->release();
2254 	}
2255 #else /* !defined(__x86_64__) */
2256 	OSData * data;
2257 
2258 	entry = IORegistryEntry::fromPath( "/efi/platform", gIODTPlane );
2259 	if (entry) {
2260 		data = OSDynamicCast( OSData, entry->getProperty( "system-id" ));
2261 		if (data && data->getLength() == 16) {
2262 			SHA1_CTX     context;
2263 			uint8_t      digest[SHA_DIGEST_LENGTH];
2264 			const uuid_t space = { 0x2A, 0x06, 0x19, 0x90, 0xD3, 0x8D, 0x44, 0x40, 0xA1, 0x39, 0xC4, 0x97, 0x70, 0x37, 0x65, 0xAC };
2265 
2266 			SHA1Init( &context );
2267 			SHA1Update( &context, space, sizeof(space));
2268 			SHA1Update( &context, data->getBytesNoCopy(), data->getLength());
2269 			SHA1Final( digest, &context );
2270 
2271 			digest[6] = (digest[6] & 0x0F) | 0x50;
2272 			digest[8] = (digest[8] & 0x3F) | 0x80;
2273 
2274 			uuid_unparse( digest, uuid );
2275 			string = OSString::withCString( uuid );
2276 		}
2277 
2278 		entry->release();
2279 	}
2280 	if (!string) {
2281 		/* vmware still runs this path */
2282 		entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
2283 		if (entry) {
2284 			data = OSDynamicCast( OSData, entry->getProperty( "platform-uuid" ));
2285 			if (data && data->getLength() == sizeof(uuid_t)) {
2286 				uuid_unparse((uint8_t *) data->getBytesNoCopy(), uuid );
2287 				string = OSString::withCString( uuid );
2288 			}
2289 			entry->release();
2290 		}
2291 	}
2292 #endif /* defined(__x86_64__) */
2293 
2294 	if (string) {
2295 		setProperty( kIOPlatformUUIDKey, string );
2296 		gIOPlatformUUIDAndSerialDone = true;
2297 
2298 		string->release();
2299 	}
2300 }
2301 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2302 
2303 #undef super
2304 #define super IOService
2305 
2306 OSDefineMetaClassAndStructors(IOPlatformDevice, IOService)
2307 
2308 OSMetaClassDefineReservedUnused(IOPlatformDevice, 0);
2309 OSMetaClassDefineReservedUnused(IOPlatformDevice, 1);
2310 OSMetaClassDefineReservedUnused(IOPlatformDevice, 2);
2311 OSMetaClassDefineReservedUnused(IOPlatformDevice, 3);
2312 
2313 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2314 
2315 bool
compareName(OSString * name,OSString ** matched) const2316 IOPlatformDevice::compareName( OSString * name,
2317     OSString ** matched ) const
2318 {
2319 	return ((IOPlatformExpert *)getProvider())->
2320 	       compareNubName( this, name, matched );
2321 }
2322 
2323 IOService *
matchLocation(IOService *)2324 IOPlatformDevice::matchLocation( IOService * /* client */ )
2325 {
2326 	return this;
2327 }
2328 
2329 IOReturn
getResources(void)2330 IOPlatformDevice::getResources( void )
2331 {
2332 	return ((IOPlatformExpert *)getProvider())->getNubResources( this );
2333 }
2334 
2335 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2336 
2337 /*********************************************************************
2338 * IOPanicPlatform class
2339 *
2340 * If no legitimate IOPlatformDevice matches, this one does and panics
2341 * the kernel with a suitable message.
2342 *********************************************************************/
2343 
2344 class IOPanicPlatform : IOPlatformExpert {
2345 	OSDeclareDefaultStructors(IOPanicPlatform);
2346 
2347 public:
2348 	bool start(IOService * provider) APPLE_KEXT_OVERRIDE;
2349 };
2350 
2351 
2352 OSDefineMetaClassAndStructors(IOPanicPlatform, IOPlatformExpert);
2353 
2354 
2355 bool
start(IOService * provider)2356 IOPanicPlatform::start(IOService * provider)
2357 {
2358 	const char * platform_name = "(unknown platform name)";
2359 
2360 	if (provider) {
2361 		platform_name = provider->getName();
2362 	}
2363 
2364 	panic("Unable to find driver for this platform: \"%s\".",
2365 	    platform_name);
2366 
2367 	return false;
2368 }
2369