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