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