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