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