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
60extern "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
71boolean_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
75void printDictionaryKeys(OSDictionary * inDictionary, char * inMsg);
76static 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 */
87uint32_t gEnforcePlatformActionSafety = 0;
88
89/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
90
91#define super IOService
92
93OSDefineMetaClassAndStructors(IOPlatformExpert, IOService)
94
95OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 0);
96OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 1);
97OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 2);
98OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 3);
99OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 4);
100OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 5);
101OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 6);
102
103OSMetaClassDefineReservedUnused(IOPlatformExpert, 7);
104OSMetaClassDefineReservedUnused(IOPlatformExpert, 8);
105OSMetaClassDefineReservedUnused(IOPlatformExpert, 9);
106OSMetaClassDefineReservedUnused(IOPlatformExpert, 10);
107OSMetaClassDefineReservedUnused(IOPlatformExpert, 11);
108
109static IOPlatformExpert * gIOPlatform;
110static OSDictionary * gIOInterruptControllers;
111static IOLock * gIOInterruptControllersLock;
112static IODTNVRAM *gIOOptionsEntry;
113
114OSSymbol * gPlatformInterruptControllerName;
115
116/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
117
118bool
119IOPlatformExpert::attach( IOService * provider )
120{
121 if (!super::attach( provider )) {
122 return false;
123 }
124
125 return true;
126}
127
128bool
129IOPlatformExpert::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(arg_string: "dart", arg_ptr: &debugFlags, max_arg: 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(capacity: 1);
160 gIOInterruptControllersLock = IOLockAlloc();
161
162 // Correct the bus frequency in the device tree.
163 busFrequency = OSData::withBytesNoCopy(bytes: (void *)&gPEClockFrequencyInfo.bus_clock_rate_hz, numBytes: 4);
164 provider->setProperty(aKey: "clock-frequency", anObject: busFrequency);
165 busFrequency->release();
166
167 gPlatformInterruptControllerName = (OSSymbol *)OSSymbol::withCStringNoCopy(cString: "IOPlatformInterruptController");
168
169 physicalRanges = IORangeAllocator::withRange(endOfRange: 0xffffffff, defaultAlignment: 1, capacity: 16,
170 options: IORangeAllocator::kLocking);
171 assert(physicalRanges);
172 setProperty(aKey: "Platform Memory Ranges", anObject: 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(arg_string: "enforce_platform_action_safety", arg_ptr: &gEnforcePlatformActionSafety,
192 max_arg: sizeof(gEnforcePlatformActionSafety));
193
194 return configure(provider);
195}
196
197bool
198IOPlatformExpert::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( anObject: dict );
211 OSSafeReleaseNULL(nub);
212 nub = createNub( from: dict );
213 dict->release();
214 if (NULL == nub) {
215 continue;
216 }
217 nub->attach( provider: this );
218 nub->registerService();
219 }
220 }
221 OSSafeReleaseNULL(nub);
222 return true;
223}
224
225IOService *
226IOPlatformExpert::createNub( OSDictionary * from )
227{
228 IOService * nub;
229
230 nub = new IOPlatformDevice;
231 if (nub) {
232 if (!nub->init( dictionary: from )) {
233 nub->release();
234 nub = NULL;
235 }
236 }
237 return nub;
238}
239
240bool
241IOPlatformExpert::compareNubName( const IOService * nub,
242 OSString * name, OSString ** matched ) const
243{
244 return nub->IORegistryEntry::compareName( name, matched );
245}
246
247bool
248IOPlatformExpert::compareNubName( const IOService * nub,
249 OSString * name, OSSharedPtr<OSString>& matched ) const
250{
251 OSString* matchedRaw = NULL;
252 bool result = compareNubName(nub, name, matched: &matchedRaw);
253 matched.reset(p: matchedRaw, OSNoRetain);
254 return result;
255}
256
257IOReturn
258IOPlatformExpert::getNubResources( IOService * nub )
259{
260 return kIOReturnSuccess;
261}
262
263long
264IOPlatformExpert::getBootROMType(void)
265{
266 return _peBootROMType;
267}
268
269long
270IOPlatformExpert::getChipSetType(void)
271{
272 return _peChipSetType;
273}
274
275long
276IOPlatformExpert::getMachineType(void)
277{
278 return _peMachineType;
279}
280
281void
282IOPlatformExpert::setBootROMType(long peBootROMType)
283{
284 _peBootROMType = peBootROMType;
285}
286
287void
288IOPlatformExpert::setChipSetType(long peChipSetType)
289{
290 _peChipSetType = peChipSetType;
291}
292
293void
294IOPlatformExpert::setMachineType(long peMachineType)
295{
296 _peMachineType = peMachineType;
297}
298
299bool
300IOPlatformExpert::getMachineName( char * /*name*/, int /*maxLength*/)
301{
302 return false;
303}
304
305bool
306IOPlatformExpert::getModelName( char * /*name*/, int /*maxLength*/)
307{
308 return false;
309}
310
311bool
312IOPlatformExpert::getTargetName( char * /*name*/, int /*maxLength*/)
313{
314 return false;
315}
316
317bool
318IOPlatformExpert::getProductName( char * /*name*/, int /*maxLength*/)
319{
320 return false;
321}
322
323OSString*
324IOPlatformExpert::createSystemSerialNumberString(OSData* myProperty)
325{
326 return NULL;
327}
328
329IORangeAllocator *
330IOPlatformExpert::getPhysicalRangeAllocator(void)
331{
332 return OSDynamicCast(IORangeAllocator,
333 getProperty("Platform Memory Ranges"));
334}
335
336int (*PE_halt_restart)(unsigned int type) = NULL;
337
338int
339IOPlatformExpert::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
370void
371IOPlatformExpert::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
393long
394IOPlatformExpert::getGMTTimeOfDay(void)
395{
396 return 0;
397}
398
399void
400IOPlatformExpert::setGMTTimeOfDay(long secs)
401{
402}
403
404
405IOReturn
406IOPlatformExpert::getConsoleInfo( PE_Video * consoleInfo )
407{
408 return PE_current_console( info: consoleInfo);
409}
410
411IOReturn
412IOPlatformExpert::setConsoleInfo( PE_Video * consoleInfo,
413 unsigned int op)
414{
415 return PE_initialize_console( newInfo: consoleInfo, op );
416}
417
418IOReturn
419IOPlatformExpert::registerInterruptController(OSSymbol *name, IOInterruptController *interruptController)
420{
421 IOLockLock(gIOInterruptControllersLock);
422
423 gIOInterruptControllers->setObject(aKey: name, anObject: interruptController);
424
425 IOLockWakeup(lock: gIOInterruptControllersLock,
426 event: gIOInterruptControllers, /* one-thread */ oneThread: false);
427
428 IOLockUnlock(gIOInterruptControllersLock);
429
430 return kIOReturnSuccess;
431}
432
433IOReturn
434IOPlatformExpert::deregisterInterruptController(OSSymbol *name)
435{
436 IOLockLock(gIOInterruptControllersLock);
437
438 gIOInterruptControllers->removeObject(aKey: name);
439
440 IOLockUnlock(gIOInterruptControllersLock);
441
442 return kIOReturnSuccess;
443}
444
445IOInterruptController *
446IOPlatformExpert::lookUpInterruptController(OSSymbol *name)
447{
448 OSObject *object;
449
450 IOLockLock(gIOInterruptControllersLock);
451 while (1) {
452 object = gIOInterruptControllers->getObject(aKey: name);
453
454 if (object != NULL) {
455 break;
456 }
457
458 IOLockSleep(lock: gIOInterruptControllersLock,
459 event: gIOInterruptControllers, THREAD_UNINT);
460 }
461
462 IOLockUnlock(gIOInterruptControllersLock);
463 return OSDynamicCast(IOInterruptController, object);
464}
465
466
467void
468IOPlatformExpert::setCPUInterruptProperties(IOService *service)
469{
470 IOInterruptController *controller;
471
472 OSDictionary *matching = serviceMatching(className: "IOInterruptController");
473 matching = propertyMatching(key: gPlatformInterruptControllerName, value: kOSBooleanTrue, table: matching);
474
475 controller = OSDynamicCast(IOInterruptController, waitForService(matching));
476 if (controller) {
477 controller->setCPUInterruptProperties(service);
478 }
479}
480
481bool
482IOPlatformExpert::atInterruptLevel(void)
483{
484 return ml_at_interrupt_context();
485}
486
487bool
488IOPlatformExpert::platformAdjustService(IOService */*service*/)
489{
490 return true;
491}
492
493void
494IOPlatformExpert::getUTCTimeOfDay(clock_sec_t * secs, clock_nsec_t * nsecs)
495{
496 *secs = getGMTTimeOfDay();
497 *nsecs = 0;
498}
499
500void
501IOPlatformExpert::setUTCTimeOfDay(clock_sec_t secs, __unused clock_nsec_t nsecs)
502{
503 setGMTTimeOfDay(secs);
504}
505
506
507//*********************************************************************************
508// PMLog
509//
510//*********************************************************************************
511
512void
513IOPlatformExpert::
514PMLog(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(secs: &nows, microsecs: &nowus);
520 nowus += (nows % 1000) * 1000000;
521
522 kprintf(fmt: "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
537void
538IOPlatformExpert::PMInstantiatePowerDomains( void )
539{
540 root = new IOPMrootDomain;
541 root->init();
542 root->attach(provider: this);
543 root->start(provider: 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
554void
555IOPlatformExpert::PMRegisterDevice(IOService * theNub, IOService * theDevice)
556{
557 root->addPowerChild( theChild: theDevice );
558}
559
560//*********************************************************************************
561// hasPMFeature
562//
563//*********************************************************************************
564
565bool
566IOPlatformExpert::hasPMFeature(unsigned long featureMask)
567{
568 return (_pePMFeatures & featureMask) != 0;
569}
570
571//*********************************************************************************
572// hasPrivPMFeature
573//
574//*********************************************************************************
575
576bool
577IOPlatformExpert::hasPrivPMFeature(unsigned long privFeatureMask)
578{
579 return (_pePrivPMFeatures & privFeatureMask) != 0;
580}
581
582//*********************************************************************************
583// numBatteriesSupported
584//
585//*********************************************************************************
586
587int
588IOPlatformExpert::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
604bool
605IOPlatformExpert::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(index: i);
631
632 matchingDictionary = (OSDictionary *) entry->getObject(aKey: "device");
633 providerDictionary = (OSDictionary *) entry->getObject(aKey: "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( aDictionary: matchingDictionary, keys: 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( aDictionary: providerDictionary, keys: 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(aKey: "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(theService: theDevice, theTreeNode: entry, theTreeParentNode: theParent, theProvider: theNub)) {
674 if (kIOLogPower & gIOKitDebug) {
675 IOLog(format: "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(aKey: "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(aKey: "children")))) {
690 nodeFound = CheckSubTree( inSubTree: children, theNub, theDevice, theParent: 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
708bool
709IOPlatformExpert::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(aKey: "service")) {
720 if (theTreeNode->setObject(aKey: "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(aKey: "children"))) {
727 numChildren = children->getCount();
728 for (unsigned int i = 0; i < numChildren; i++) {
729 if (NULL != (child = (OSDictionary *) children->getObject(index: i))) {
730 if (NULL != (aService = (IOService *) child->getObject(aKey: "service"))) {
731 theService->addPowerChild(theChild: 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(aKey: "service"))) {
744 if (aService != theProvider) {
745 aService->addPowerChild(theChild: 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//*********************************************************************************
762void
763printDictionaryKeys(OSDictionary * inDictionary, char * inMsg)
764{
765 OSCollectionIterator * mcoll = OSCollectionIterator::withCollection(inColl: 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(cString: "IOClass")) {
780 ioClass = (OSString *) inDictionary->getObject(aKey: "IOClass");
781 if (ioClass) {
782 IOLog(format: "%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(cString: "IOProviderClass")) {
789 ioClass = (OSString *) inDictionary->getObject(aKey: "IOProviderClass");
790 if (ioClass) {
791 IOLog(format: "%s IOProviderClass is %s\n", inMsg, ioClass->getCStringNoCopy());
792 }
793 }
794
795 // also print IONameMatch keys
796 if (mkey->isEqualTo(cString: "IONameMatch")) {
797 ioClass = (OSString *) inDictionary->getObject(aKey: "IONameMatch");
798 if (ioClass) {
799 IOLog(format: "%s IONameMatch is %s\n", inMsg, ioClass->getCStringNoCopy());
800 }
801 }
802
803 // also print IONameMatched keys
804
805 if (mkey->isEqualTo(cString: "IONameMatched")) {
806 ioClass = (OSString *) inDictionary->getObject(aKey: "IONameMatched");
807 if (ioClass) {
808 IOLog(format: "%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(cString: "name")) {
827 char nameStr[64];
828 nameStr[0] = 0;
829 getCStringForObject(inObj: inDictionary->getObject(aKey: "name"), outStr: nameStr,
830 outStrLen: sizeof(nameStr));
831 if (strlen(s: nameStr) > 0) {
832 IOLog(format: "%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
844static void
845getCStringForObject(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(s1: objString, s2: "OSString", n: sizeof("OSString"))) ||
857 (0 == strncmp(s1: objString, s2: "OSSymbol", n: sizeof("OSSymbol")))) {
858 strlcpy(dst: outStr, src: ((OSString *)inObj)->getCStringNoCopy(), n: outStrLen);
859 } else if (0 == strncmp(s1: objString, s2: "OSData", n: 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
877static void
878IOShutdownNotificationsTimedOut(
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
905extern "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 */
915boolean_t
916PEGetMachineName( 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 */
930boolean_t
931PEGetModelName( char * name, int maxLength )
932{
933 if (gIOPlatform) {
934 return gIOPlatform->getModelName( name, maxLength );
935 } else {
936 return false;
937 }
938}
939
940boolean_t
941PEGetTargetName( char * name, int maxLength )
942{
943 if (gIOPlatform) {
944 return gIOPlatform->getTargetName( name, maxLength );
945 } else {
946 return false;
947 }
948}
949
950boolean_t
951PEGetProductName( char * name, int maxLength )
952{
953 if (gIOPlatform) {
954 return gIOPlatform->getProductName( name, maxLength );
955 } else {
956 return false;
957 }
958}
959
960int
961PEGetPlatformEpoch(void)
962{
963 if (gIOPlatform) {
964 return (int) gIOPlatform->getBootROMType();
965 } else {
966 return -1;
967 }
968}
969
970/* Handle necessary platform specific actions prior to panic */
971void
972PEInitiatePanic(void)
973{
974#if defined(__arm64__)
975 /*
976 * Trigger a TLB flush so any hard hangs exercise the SoC diagnostic
977 * collection flow rather than hanging late in panic (see rdar://58062030)
978 */
979 flush_mmu_tlb_entries_async(start: 0, PAGE_SIZE, PAGE_SIZE, last_level_only: true, strong: true);
980 arm64_sync_tlb(strong: true);
981#endif // defined(__arm64__)
982}
983
984int
985PEHaltRestartInternal(unsigned int type, uint32_t details)
986{
987 IOPMrootDomain *pmRootDomain;
988 AbsoluteTime deadline;
989 thread_call_t shutdown_hang;
990 IORegistryEntry *node;
991 OSData *data;
992 uint32_t timeout = kShutdownTimeout;
993 static boolean_t panic_begin_called = FALSE;
994
995 if (type == kPEHaltCPU || type == kPERestartCPU || type == kPEUPSDelayHaltCPU) {
996 /* If we're in the panic path, the locks and memory allocations required below
997 * could fail. So just try to reboot instead of risking a nested panic.
998 */
999 if (panic_begin_called) {
1000 goto skip_to_haltRestart;
1001 }
1002
1003 pmRootDomain = IOService::getPMRootDomain();
1004 /* Notify IOKit PM clients of shutdown/restart
1005 * Clients subscribe to this message with a call to
1006 * IOService::registerInterest()
1007 */
1008
1009 /* Spawn a thread that will panic in 30 seconds.
1010 * If all goes well the machine will be off by the time
1011 * the timer expires. If the device wants a different
1012 * timeout, use that value instead of 30 seconds.
1013 */
1014#if defined(__arm64__)
1015#define RESTART_NODE_PATH "/defaults"
1016#else
1017#define RESTART_NODE_PATH "/chosen"
1018#endif
1019 node = IORegistryEntry::fromPath( RESTART_NODE_PATH, plane: gIODTPlane );
1020 if (node) {
1021 data = OSDynamicCast( OSData, node->getProperty( "halt-restart-timeout" ));
1022 if (data && data->getLength() == 4) {
1023 timeout = *((uint32_t *) data->getBytesNoCopy());
1024 }
1025 OSSafeReleaseNULL(node);
1026 }
1027
1028#if (DEVELOPMENT || DEBUG)
1029 /* Override the default timeout via a boot-arg */
1030 uint32_t boot_arg_val;
1031 if (PE_parse_boot_argn("halt_restart_timeout", &boot_arg_val, sizeof(boot_arg_val))) {
1032 timeout = boot_arg_val;
1033 }
1034#endif
1035
1036 if (timeout) {
1037 shutdown_hang = thread_call_allocate( func: &IOShutdownNotificationsTimedOut,
1038 param0: (thread_call_param_t)(uintptr_t) type);
1039 clock_interval_to_deadline( interval: timeout, scale_factor: kSecondScale, result: &deadline );
1040 thread_call_enter1_delayed( call: shutdown_hang, param1: (thread_call_param_t)(uintptr_t)timeout, deadline );
1041 }
1042
1043 pmRootDomain->handlePlatformHaltRestart(pe_type: type);
1044 /* This notification should have few clients who all do
1045 * their work synchronously.
1046 *
1047 * In this "shutdown notification" context we don't give
1048 * drivers the option of working asynchronously and responding
1049 * later. PM internals make it very hard to wait for asynchronous
1050 * replies.
1051 */
1052 } else if (type == kPEPanicRestartCPU || type == kPEPanicSync || type == kPEPanicRestartCPUNoCallouts) {
1053 if (type == kPEPanicRestartCPU) {
1054 // Notify any listeners that we're done collecting
1055 // panic data before we call through to do the restart
1056#if defined(__x86_64__)
1057 if (coprocessor_cross_panic_enabled)
1058#endif
1059 IOCPURunPlatformPanicActions(message: kPEPanicEnd, details);
1060 } else if (type == kPEPanicRestartCPUNoCallouts) {
1061 // We skipped the callouts so now set the type to
1062 // the variant that the platform uses for panic restarts.
1063 type = kPEPanicRestartCPU;
1064 }
1065
1066
1067 // Do an initial sync to flush as much panic data as possible,
1068 // in case we have a problem in one of the platorm panic handlers.
1069 // After running the platform handlers, do a final sync w/
1070 // platform hardware quiesced for the panic.
1071 PE_sync_panic_buffers();
1072 IOCPURunPlatformPanicActions(message: type, details);
1073 PE_sync_panic_buffers();
1074 } else if (type == kPEPanicEnd) {
1075#if defined(__x86_64__)
1076 if (coprocessor_cross_panic_enabled)
1077#endif
1078 IOCPURunPlatformPanicActions(message: type, details);
1079 } else if (type == kPEPanicBegin) {
1080#if defined(__x86_64__)
1081 if (coprocessor_cross_panic_enabled)
1082#endif
1083 {
1084 // Only call the kPEPanicBegin callout once
1085 if (!panic_begin_called) {
1086 panic_begin_called = TRUE;
1087 IOCPURunPlatformPanicActions(message: type, details);
1088 }
1089 }
1090 } else if (type == kPEPanicDiagnosticsDone || type == kPEPanicDiagnosticsInProgress) {
1091 IOCPURunPlatformPanicActions(message: type, details);
1092 }
1093
1094skip_to_haltRestart:
1095 if (gIOPlatform) {
1096 // note that this will not necessarily halt or restart the system...
1097 // Implementors of this function will check the type and take action accordingly
1098 return gIOPlatform->haltRestart(type);
1099 } else {
1100 return -1;
1101 }
1102}
1103
1104int
1105PEHaltRestart(unsigned int type)
1106{
1107 return PEHaltRestartInternal(type, details: 0);
1108}
1109
1110UInt32
1111PESavePanicInfo(UInt8 *buffer, UInt32 length)
1112{
1113 if (gIOPlatform != NULL) {
1114 return (UInt32) gIOPlatform->savePanicInfo(buffer, length);
1115 } else {
1116 return 0;
1117 }
1118}
1119
1120void
1121PESavePanicInfoAction(void *buffer, UInt32 offset, UInt32 length)
1122{
1123 IOCPURunPlatformPanicSyncAction(addr: buffer, offset, len: length);
1124 return;
1125}
1126
1127
1128/*
1129 * Depending on the platform, the /options node may not be created
1130 * until after IOKit matching has started, by an externally-supplied
1131 * platform expert subclass. Therefore, we must check for its presence
1132 * here and update gIOOptionsEntry for the platform code as necessary.
1133 */
1134inline static int
1135init_gIOOptionsEntry(void)
1136{
1137 IORegistryEntry *entry;
1138 void *nvram_entry;
1139 volatile void **options;
1140 int ret = -1;
1141
1142 if (gIOOptionsEntry) {
1143 return 0;
1144 }
1145
1146 entry = IORegistryEntry::fromPath( path: "/options", plane: gIODTPlane );
1147 if (!entry) {
1148 return -1;
1149 }
1150
1151 nvram_entry = (void *) OSDynamicCast(IODTNVRAM, entry);
1152 if (!nvram_entry) {
1153 goto release;
1154 }
1155
1156 options = (volatile void **) &gIOOptionsEntry;
1157 if (!OSCompareAndSwapPtr(NULL, nvram_entry, options)) {
1158 ret = 0;
1159 goto release;
1160 }
1161
1162 return 0;
1163
1164release:
1165 entry->release();
1166 return ret;
1167}
1168
1169/* pass in a NULL value if you just want to figure out the len */
1170boolean_t
1171PEReadNVRAMProperty(const char *symbol, void *value,
1172 unsigned int *len)
1173{
1174 OSObject *obj;
1175 OSData *data;
1176 unsigned int vlen;
1177
1178 if (!symbol || !len) {
1179 goto err;
1180 }
1181
1182 if (init_gIOOptionsEntry() < 0) {
1183 goto err;
1184 }
1185
1186 vlen = *len;
1187 *len = 0;
1188
1189 obj = gIOOptionsEntry->getProperty(aKey: symbol);
1190 if (!obj) {
1191 goto err;
1192 }
1193
1194 /* convert to data */
1195 data = OSDynamicCast(OSData, obj);
1196 if (!data) {
1197 goto err;
1198 }
1199
1200 *len = data->getLength();
1201 vlen = min(vlen, *len);
1202 if (value && vlen) {
1203 memcpy(dst: (void *) value, src: data->getBytesNoCopy(), n: vlen);
1204 }
1205
1206 return TRUE;
1207
1208err:
1209 return FALSE;
1210}
1211
1212boolean_t
1213PEReadNVRAMBooleanProperty(const char *symbol, boolean_t *value)
1214{
1215 OSObject *obj;
1216 OSBoolean *data;
1217
1218 if (!symbol || !value) {
1219 goto err;
1220 }
1221
1222 if (init_gIOOptionsEntry() < 0) {
1223 goto err;
1224 }
1225
1226 obj = gIOOptionsEntry->getProperty(aKey: symbol);
1227 if (!obj) {
1228 return TRUE;
1229 }
1230
1231 /* convert to bool */
1232 data = OSDynamicCast(OSBoolean, obj);
1233 if (!data) {
1234 goto err;
1235 }
1236
1237 *value = data->isTrue() ? TRUE : FALSE;
1238
1239 return TRUE;
1240
1241err:
1242 return FALSE;
1243}
1244
1245boolean_t
1246PEWriteNVRAMBooleanProperty(const char *symbol, boolean_t value)
1247{
1248 const OSSymbol *sym = NULL;
1249 OSBoolean *data = NULL;
1250 bool ret = false;
1251
1252 if (symbol == NULL) {
1253 goto exit;
1254 }
1255
1256 if (init_gIOOptionsEntry() < 0) {
1257 goto exit;
1258 }
1259
1260 if ((sym = OSSymbol::withCStringNoCopy(cString: symbol)) == NULL) {
1261 goto exit;
1262 }
1263
1264 data = value ? kOSBooleanTrue : kOSBooleanFalse;
1265 ret = gIOOptionsEntry->setProperty(aKey: sym, anObject: data);
1266
1267 sym->release();
1268
1269 /* success, force the NVRAM to flush writes */
1270 if (ret == true) {
1271 gIOOptionsEntry->sync();
1272 }
1273
1274exit:
1275 return ret;
1276}
1277
1278static boolean_t
1279PEWriteNVRAMPropertyInternal(const char *symbol, boolean_t copySymbol, const void *value,
1280 const unsigned int len)
1281{
1282 const OSSymbol *sym;
1283 OSData *data;
1284 bool ret = false;
1285
1286 if (!symbol || !value || !len) {
1287 goto err;
1288 }
1289
1290 if (init_gIOOptionsEntry() < 0) {
1291 goto err;
1292 }
1293
1294 if (copySymbol == TRUE) {
1295 sym = OSSymbol::withCString(cString: symbol);
1296 } else {
1297 sym = OSSymbol::withCStringNoCopy(cString: symbol);
1298 }
1299
1300 if (!sym) {
1301 goto err;
1302 }
1303
1304 data = OSData::withBytes(bytes: (void *) value, numBytes: len);
1305 if (!data) {
1306 goto sym_done;
1307 }
1308
1309 ret = gIOOptionsEntry->setProperty(aKey: sym, anObject: data);
1310 data->release();
1311
1312sym_done:
1313 sym->release();
1314
1315 if (ret == true) {
1316 gIOOptionsEntry->sync();
1317 return TRUE;
1318 }
1319
1320err:
1321 return FALSE;
1322}
1323
1324boolean_t
1325PEWriteNVRAMProperty(const char *symbol, const void *value,
1326 const unsigned int len)
1327{
1328 return PEWriteNVRAMPropertyInternal(symbol, FALSE, value, len);
1329}
1330
1331boolean_t
1332PEWriteNVRAMPropertyWithCopy(const char *symbol, const void *value,
1333 const unsigned int len)
1334{
1335 return PEWriteNVRAMPropertyInternal(symbol, TRUE, value, len);
1336}
1337
1338boolean_t
1339PERemoveNVRAMProperty(const char *symbol)
1340{
1341 const OSSymbol *sym;
1342
1343 if (!symbol) {
1344 goto err;
1345 }
1346
1347 if (init_gIOOptionsEntry() < 0) {
1348 goto err;
1349 }
1350
1351 sym = OSSymbol::withCStringNoCopy(cString: symbol);
1352 if (!sym) {
1353 goto err;
1354 }
1355
1356 gIOOptionsEntry->removeProperty(aKey: sym);
1357
1358 sym->release();
1359
1360 gIOOptionsEntry->sync();
1361 return TRUE;
1362
1363err:
1364 return FALSE;
1365}
1366
1367boolean_t
1368PESyncNVRAM(void)
1369{
1370 if (gIOOptionsEntry != nullptr) {
1371 gIOOptionsEntry->sync();
1372 }
1373
1374 return TRUE;
1375}
1376
1377long
1378PEGetGMTTimeOfDay(void)
1379{
1380 clock_sec_t secs;
1381 clock_usec_t usecs;
1382
1383 PEGetUTCTimeOfDay(secs: &secs, usecs: &usecs);
1384 return secs;
1385}
1386
1387void
1388PESetGMTTimeOfDay(long secs)
1389{
1390 PESetUTCTimeOfDay(secs, usecs: 0);
1391}
1392
1393void
1394PEGetUTCTimeOfDay(clock_sec_t * secs, clock_usec_t * usecs)
1395{
1396 clock_nsec_t nsecs = 0;
1397
1398 *secs = 0;
1399 if (gIOPlatform) {
1400 gIOPlatform->getUTCTimeOfDay(secs, nsecs: &nsecs);
1401 }
1402
1403 assert(nsecs < NSEC_PER_SEC);
1404 *usecs = nsecs / NSEC_PER_USEC;
1405}
1406
1407void
1408PESetUTCTimeOfDay(clock_sec_t secs, clock_usec_t usecs)
1409{
1410 assert(usecs < USEC_PER_SEC);
1411 if (gIOPlatform) {
1412 gIOPlatform->setUTCTimeOfDay(secs, nsecs: usecs * NSEC_PER_USEC);
1413 }
1414}
1415
1416coprocessor_type_t
1417PEGetCoprocessorVersion( void )
1418{
1419 coprocessor_type_t coprocessor_version = kCoprocessorVersionNone;
1420#if defined(__x86_64__)
1421 IORegistryEntry *platform_entry = NULL;
1422 OSData *coprocessor_version_obj = NULL;
1423
1424 platform_entry = IORegistryEntry::fromPath(kIODeviceTreePlane ":/efi/platform");
1425 if (platform_entry != NULL) {
1426 coprocessor_version_obj = OSDynamicCast(OSData, platform_entry->getProperty("apple-coprocessor-version"));
1427 if ((coprocessor_version_obj != NULL) && (coprocessor_version_obj->getLength() <= sizeof(uint64_t))) {
1428 memcpy(&coprocessor_version, coprocessor_version_obj->getBytesNoCopy(), coprocessor_version_obj->getLength());
1429 }
1430 platform_entry->release();
1431 }
1432#endif
1433 return coprocessor_version;
1434}
1435} /* extern "C" */
1436
1437bool gIOPlatformUUIDAndSerialDone = false;
1438
1439void
1440IOPlatformExpert::publishPlatformUUIDAndSerial( void )
1441{
1442 if (!gIOPlatformUUIDAndSerialDone) {
1443 // Parse the serial-number data and publish a user-readable string
1444 if (NULL == getProvider()->getProperty(kIOPlatformSerialNumberKey)) {
1445 OSData* mydata = (OSData*) (getProvider()->getProperty(aKey: "serial-number"));
1446 if (mydata != NULL) {
1447 OSString *serNoString = createSystemSerialNumberString(myProperty: mydata);
1448 if (serNoString != NULL) {
1449 getProvider()->setProperty(kIOPlatformSerialNumberKey, anObject: serNoString);
1450 serNoString->release();
1451 }
1452 }
1453 }
1454 IOPlatformExpertDevice *provider = OSDynamicCast(IOPlatformExpertDevice, getProvider());
1455 assert(provider != NULL);
1456 provider->generatePlatformUUID();
1457 }
1458
1459 if (gIOPlatformUUIDAndSerialDone) {
1460 publishResource(kIOPlatformUUIDKey, value: getProvider()->getProperty(kIOPlatformUUIDKey));
1461 }
1462}
1463
1464void
1465IOPlatformExpert::publishNVRAM( void )
1466{
1467 if (init_gIOOptionsEntry() < 0) {
1468 IOPlatformExpertDevice *provider = OSDynamicCast(IOPlatformExpertDevice, getProvider());
1469 assert(provider != NULL);
1470 provider->createNVRAM();
1471 }
1472 if (gIOOptionsEntry != NULL) {
1473 gIOOptionsEntry->registerService();
1474 }
1475}
1476
1477void
1478IOPlatformExpert::registerNVRAMController(IONVRAMController * caller)
1479{
1480#if defined(__x86_64__)
1481 OSData * data;
1482 IORegistryEntry * entry;
1483
1484 /*
1485 * If we have panic debugging enabled WITHOUT behavior to reboot after any crash (DB_REBOOT_ALWAYS)
1486 * and we are on a co-processor system that has the panic SoC watchdog enabled, disable
1487 * cross panics so that the co-processor doesn't cause the system
1488 * to reset when we enter the debugger or hit a panic on the x86 side.
1489 */
1490 if (panicDebugging && !(debug_boot_arg & DB_REBOOT_ALWAYS)) {
1491 entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
1492 if (entry) {
1493 data = OSDynamicCast( OSData, entry->getProperty( APPLE_VENDOR_VARIABLE_GUID":BridgeOSPanicWatchdogEnabled" ));
1494 if (data && (data->getLength() == sizeof(UInt8))) {
1495 UInt8 *panicWatchdogEnabled = (UInt8 *) data->getBytesNoCopy();
1496 UInt32 debug_flags = 0;
1497 if (*panicWatchdogEnabled || (PE_i_can_has_debugger(&debug_flags) &&
1498 (debug_flags & DB_DISABLE_CROSS_PANIC))) {
1499 coprocessor_cross_panic_enabled = FALSE;
1500 }
1501 }
1502 entry->release();
1503 }
1504 }
1505
1506#if (DEVELOPMENT || DEBUG)
1507 entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
1508 if (entry) {
1509 data = OSDynamicCast( OSData, entry->getProperty(nvram_osenvironment));
1510 if (data) {
1511 sysctl_set_osenvironment(data->getLength(), data->getBytesNoCopy());
1512 entry->removeProperty(nvram_osenvironment);
1513 IODTNVRAM * nvramOptionsEntry = OSDynamicCast(IODTNVRAM, entry);
1514 if (nvramOptionsEntry) {
1515 nvramOptionsEntry->sync();
1516 }
1517 }
1518 entry->release();
1519 }
1520 sysctl_unblock_osenvironment();
1521#endif
1522 /* on intel the UUID must be published after nvram is available */
1523 publishPlatformUUIDAndSerial();
1524
1525#endif /* defined(__x86_64__) */
1526
1527 publishResource(key: "IONVRAM");
1528}
1529
1530IOReturn
1531IOPlatformExpert::callPlatformFunction(const OSSymbol *functionName,
1532 bool waitForFunction,
1533 void *param1, void *param2,
1534 void *param3, void *param4)
1535{
1536 IOService *service, *_resources;
1537 OSObject *prop = NULL;
1538 IOReturn ret;
1539
1540 if (functionName == gIOPlatformQuiesceActionKey ||
1541 functionName == gIOPlatformActiveActionKey ||
1542 functionName == gIOPlatformPanicActionKey) {
1543 /*
1544 * Services which register for IOPlatformQuiesceAction / IOPlatformActiveAction / IOPlatformPanicAction
1545 * must consume that event themselves, without passing it up to super/IOPlatformExpert.
1546 */
1547 if (gEnforcePlatformActionSafety) {
1548 panic("Class %s passed the %s action to IOPlatformExpert",
1549 getMetaClass()->getClassName(), functionName->getCStringNoCopy());
1550 }
1551 }
1552
1553 if (waitForFunction) {
1554 _resources = waitForService(matching: resourceMatching(name: functionName));
1555 } else {
1556 _resources = getResourceService();
1557 }
1558 if (_resources == NULL) {
1559 return kIOReturnUnsupported;
1560 }
1561
1562 prop = _resources->copyProperty(aKey: functionName);
1563 service = OSDynamicCast(IOService, prop);
1564 if (service == NULL) {
1565 ret = kIOReturnUnsupported;
1566 goto finish;
1567 }
1568
1569 ret = service->callPlatformFunction(functionName, waitForFunction,
1570 param1, param2, param3, param4);
1571
1572finish:
1573 OSSafeReleaseNULL(prop);
1574 return ret;
1575}
1576
1577IOByteCount
1578IOPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length)
1579{
1580 return 0;
1581}
1582
1583/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1584
1585#undef super
1586#define super IOPlatformExpert
1587
1588OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert, IOPlatformExpert )
1589
1590OSMetaClassDefineReservedUnused(IODTPlatformExpert, 0);
1591OSMetaClassDefineReservedUnused(IODTPlatformExpert, 1);
1592OSMetaClassDefineReservedUnused(IODTPlatformExpert, 2);
1593OSMetaClassDefineReservedUnused(IODTPlatformExpert, 3);
1594OSMetaClassDefineReservedUnused(IODTPlatformExpert, 4);
1595OSMetaClassDefineReservedUnused(IODTPlatformExpert, 5);
1596OSMetaClassDefineReservedUnused(IODTPlatformExpert, 6);
1597OSMetaClassDefineReservedUnused(IODTPlatformExpert, 7);
1598
1599/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1600
1601IOService *
1602IODTPlatformExpert::probe( IOService * provider,
1603 SInt32 * score )
1604{
1605 if (!super::probe( provider, score)) {
1606 return NULL;
1607 }
1608
1609 // check machine types
1610 if (!provider->compareNames( name: getProperty( aKey: gIONameMatchKey ))) {
1611 return NULL;
1612 }
1613
1614 return this;
1615}
1616
1617bool
1618IODTPlatformExpert::configure( IOService * provider )
1619{
1620 if (!super::configure( provider)) {
1621 return false;
1622 }
1623
1624 processTopLevel( root: provider );
1625
1626 return true;
1627}
1628
1629IOService *
1630IODTPlatformExpert::createNub( IORegistryEntry * from )
1631{
1632 IOService * nub;
1633
1634 nub = new IOPlatformDevice;
1635 if (nub) {
1636 if (!nub->init( from, inPlane: gIODTPlane )) {
1637 nub->free();
1638 nub = NULL;
1639 }
1640 }
1641 return nub;
1642}
1643
1644bool
1645IODTPlatformExpert::createNubs( IOService * parent, OSIterator * iter )
1646{
1647 IORegistryEntry * next;
1648 IOService * nub = NULL;
1649 bool ok = true;
1650
1651 if (iter) {
1652 while ((next = (IORegistryEntry *) iter->getNextObject())) {
1653 OSSafeReleaseNULL(nub);
1654
1655 if (NULL == (nub = createNub( from: next ))) {
1656 continue;
1657 }
1658
1659 nub->attach( provider: parent );
1660#if !defined(__x86_64__)
1661 OSData *tmpData = (OSData *)next->getProperty(aKey: "device_type");
1662 if (tmpData == NULL) {
1663 nub->registerService();
1664 continue;
1665 }
1666
1667 char *device_type = (char *)tmpData->getBytesNoCopy();
1668 if (strcmp(s1: device_type, s2: "cpu") != 0) {
1669 nub->registerService();
1670 continue;
1671 }
1672
1673 tmpData = (OSData *)next->getProperty(aKey: "reg");
1674 assert(tmpData != NULL);
1675 assert(tmpData->getLength() >= sizeof(UInt32));
1676
1677 uint32_t phys_id = *(UInt32 *)tmpData->getBytesNoCopy();
1678 int logical_cpu_id = ml_get_cpu_number(phys_id);
1679 int logical_cluster_id = ml_get_cluster_number(phys_id);
1680
1681 /*
1682 * If the following condition triggers, it means that a CPU that was present in the DT
1683 * was ignored by XNU at topology parsing time. This can happen currently when using the
1684 * cpus=N boot-arg; for example, cpus=1 will cause XNU to parse and enable a single CPU.
1685 *
1686 * Note that this condition will not trigger for harvested cores because these do not show up
1687 * in the DT/IORegistry in the first place.
1688 */
1689 if (logical_cpu_id < 0) {
1690 nub->registerService();
1691 continue;
1692 }
1693
1694 __assert_only bool logical_id_added_to_ioreg = nub->setProperty(aKey: "logical-cpu-id", aValue: logical_cpu_id, aNumberOfBits: 32U);
1695 assert(logical_id_added_to_ioreg == true);
1696 logical_id_added_to_ioreg = nub->setProperty(aKey: "logical-cluster-id", aValue: logical_cluster_id, aNumberOfBits: 32U);
1697 assert(logical_id_added_to_ioreg == true);
1698#endif
1699 nub->registerService();
1700 }
1701 OSSafeReleaseNULL(nub);
1702 iter->release();
1703 }
1704
1705 return ok;
1706}
1707
1708void
1709IODTPlatformExpert::processTopLevel( IORegistryEntry * rootEntry )
1710{
1711 OSIterator * kids;
1712 IORegistryEntry * next;
1713 IORegistryEntry * cpus;
1714
1715 // infanticide
1716 kids = IODTFindMatchingEntries( from: rootEntry, options: 0, keys: deleteList());
1717 if (kids) {
1718 while ((next = (IORegistryEntry *)kids->getNextObject())) {
1719 next->detachAll( plane: gIODTPlane);
1720 }
1721 kids->release();
1722 }
1723
1724 publishNVRAM();
1725 assert(gIOOptionsEntry != NULL); // subclasses that do their own NVRAM initialization shouldn't be calling this
1726 dtNVRAM = gIOOptionsEntry;
1727
1728 // Publish the cpus.
1729 cpus = rootEntry->childFromPath( path: "cpus", plane: gIODTPlane);
1730 if (cpus) {
1731 createNubs( parent: this, iter: IODTFindMatchingEntries( from: cpus, options: kIODTExclusive, NULL));
1732 cpus->release();
1733 }
1734
1735 // publish top level, minus excludeList
1736 createNubs( parent: this, iter: IODTFindMatchingEntries( from: rootEntry, options: kIODTExclusive, keys: excludeList()));
1737}
1738
1739IOReturn
1740IODTPlatformExpert::getNubResources( IOService * nub )
1741{
1742 if (nub->getDeviceMemory()) {
1743 return kIOReturnSuccess;
1744 }
1745
1746 IODTResolveAddressing( regEntry: nub, addressPropertyName: "reg", NULL);
1747
1748 return kIOReturnSuccess;
1749}
1750
1751bool
1752IODTPlatformExpert::compareNubName( const IOService * nub,
1753 OSString * name, OSString ** matched ) const
1754{
1755 return IODTCompareNubName( regEntry: nub, name, matchingName: matched )
1756 || super::compareNubName( nub, name, matched);
1757}
1758
1759
1760/*
1761 * Do not use this method directly, it returns inconsistent results
1762 * across architectures and is considered deprecated.
1763 *
1764 * Use getTargetName and getProductName respectively. For example:
1765 *
1766 * targetName: J137AP
1767 * productName: iMacPro1,1
1768 *
1769 * targetName: D331pAP
1770 * productName: iPhone11,6
1771 */
1772
1773bool
1774IODTPlatformExpert::getModelName( char * name, int maxLength )
1775{
1776 OSData * prop;
1777 const char * str;
1778 int len;
1779 char c;
1780 bool ok = false;
1781
1782 maxLength--;
1783
1784 prop = (OSData *) getProvider()->getProperty( aKey: gIODTCompatibleKey );
1785 if (prop) {
1786 str = (const char *) prop->getBytesNoCopy();
1787
1788 if (0 == strncmp( s1: str, s2: "AAPL,", n: strlen( s: "AAPL," ))) {
1789 str += strlen( s: "AAPL," );
1790 }
1791
1792 len = 0;
1793 while ((c = *str++)) {
1794 if ((c == '/') || (c == ' ')) {
1795 c = '-';
1796 }
1797
1798 name[len++] = c;
1799 if (len >= maxLength) {
1800 break;
1801 }
1802 }
1803
1804 name[len] = 0;
1805 ok = true;
1806 }
1807 return ok;
1808}
1809
1810/*
1811 * Do not use this method directly, it returns inconsistent results
1812 * across architectures and is considered deprecated.
1813 *
1814 * Use getTargetName and getProductName respectively. For example:
1815 *
1816 * targetName: J137AP
1817 * productName: iMacPro1,1
1818 *
1819 * targetName: D331pAP
1820 * productName: iPhone11,6
1821 */
1822
1823bool
1824IODTPlatformExpert::getMachineName( char * name, int maxLength )
1825{
1826 OSData * prop;
1827 bool ok = false;
1828
1829 maxLength--;
1830 prop = (OSData *) getProvider()->getProperty( aKey: gIODTModelKey );
1831 ok = (NULL != prop);
1832
1833 if (ok) {
1834 strlcpy( dst: name, src: (const char *) prop->getBytesNoCopy(), n: maxLength );
1835 }
1836
1837 return ok;
1838}
1839
1840/* Examples: J137AP, D331pAP... */
1841
1842bool
1843IODTPlatformExpert::getTargetName( char * name, int maxLength )
1844{
1845#if __x86_64__
1846 OSData * prop;
1847
1848 const OSSymbol * key = gIODTBridgeModelKey;
1849
1850 maxLength--;
1851 prop = (OSData *) getProvider()->getProperty( key );
1852
1853 if (prop == NULL) {
1854 // This happens if there is no bridge.
1855 char const * const unknown = "";
1856
1857 strlcpy( name, unknown, maxLength );
1858 } else {
1859 strlcpy( name, (const char *)prop->getBytesNoCopy(), maxLength );
1860 }
1861
1862 return true;
1863#else
1864 return getModelName( name, maxLength );
1865#endif
1866}
1867
1868/* Examples: iMacPro1,1, iPhone11,6... */
1869
1870bool
1871IODTPlatformExpert::getProductName( char * name, int maxLength )
1872{
1873#if __x86_64__
1874 return getModelName( name, maxLength );
1875#else
1876 return getMachineName( name, maxLength );
1877#endif
1878}
1879
1880/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1881
1882void
1883IODTPlatformExpert::registerNVRAMController( IONVRAMController * nvram )
1884{
1885 if (dtNVRAM) {
1886 dtNVRAM->registerNVRAMController(controller: nvram);
1887 }
1888
1889 super::registerNVRAMController(caller: nvram);
1890}
1891
1892int
1893IODTPlatformExpert::haltRestart(unsigned int type)
1894{
1895 return super::haltRestart(type);
1896}
1897
1898IOReturn
1899IODTPlatformExpert::readXPRAM(IOByteCount offset, UInt8 * buffer,
1900 IOByteCount length)
1901{
1902 if (dtNVRAM) {
1903 return dtNVRAM->readXPRAM(offset, buffer, length);
1904 } else {
1905 return kIOReturnNotReady;
1906 }
1907}
1908
1909IOReturn
1910IODTPlatformExpert::writeXPRAM(IOByteCount offset, UInt8 * buffer,
1911 IOByteCount length)
1912{
1913 if (dtNVRAM) {
1914 return dtNVRAM->writeXPRAM(offset, buffer, length);
1915 } else {
1916 return kIOReturnNotReady;
1917 }
1918}
1919
1920IOReturn
1921IODTPlatformExpert::readNVRAMProperty(
1922 IORegistryEntry * entry,
1923 const OSSymbol ** name, OSData ** value )
1924{
1925 if (dtNVRAM) {
1926 return dtNVRAM->readNVRAMProperty(entry, name, value);
1927 } else {
1928 return kIOReturnNotReady;
1929 }
1930}
1931
1932IOReturn
1933IODTPlatformExpert::readNVRAMProperty(
1934 IORegistryEntry * entry,
1935 OSSharedPtr<const OSSymbol>& name, OSSharedPtr<OSData>& value )
1936{
1937 const OSSymbol* nameRaw = NULL;
1938 OSData* valueRaw = NULL;
1939
1940 IOReturn result = readNVRAMProperty(entry, name: &nameRaw, value: &valueRaw);
1941
1942 name.reset(p: nameRaw, OSNoRetain);
1943 value.reset(p: valueRaw, OSNoRetain);
1944
1945 return result;
1946}
1947
1948IOReturn
1949IODTPlatformExpert::writeNVRAMProperty(
1950 IORegistryEntry * entry,
1951 const OSSymbol * name, OSData * value )
1952{
1953 if (dtNVRAM) {
1954 return dtNVRAM->writeNVRAMProperty(entry, name, value);
1955 } else {
1956 return kIOReturnNotReady;
1957 }
1958}
1959
1960OSDictionary *
1961IODTPlatformExpert::getNVRAMPartitions(void)
1962{
1963 if (dtNVRAM) {
1964 return dtNVRAM->getNVRAMPartitions();
1965 } else {
1966 return NULL;
1967 }
1968}
1969
1970IOReturn
1971IODTPlatformExpert::readNVRAMPartition(const OSSymbol * partitionID,
1972 IOByteCount offset, UInt8 * buffer,
1973 IOByteCount length)
1974{
1975 if (dtNVRAM) {
1976 return dtNVRAM->readNVRAMPartition(partitionID, offset,
1977 buffer, length);
1978 } else {
1979 return kIOReturnNotReady;
1980 }
1981}
1982
1983IOReturn
1984IODTPlatformExpert::writeNVRAMPartition(const OSSymbol * partitionID,
1985 IOByteCount offset, UInt8 * buffer,
1986 IOByteCount length)
1987{
1988 if (dtNVRAM) {
1989 return dtNVRAM->writeNVRAMPartition(partitionID, offset,
1990 buffer, length);
1991 } else {
1992 return kIOReturnNotReady;
1993 }
1994}
1995
1996IOByteCount
1997IODTPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length)
1998{
1999 IOByteCount lengthSaved = 0;
2000
2001 if (dtNVRAM) {
2002 lengthSaved = dtNVRAM->savePanicInfo(buffer, length);
2003 }
2004
2005 if (lengthSaved == 0) {
2006 lengthSaved = super::savePanicInfo(buffer, length);
2007 }
2008
2009 return lengthSaved;
2010}
2011
2012OSString*
2013IODTPlatformExpert::createSystemSerialNumberString(OSData* myProperty)
2014{
2015 UInt8* serialNumber;
2016 unsigned int serialNumberSize;
2017 unsigned short pos = 0;
2018 char* temp;
2019 char SerialNo[30];
2020
2021 if (myProperty != NULL) {
2022 serialNumberSize = myProperty->getLength();
2023 serialNumber = (UInt8*)(myProperty->getBytesNoCopy());
2024 temp = (char*)serialNumber;
2025 if (serialNumberSize > 0) {
2026 // check to see if this is a CTO serial number...
2027 while (pos < serialNumberSize && temp[pos] != '-') {
2028 pos++;
2029 }
2030
2031 if (pos < serialNumberSize) { // there was a hyphen, so it's a CTO serial number
2032 memcpy(dst: SerialNo, src: serialNumber + 12, n: 8);
2033 memcpy(dst: &SerialNo[8], src: serialNumber, n: 3);
2034 SerialNo[11] = '-';
2035 memcpy(dst: &SerialNo[12], src: serialNumber + 3, n: 8);
2036 SerialNo[20] = 0;
2037 } else { // just a normal serial number
2038 memcpy(dst: SerialNo, src: serialNumber + 13, n: 8);
2039 memcpy(dst: &SerialNo[8], src: serialNumber, n: 3);
2040 SerialNo[11] = 0;
2041 }
2042 return OSString::withCString(cString: SerialNo);
2043 }
2044 }
2045 return NULL;
2046}
2047
2048
2049/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2050
2051#undef super
2052#define super IOService
2053
2054OSDefineMetaClassAndStructors(IOPlatformExpertDevice, IOService)
2055
2056OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 0);
2057OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 1);
2058OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 2);
2059OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 3);
2060
2061/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2062
2063bool
2064IOPlatformExpertDevice::compareName( OSString * name,
2065 OSString ** matched ) const
2066{
2067 return IODTCompareNubName( regEntry: this, name, matchingName: matched );
2068}
2069
2070bool
2071IOPlatformExpertDevice::init(void *dtRoot)
2072{
2073 IORegistryEntry * dt = NULL;
2074 bool ok;
2075
2076 if ((dtRoot != NULL) && (dt = IODeviceTreeAlloc(dtTop: dtRoot))) {
2077 ok = super::init( from: dt, inPlane: gIODTPlane );
2078 } else {
2079 ok = super::init();
2080 }
2081
2082 if (!ok) {
2083 return false;
2084 }
2085
2086 return true;
2087}
2088
2089bool
2090IOPlatformExpertDevice::startIOServiceMatching(void)
2091{
2092 workLoop = IOWorkLoop::workLoop();
2093 if (!workLoop) {
2094 return false;
2095 }
2096
2097 registerService();
2098
2099 return true;
2100}
2101
2102IOWorkLoop *
2103IOPlatformExpertDevice::getWorkLoop() const
2104{
2105 return workLoop;
2106}
2107
2108IOReturn
2109IOPlatformExpertDevice::setProperties( OSObject * properties )
2110{
2111 return kIOReturnUnsupported;
2112}
2113
2114IOReturn
2115IOPlatformExpertDevice::newUserClient( task_t owningTask, void * securityID,
2116 UInt32 type, OSDictionary * properties,
2117 IOUserClient ** handler )
2118{
2119 IOReturn err = kIOReturnSuccess;
2120 IOUserClient * newConnect = NULL;
2121 IOUserClient * theConnect = NULL;
2122
2123 switch (type) {
2124 case kIOKitDiagnosticsClientType:
2125 newConnect = IOKitDiagnosticsClient::withTask(owningTask);
2126 if (!newConnect) {
2127 err = kIOReturnNotPermitted;
2128 }
2129 break;
2130 case kIOKitUserServerClientType:
2131 newConnect = IOUserServer::withTask(owningTask);
2132 if (!newConnect) {
2133 err = kIOReturnNotPermitted;
2134 }
2135 break;
2136 default:
2137 err = kIOReturnBadArgument;
2138 }
2139
2140 if (newConnect) {
2141 if ((false == newConnect->attach(provider: this))
2142 || (false == newConnect->start(provider: this))) {
2143 newConnect->detach( provider: this );
2144 newConnect->release();
2145 err = kIOReturnNotPermitted;
2146 } else {
2147 theConnect = newConnect;
2148 }
2149 }
2150
2151 *handler = theConnect;
2152 return err;
2153}
2154
2155void
2156IOPlatformExpertDevice::free()
2157{
2158 if (workLoop) {
2159 workLoop->release();
2160 }
2161}
2162
2163void
2164IOPlatformExpertDevice::configureDefaults( void )
2165{
2166 createNVRAM();
2167 // Parse the serial-number data and publish a user-readable string
2168 OSData* mydata = (OSData*) (getProperty(aKey: "serial-number"));
2169 if (mydata != NULL) {
2170 OSString *serNoString = OSString::withCString(cString: (const char *)mydata->getBytesNoCopy());
2171 if (serNoString != NULL) {
2172 setProperty(kIOPlatformSerialNumberKey, anObject: serNoString);
2173 serNoString->release();
2174 }
2175 }
2176 generatePlatformUUID();
2177}
2178
2179void
2180IOPlatformExpertDevice::createNVRAM( void )
2181{
2182 /*
2183 * Publish an IODTNVRAM class on /options, if present.
2184 * DT-based platforms may need NVRAM access prior to the start
2185 * of IOKit matching, to support security-related operations
2186 * that must happen before machine_lockdown().
2187 */
2188 IORegistryEntry *options = IORegistryEntry::fromPath(path: "/options", plane: gIODTPlane);
2189 if (options == NULL) {
2190 return; // /options may not be present
2191 }
2192
2193 assert(gIOOptionsEntry == NULL);
2194 gIOOptionsEntry = new IODTNVRAM;
2195
2196 assert(gIOOptionsEntry != NULL);
2197
2198 gIOOptionsEntry->init(old: options, plane: gIODTPlane);
2199 gIOOptionsEntry->attach(provider: this);
2200 gIOOptionsEntry->start(provider: this);
2201 options->release();
2202}
2203
2204void
2205IOPlatformExpertDevice::generatePlatformUUID( void )
2206{
2207 IORegistryEntry * entry;
2208 OSString * string = NULL;
2209 uuid_string_t uuid;
2210
2211#if !defined(__x86_64__)
2212 entry = IORegistryEntry::fromPath( path: "/chosen", plane: gIODTPlane );
2213 if (entry) {
2214 OSData * data1;
2215
2216 data1 = OSDynamicCast( OSData, entry->getProperty( "unique-chip-id" ));
2217 if (data1 && data1->getLength() == 8) {
2218 OSData * data2;
2219
2220 data2 = OSDynamicCast( OSData, entry->getProperty( "chip-id" ));
2221 if (data2 && data2->getLength() == 4) {
2222 SHA1_CTX context;
2223 uint8_t digest[SHA_DIGEST_LENGTH];
2224 const uuid_t space = { 0xA6, 0xDD, 0x4C, 0xCB, 0xB5, 0xE8, 0x4A, 0xF5, 0xAC, 0xDD, 0xB6, 0xDC, 0x6A, 0x05, 0x42, 0xB8 };
2225
2226 SHA1Init( &context );
2227 SHA1Update( &context, space, sizeof(space));
2228 SHA1Update( &context, data1->getBytesNoCopy(), data1->getLength());
2229 SHA1Update( &context, data2->getBytesNoCopy(), data2->getLength());
2230 SHA1Final( digest, &context );
2231
2232 digest[6] = (digest[6] & 0x0F) | 0x50;
2233 digest[8] = (digest[8] & 0x3F) | 0x80;
2234
2235 uuid_unparse( uu: digest, out: uuid );
2236 string = OSString::withCString( cString: uuid );
2237 }
2238 }
2239
2240 entry->release();
2241 }
2242#else /* !defined(__x86_64__) */
2243 OSData * data;
2244
2245 entry = IORegistryEntry::fromPath( "/efi/platform", gIODTPlane );
2246 if (entry) {
2247 data = OSDynamicCast( OSData, entry->getProperty( "system-id" ));
2248 if (data && data->getLength() == 16) {
2249 SHA1_CTX context;
2250 uint8_t digest[SHA_DIGEST_LENGTH];
2251 const uuid_t space = { 0x2A, 0x06, 0x19, 0x90, 0xD3, 0x8D, 0x44, 0x40, 0xA1, 0x39, 0xC4, 0x97, 0x70, 0x37, 0x65, 0xAC };
2252
2253 SHA1Init( &context );
2254 SHA1Update( &context, space, sizeof(space));
2255 SHA1Update( &context, data->getBytesNoCopy(), data->getLength());
2256 SHA1Final( digest, &context );
2257
2258 digest[6] = (digest[6] & 0x0F) | 0x50;
2259 digest[8] = (digest[8] & 0x3F) | 0x80;
2260
2261 uuid_unparse( digest, uuid );
2262 string = OSString::withCString( uuid );
2263 }
2264
2265 entry->release();
2266 }
2267 if (!string) {
2268 /* vmware still runs this path */
2269 entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
2270 if (entry) {
2271 data = OSDynamicCast( OSData, entry->getProperty( "platform-uuid" ));
2272 if (data && data->getLength() == sizeof(uuid_t)) {
2273 uuid_unparse((uint8_t *) data->getBytesNoCopy(), uuid );
2274 string = OSString::withCString( uuid );
2275 }
2276 entry->release();
2277 }
2278 }
2279#endif /* defined(__x86_64__) */
2280
2281 if (string) {
2282 setProperty( kIOPlatformUUIDKey, anObject: string );
2283 gIOPlatformUUIDAndSerialDone = true;
2284
2285 string->release();
2286 }
2287}
2288/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2289
2290#undef super
2291#define super IOService
2292
2293OSDefineMetaClassAndStructors(IOPlatformDevice, IOService)
2294
2295OSMetaClassDefineReservedUnused(IOPlatformDevice, 0);
2296OSMetaClassDefineReservedUnused(IOPlatformDevice, 1);
2297OSMetaClassDefineReservedUnused(IOPlatformDevice, 2);
2298OSMetaClassDefineReservedUnused(IOPlatformDevice, 3);
2299
2300/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2301
2302bool
2303IOPlatformDevice::compareName( OSString * name,
2304 OSString ** matched ) const
2305{
2306 return ((IOPlatformExpert *)getProvider())->
2307 compareNubName( nub: this, name, matched );
2308}
2309
2310IOService *
2311IOPlatformDevice::matchLocation( IOService * /* client */ )
2312{
2313 return this;
2314}
2315
2316IOReturn
2317IOPlatformDevice::getResources( void )
2318{
2319 return ((IOPlatformExpert *)getProvider())->getNubResources( nub: this );
2320}
2321
2322/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2323
2324/*********************************************************************
2325* IOPanicPlatform class
2326*
2327* If no legitimate IOPlatformDevice matches, this one does and panics
2328* the kernel with a suitable message.
2329*********************************************************************/
2330
2331class IOPanicPlatform : IOPlatformExpert {
2332 OSDeclareDefaultStructors(IOPanicPlatform);
2333
2334public:
2335 bool start(IOService * provider) APPLE_KEXT_OVERRIDE;
2336};
2337
2338
2339OSDefineMetaClassAndStructors(IOPanicPlatform, IOPlatformExpert);
2340
2341
2342bool
2343IOPanicPlatform::start(IOService * provider)
2344{
2345 const char * platform_name = "(unknown platform name)";
2346
2347 if (provider) {
2348 platform_name = provider->getName();
2349 }
2350
2351 panic("Unable to find driver for this platform: \"%s\".",
2352 platform_name);
2353
2354 return false;
2355}
2356