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