2 * Copyright (c) 1998-2014 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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>
44 #include <IOKit/system.h>
46 #include <libkern/c++/OSContainers.h>
47 #include <libkern/crypto/sha1.h>
48 #include <libkern/OSAtomic.h>
51 #include <machine/machine_routines.h>
52 #include <pexpert/pexpert.h>
53 #include <uuid/uuid.h>
56 void printDictionaryKeys (OSDictionary
* inDictionary
, char * inMsg
);
57 static void getCStringForObject(OSObject
*inObj
, char *outStr
, size_t outStrLen
);
59 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
61 #define super IOService
63 OSDefineMetaClassAndStructors(IOPlatformExpert
, IOService
)
65 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 0);
66 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 1);
67 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 2);
68 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 3);
69 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 4);
71 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 5);
72 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 6);
73 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 7);
74 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 8);
75 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 9);
76 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 10);
77 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 11);
79 static IOPlatformExpert
* gIOPlatform
;
80 static OSDictionary
* gIOInterruptControllers
;
81 static IOLock
* gIOInterruptControllersLock
;
82 static IODTNVRAM
*gIOOptionsEntry
;
84 OSSymbol
* gPlatformInterruptControllerName
;
86 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
88 bool IOPlatformExpert::attach( IOService
* provider
)
91 if( !super::attach( provider
))
97 bool IOPlatformExpert::start( IOService
* provider
)
99 IORangeAllocator
* physicalRanges
;
100 OSData
* busFrequency
;
103 if (!super::start(provider
))
106 // Override the mapper present flag is requested by boot arguments.
107 if (PE_parse_boot_argn("dart", &debugFlags
, sizeof (debugFlags
)) && (debugFlags
== 0))
108 removeProperty(kIOPlatformMapperPresentKey
);
109 if (PE_parse_boot_argn("-x", &debugFlags
, sizeof (debugFlags
)))
110 removeProperty(kIOPlatformMapperPresentKey
);
112 // Register the presence or lack thereof a system
113 // PCI address mapper with the IOMapper class
114 IOMapper::setMapperRequired(0 != getProperty(kIOPlatformMapperPresentKey
));
116 gIOInterruptControllers
= OSDictionary::withCapacity(1);
117 gIOInterruptControllersLock
= IOLockAlloc();
119 // Correct the bus frequency in the device tree.
120 busFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.bus_clock_rate_hz
, 4);
121 provider
->setProperty("clock-frequency", busFrequency
);
122 busFrequency
->release();
124 gPlatformInterruptControllerName
= (OSSymbol
*)OSSymbol::withCStringNoCopy("IOPlatformInterruptController");
126 physicalRanges
= IORangeAllocator::withRange(0xffffffff, 1, 16,
127 IORangeAllocator::kLocking
);
128 assert(physicalRanges
);
129 setProperty("Platform Memory Ranges", physicalRanges
);
134 PMInstantiatePowerDomains();
136 // Parse the serial-number data and publish a user-readable string
137 OSData
* mydata
= (OSData
*) (provider
->getProperty("serial-number"));
138 if (mydata
!= NULL
) {
139 OSString
*serNoString
= createSystemSerialNumberString(mydata
);
140 if (serNoString
!= NULL
) {
141 provider
->setProperty(kIOPlatformSerialNumberKey
, serNoString
);
142 serNoString
->release();
146 return( configure(provider
) );
149 bool IOPlatformExpert::configure( IOService
* provider
)
155 topLevel
= OSDynamicCast( OSSet
, getProperty("top-level"));
158 while( (dict
= OSDynamicCast( OSDictionary
,
159 topLevel
->getAnyObject()))) {
161 topLevel
->removeObject( dict
);
162 nub
= createNub( dict
);
167 nub
->registerService();
174 IOService
* IOPlatformExpert::createNub( OSDictionary
* from
)
178 nub
= new IOPlatformDevice
;
180 if( !nub
->init( from
)) {
188 bool IOPlatformExpert::compareNubName( const IOService
* nub
,
189 OSString
* name
, OSString
** matched
) const
191 return( nub
->IORegistryEntry::compareName( name
, matched
));
194 IOReturn
IOPlatformExpert::getNubResources( IOService
* nub
)
196 return( kIOReturnSuccess
);
199 long IOPlatformExpert::getBootROMType(void)
201 return _peBootROMType
;
204 long IOPlatformExpert::getChipSetType(void)
206 return _peChipSetType
;
209 long IOPlatformExpert::getMachineType(void)
211 return _peMachineType
;
214 void IOPlatformExpert::setBootROMType(long peBootROMType
)
216 _peBootROMType
= peBootROMType
;
219 void IOPlatformExpert::setChipSetType(long peChipSetType
)
221 _peChipSetType
= peChipSetType
;
224 void IOPlatformExpert::setMachineType(long peMachineType
)
226 _peMachineType
= peMachineType
;
229 bool IOPlatformExpert::getMachineName( char * /*name*/, int /*maxLength*/)
234 bool IOPlatformExpert::getModelName( char * /*name*/, int /*maxLength*/)
239 OSString
* IOPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
)
244 IORangeAllocator
* IOPlatformExpert::getPhysicalRangeAllocator(void)
246 return(OSDynamicCast(IORangeAllocator
,
247 getProperty("Platform Memory Ranges")));
250 int (*PE_halt_restart
)(unsigned int type
) = 0;
252 int IOPlatformExpert::haltRestart(unsigned int type
)
254 if (type
== kPEPanicSync
) return 0;
256 if (type
== kPEHangCPU
) while (true) {}
258 if (type
== kPEUPSDelayHaltCPU
) {
259 // RestartOnPowerLoss feature was turned on, proceed with shutdown.
263 // On ARM kPEPanicRestartCPU is supported in the drivers
264 if (type
== kPEPanicRestartCPU
)
265 type
= kPERestartCPU
;
267 if (PE_halt_restart
) return (*PE_halt_restart
)(type
);
271 void IOPlatformExpert::sleepKernel(void)
277 intState
= ml_set_interrupts_enabled(false);
279 for (cnt
= 0; cnt
< 10000; cnt
++) {
283 ml_set_interrupts_enabled(intState
);
285 // PE_initialize_console(0, kPEDisableScreen);
289 // PE_initialize_console(0, kPEEnableScreen);
293 long IOPlatformExpert::getGMTTimeOfDay(void)
298 void IOPlatformExpert::setGMTTimeOfDay(long secs
)
303 IOReturn
IOPlatformExpert::getConsoleInfo( PE_Video
* consoleInfo
)
305 return( PE_current_console( consoleInfo
));
308 IOReturn
IOPlatformExpert::setConsoleInfo( PE_Video
* consoleInfo
,
311 return( PE_initialize_console( consoleInfo
, op
));
314 IOReturn
IOPlatformExpert::registerInterruptController(OSSymbol
*name
, IOInterruptController
*interruptController
)
316 IOLockLock(gIOInterruptControllersLock
);
318 gIOInterruptControllers
->setObject(name
, interruptController
);
320 IOLockWakeup(gIOInterruptControllersLock
,
321 gIOInterruptControllers
, /* one-thread */ false);
323 IOLockUnlock(gIOInterruptControllersLock
);
325 return kIOReturnSuccess
;
328 IOReturn
IOPlatformExpert::deregisterInterruptController(OSSymbol
*name
)
330 IOLockLock(gIOInterruptControllersLock
);
332 gIOInterruptControllers
->removeObject(name
);
334 IOLockUnlock(gIOInterruptControllersLock
);
336 return kIOReturnSuccess
;
339 IOInterruptController
*IOPlatformExpert::lookUpInterruptController(OSSymbol
*name
)
343 IOLockLock(gIOInterruptControllersLock
);
346 object
= gIOInterruptControllers
->getObject(name
);
351 IOLockSleep(gIOInterruptControllersLock
,
352 gIOInterruptControllers
, THREAD_UNINT
);
355 IOLockUnlock(gIOInterruptControllersLock
);
356 return OSDynamicCast(IOInterruptController
, object
);
360 void IOPlatformExpert::setCPUInterruptProperties(IOService
*service
)
362 IOCPUInterruptController
*controller
;
364 controller
= OSDynamicCast(IOCPUInterruptController
, waitForService(serviceMatching("IOCPUInterruptController")));
365 if (controller
) controller
->setCPUInterruptProperties(service
);
368 bool IOPlatformExpert::atInterruptLevel(void)
370 return ml_at_interrupt_context();
373 bool IOPlatformExpert::platformAdjustService(IOService */
*service*/
)
378 void IOPlatformExpert::getUTCTimeOfDay(clock_sec_t
* secs
, clock_nsec_t
* nsecs
)
380 *secs
= getGMTTimeOfDay();
384 void IOPlatformExpert::setUTCTimeOfDay(clock_sec_t secs
, __unused clock_nsec_t nsecs
)
386 setGMTTimeOfDay(secs
);
390 //*********************************************************************************
393 //*********************************************************************************
395 void IOPlatformExpert::
396 PMLog(const char *who
, unsigned long event
,
397 unsigned long param1
, unsigned long param2
)
401 clock_get_system_microtime(&nows
, &nowus
);
402 nowus
+= (nows
% 1000) * 1000000;
404 kprintf("pm%u %p %.30s %d %lx %lx\n",
405 nowus
, OBFUSCATE(current_thread()), who
, // Identity
406 (int) event
, (long)OBFUSCATE(param1
), (long)OBFUSCATE(param2
)); // Args
410 //*********************************************************************************
411 // PMInstantiatePowerDomains
413 // In this vanilla implementation, a Root Power Domain is instantiated.
414 // All other objects which register will be children of this Root.
415 // Where this is inappropriate, PMInstantiatePowerDomains is overridden
416 // in a platform-specific subclass.
417 //*********************************************************************************
419 void IOPlatformExpert::PMInstantiatePowerDomains ( void )
421 root
= new IOPMrootDomain
;
428 //*********************************************************************************
431 // In this vanilla implementation, all callers are made children of the root power domain.
432 // Where this is inappropriate, PMRegisterDevice is overridden in a platform-specific subclass.
433 //*********************************************************************************
435 void IOPlatformExpert::PMRegisterDevice(IOService
* theNub
, IOService
* theDevice
)
437 root
->addPowerChild ( theDevice
);
440 //*********************************************************************************
443 //*********************************************************************************
445 bool IOPlatformExpert::hasPMFeature (unsigned long featureMask
)
447 return ((_pePMFeatures
& featureMask
) != 0);
450 //*********************************************************************************
453 //*********************************************************************************
455 bool IOPlatformExpert::hasPrivPMFeature (unsigned long privFeatureMask
)
457 return ((_pePrivPMFeatures
& privFeatureMask
) != 0);
460 //*********************************************************************************
461 // numBatteriesSupported
463 //*********************************************************************************
465 int IOPlatformExpert::numBatteriesSupported (void)
467 return (_peNumBatteriesSupported
);
470 //*********************************************************************************
473 // This method is called by the instantiated sublass of the platform expert to
474 // determine how a device should be inserted into the Power Domain. The subclass
475 // provides an XML power tree description against which a device is matched based
476 // on class and provider. If a match is found this routine returns true in addition
477 // to flagging the description tree at the appropriate node that a device has been
478 // registered for the given service.
479 //*********************************************************************************
481 bool IOPlatformExpert::CheckSubTree (OSArray
* inSubTree
, IOService
* theNub
, IOService
* theDevice
, OSDictionary
* theParent
)
484 unsigned int numPowerTreeNodes
;
485 OSDictionary
* entry
;
486 OSDictionary
* matchingDictionary
;
487 OSDictionary
* providerDictionary
;
488 OSDictionary
* deviceDictionary
;
489 OSDictionary
* nubDictionary
;
491 bool nodeFound
= false;
492 bool continueSearch
= false;
493 bool deviceMatch
= false;
494 bool providerMatch
= false;
495 bool multiParentMatch
= false;
497 if ( (NULL
== theDevice
) || (NULL
== inSubTree
) )
500 numPowerTreeNodes
= inSubTree
->getCount ();
502 // iterate through the power tree to find a home for this device
504 for ( i
= 0; i
< numPowerTreeNodes
; i
++ ) {
506 entry
= (OSDictionary
*) inSubTree
->getObject (i
);
508 matchingDictionary
= (OSDictionary
*) entry
->getObject ("device");
509 providerDictionary
= (OSDictionary
*) entry
->getObject ("provider");
511 deviceMatch
= true; // if no matching dictionary, this is not a criteria and so must match
512 if ( matchingDictionary
) {
514 if ( NULL
!= (deviceDictionary
= theDevice
->dictionaryWithProperties ())) {
515 deviceMatch
= deviceDictionary
->isEqualTo ( matchingDictionary
, matchingDictionary
);
516 deviceDictionary
->release ();
520 providerMatch
= true; // we indicate a match if there is no nub or provider
521 if ( theNub
&& providerDictionary
) {
522 providerMatch
= false;
523 if ( NULL
!= (nubDictionary
= theNub
->dictionaryWithProperties ()) ) {
524 providerMatch
= nubDictionary
->isEqualTo ( providerDictionary
, providerDictionary
);
525 nubDictionary
->release ();
529 multiParentMatch
= true; // again we indicate a match if there is no multi-parent node
530 if (deviceMatch
&& providerMatch
) {
531 if (NULL
!= multipleParentKeyValue
) {
532 OSNumber
* aNumber
= (OSNumber
*) entry
->getObject ("multiple-parent");
533 multiParentMatch
= (NULL
!= aNumber
) ? multipleParentKeyValue
->isEqualTo (aNumber
) : false;
537 nodeFound
= (deviceMatch
&& providerMatch
&& multiParentMatch
);
539 // if the power tree specifies a provider dictionary but theNub is
540 // NULL then we cannot match with this entry.
542 if ( theNub
== NULL
&& providerDictionary
!= NULL
)
545 // if this node is THE ONE...then register the device
548 if (RegisterServiceInTree (theDevice
, entry
, theParent
, theNub
) ) {
550 if ( kIOLogPower
& gIOKitDebug
)
551 IOLog ("PMRegisterDevice/CheckSubTree - service registered!\n");
553 numInstancesRegistered
++;
555 // determine if we need to search for additional nodes for this item
556 multipleParentKeyValue
= (OSNumber
*) entry
->getObject ("multiple-parent");
562 continueSearch
= ( (false == nodeFound
) || (NULL
!= multipleParentKeyValue
) );
564 if ( continueSearch
&& (NULL
!= (children
= (OSArray
*) entry
->getObject ("children"))) ) {
565 nodeFound
= CheckSubTree ( children
, theNub
, theDevice
, entry
);
566 continueSearch
= ( (false == nodeFound
) || (NULL
!= multipleParentKeyValue
) );
569 if ( false == continueSearch
)
573 return ( nodeFound
);
576 //*********************************************************************************
577 // RegisterServiceInTree
579 // Register a device at the specified node of our power tree.
580 //*********************************************************************************
582 bool IOPlatformExpert::RegisterServiceInTree (IOService
* theService
, OSDictionary
* theTreeNode
, OSDictionary
* theTreeParentNode
, IOService
* theProvider
)
584 IOService
* aService
;
585 bool registered
= false;
587 unsigned int numChildren
;
588 OSDictionary
* child
;
590 // make sure someone is not already registered here
592 if ( NULL
== theTreeNode
->getObject ("service") ) {
594 if ( theTreeNode
->setObject ("service", OSDynamicCast ( OSObject
, theService
)) ) {
596 // 1. CHILDREN ------------------
598 // we registered the node in the tree...now if the node has children
599 // registered we must tell this service to add them.
601 if ( NULL
!= (children
= (OSArray
*) theTreeNode
->getObject ("children")) ) {
602 numChildren
= children
->getCount ();
603 for ( unsigned int i
= 0; i
< numChildren
; i
++ ) {
604 if ( NULL
!= (child
= (OSDictionary
*) children
->getObject (i
)) ) {
605 if ( NULL
!= (aService
= (IOService
*) child
->getObject ("service")) )
606 theService
->addPowerChild (aService
);
611 // 2. PARENT --------------------
613 // also we must notify the parent of this node (if a registered service
614 // exists there) of a new child.
616 if ( theTreeParentNode
) {
617 if ( NULL
!= (aService
= (IOService
*) theTreeParentNode
->getObject ("service")) )
618 if (aService
!= theProvider
)
619 aService
->addPowerChild (theService
);
629 //*********************************************************************************
630 // printDictionaryKeys
632 // Print the keys for the given dictionary and selected contents.
633 //*********************************************************************************
634 void printDictionaryKeys (OSDictionary
* inDictionary
, char * inMsg
)
636 OSCollectionIterator
* mcoll
= OSCollectionIterator::withCollection (inDictionary
);
643 mkey
= OSDynamicCast (OSSymbol
, mcoll
->getNextObject ());
647 // kprintf ("dictionary key #%d: %s\n", i, mkey->getCStringNoCopy () );
649 // if this is the IOClass key, print it's contents
651 if ( mkey
->isEqualTo ("IOClass") ) {
652 ioClass
= (OSString
*) inDictionary
->getObject ("IOClass");
653 if ( ioClass
) IOLog ("%s IOClass is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
656 // if this is an IOProviderClass key print it
658 if ( mkey
->isEqualTo ("IOProviderClass") ) {
659 ioClass
= (OSString
*) inDictionary
->getObject ("IOProviderClass");
660 if ( ioClass
) IOLog ("%s IOProviderClass is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
664 // also print IONameMatch keys
665 if ( mkey
->isEqualTo ("IONameMatch") ) {
666 ioClass
= (OSString
*) inDictionary
->getObject ("IONameMatch");
667 if ( ioClass
) IOLog ("%s IONameMatch is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
670 // also print IONameMatched keys
672 if ( mkey
->isEqualTo ("IONameMatched") ) {
673 ioClass
= (OSString
*) inDictionary
->getObject ("IONameMatched");
674 if ( ioClass
) IOLog ("%s IONameMatched is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
680 if ( mkey
->isEqualTo ("AAPL,clock-id") ) {
682 cstr
= getCStringForObject (inDictionary
->getObject ("AAPL,clock-id"));
684 kprintf (" ===> AAPL,clock-id is %s\n", cstr
);
690 if ( mkey
->isEqualTo ("name") ) {
693 getCStringForObject(inDictionary
->getObject("name"), nameStr
,
695 if (strlen(nameStr
) > 0)
696 IOLog ("%s name is %s\n", inMsg
, nameStr
);
699 mkey
= (OSSymbol
*) mcoll
->getNextObject ();
708 getCStringForObject(OSObject
*inObj
, char *outStr
, size_t outStrLen
)
713 if ( (NULL
== inObj
) || (NULL
== outStr
))
716 char * objString
= (char *) (inObj
->getMetaClass())->getClassName();
718 if ((0 == strncmp(objString
, "OSString", sizeof("OSString"))) ||
719 (0 == strncmp(objString
, "OSSymbol", sizeof("OSSymbol"))))
720 strlcpy(outStr
, ((OSString
*)inObj
)->getCStringNoCopy(), outStrLen
);
722 else if (0 == strncmp(objString
, "OSData", sizeof("OSData"))) {
723 len
= ((OSData
*)inObj
)->getLength();
724 buffer
= (char *)((OSData
*)inObj
)->getBytesNoCopy();
725 if (buffer
&& (len
> 0)) {
726 for (i
=0; i
< len
; i
++) {
727 outStr
[i
] = buffer
[i
];
734 /* IOShutdownNotificationsTimedOut
735 * - Called from a timer installed by PEHaltRestart
737 static void IOShutdownNotificationsTimedOut(
738 thread_call_param_t p0
,
739 thread_call_param_t p1
)
741 int type
= (int)(long)p0
;
743 /* 30 seconds has elapsed - resume shutdown */
744 if(gIOPlatform
) gIOPlatform
->haltRestart(type
);
751 * Callouts from BSD for machine name & model
754 boolean_t
PEGetMachineName( char * name
, int maxLength
)
757 return( gIOPlatform
->getMachineName( name
, maxLength
));
762 boolean_t
PEGetModelName( char * name
, int maxLength
)
765 return( gIOPlatform
->getModelName( name
, maxLength
));
770 int PEGetPlatformEpoch(void)
773 return( gIOPlatform
->getBootROMType());
778 int PEHaltRestart(unsigned int type
)
780 IOPMrootDomain
*pmRootDomain
;
781 AbsoluteTime deadline
;
782 thread_call_t shutdown_hang
;
783 IORegistryEntry
*node
;
785 uint32_t timeout
= 30;
787 if(type
== kPEHaltCPU
|| type
== kPERestartCPU
|| type
== kPEUPSDelayHaltCPU
)
789 pmRootDomain
= IOService::getPMRootDomain();
790 /* Notify IOKit PM clients of shutdown/restart
791 Clients subscribe to this message with a call to
792 IOService::registerInterest()
795 /* Spawn a thread that will panic in 30 seconds.
796 If all goes well the machine will be off by the time
797 the timer expires. If the device wants a different
798 timeout, use that value instead of 30 seconds.
800 #define RESTART_NODE_PATH "/chosen"
801 node
= IORegistryEntry::fromPath( RESTART_NODE_PATH
, gIODTPlane
);
803 data
= OSDynamicCast( OSData
, node
->getProperty( "halt-restart-timeout" ) );
804 if ( data
&& data
->getLength() == 4 )
805 timeout
= *((uint32_t *) data
->getBytesNoCopy());
808 shutdown_hang
= thread_call_allocate( &IOShutdownNotificationsTimedOut
,
809 (thread_call_param_t
)(uintptr_t) type
);
810 clock_interval_to_deadline( timeout
, kSecondScale
, &deadline
);
811 thread_call_enter1_delayed( shutdown_hang
, 0, deadline
);
813 pmRootDomain
->handlePlatformHaltRestart(type
);
814 /* This notification should have few clients who all do
815 their work synchronously.
817 In this "shutdown notification" context we don't give
818 drivers the option of working asynchronously and responding
819 later. PM internals make it very hard to wait for asynchronous
823 else if(type
== kPEPanicRestartCPU
|| type
== kPEPanicSync
)
825 IOCPURunPlatformPanicActions(type
);
828 if (gIOPlatform
) return gIOPlatform
->haltRestart(type
);
832 UInt32
PESavePanicInfo(UInt8
*buffer
, UInt32 length
)
834 if (gIOPlatform
!= 0) return gIOPlatform
->savePanicInfo(buffer
, length
);
840 inline static int init_gIOOptionsEntry(void)
842 IORegistryEntry
*entry
;
844 volatile void **options
;
850 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
854 nvram_entry
= (void *) OSDynamicCast(IODTNVRAM
, entry
);
858 options
= (volatile void **) &gIOOptionsEntry
;
859 if (!OSCompareAndSwapPtr(NULL
, nvram_entry
, options
)) {
872 /* pass in a NULL value if you just want to figure out the len */
873 boolean_t
PEReadNVRAMProperty(const char *symbol
, void *value
,
883 if (init_gIOOptionsEntry() < 0)
889 obj
= gIOOptionsEntry
->getProperty(symbol
);
893 /* convert to data */
894 data
= OSDynamicCast(OSData
, obj
);
898 *len
= data
->getLength();
899 vlen
= min(vlen
, *len
);
901 memcpy((void *) value
, data
->getBytesNoCopy(), vlen
);
910 PEWriteNVRAMBooleanProperty(const char *symbol
, boolean_t value
)
912 const OSSymbol
*sym
= NULL
;
913 OSBoolean
*data
= NULL
;
916 if (symbol
== NULL
) {
920 if (init_gIOOptionsEntry() < 0) {
924 if ((sym
= OSSymbol::withCStringNoCopy(symbol
)) == NULL
) {
928 data
= value
? kOSBooleanTrue
: kOSBooleanFalse
;
929 ret
= gIOOptionsEntry
->setProperty(sym
, data
);
933 /* success, force the NVRAM to flush writes */
935 gIOOptionsEntry
->sync();
942 boolean_t
PEWriteNVRAMProperty(const char *symbol
, const void *value
,
943 const unsigned int len
)
949 if (!symbol
|| !value
|| !len
)
952 if (init_gIOOptionsEntry() < 0)
955 sym
= OSSymbol::withCStringNoCopy(symbol
);
959 data
= OSData::withBytes((void *) value
, len
);
963 ret
= gIOOptionsEntry
->setProperty(sym
, data
);
970 gIOOptionsEntry
->sync();
979 boolean_t
PERemoveNVRAMProperty(const char *symbol
)
986 if (init_gIOOptionsEntry() < 0)
989 sym
= OSSymbol::withCStringNoCopy(symbol
);
993 gIOOptionsEntry
->removeProperty(sym
);
997 gIOOptionsEntry
->sync();
1005 long PEGetGMTTimeOfDay(void)
1010 PEGetUTCTimeOfDay(&secs
, &usecs
);
1014 void PESetGMTTimeOfDay(long secs
)
1016 PESetUTCTimeOfDay(secs
, 0);
1019 void PEGetUTCTimeOfDay(clock_sec_t
* secs
, clock_usec_t
* usecs
)
1021 clock_nsec_t nsecs
= 0;
1025 gIOPlatform
->getUTCTimeOfDay(secs
, &nsecs
);
1027 assert(nsecs
< NSEC_PER_SEC
);
1028 *usecs
= nsecs
/ NSEC_PER_USEC
;
1031 void PESetUTCTimeOfDay(clock_sec_t secs
, clock_usec_t usecs
)
1033 assert(usecs
< USEC_PER_SEC
);
1035 gIOPlatform
->setUTCTimeOfDay(secs
, usecs
* NSEC_PER_USEC
);
1040 void IOPlatformExpert::registerNVRAMController(IONVRAMController
* caller
)
1043 IORegistryEntry
* entry
;
1044 OSString
* string
= 0;
1047 entry
= IORegistryEntry::fromPath( "/efi/platform", gIODTPlane
);
1050 data
= OSDynamicCast( OSData
, entry
->getProperty( "system-id" ) );
1051 if ( data
&& data
->getLength( ) == 16 )
1054 uint8_t digest
[ SHA_DIGEST_LENGTH
];
1055 const uuid_t space
= { 0x2A, 0x06, 0x19, 0x90, 0xD3, 0x8D, 0x44, 0x40, 0xA1, 0x39, 0xC4, 0x97, 0x70, 0x37, 0x65, 0xAC };
1057 SHA1Init( &context
);
1058 SHA1Update( &context
, space
, sizeof( space
) );
1059 SHA1Update( &context
, data
->getBytesNoCopy( ), data
->getLength( ) );
1060 SHA1Final( digest
, &context
);
1062 digest
[ 6 ] = ( digest
[ 6 ] & 0x0F ) | 0x50;
1063 digest
[ 8 ] = ( digest
[ 8 ] & 0x3F ) | 0x80;
1065 uuid_unparse( digest
, uuid
);
1066 string
= OSString::withCString( uuid
);
1074 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
1077 data
= OSDynamicCast( OSData
, entry
->getProperty( "platform-uuid" ) );
1078 if ( data
&& data
->getLength( ) == sizeof( uuid_t
) )
1080 uuid_unparse( ( uint8_t * ) data
->getBytesNoCopy( ), uuid
);
1081 string
= OSString::withCString( uuid
);
1090 getProvider( )->setProperty( kIOPlatformUUIDKey
, string
);
1091 publishResource( kIOPlatformUUIDKey
, string
);
1096 publishResource("IONVRAM");
1099 IOReturn
IOPlatformExpert::callPlatformFunction(const OSSymbol
*functionName
,
1100 bool waitForFunction
,
1101 void *param1
, void *param2
,
1102 void *param3
, void *param4
)
1104 IOService
*service
, *_resources
;
1106 if (waitForFunction
) {
1107 _resources
= waitForService(resourceMatching(functionName
));
1109 _resources
= getResourceService();
1111 if (_resources
== 0) return kIOReturnUnsupported
;
1113 service
= OSDynamicCast(IOService
, _resources
->getProperty(functionName
));
1114 if (service
== 0) return kIOReturnUnsupported
;
1116 return service
->callPlatformFunction(functionName
, waitForFunction
,
1117 param1
, param2
, param3
, param4
);
1120 IOByteCount
IOPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1125 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1128 #define super IOPlatformExpert
1130 OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert
, IOPlatformExpert
)
1132 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 0);
1133 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 1);
1134 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 2);
1135 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 3);
1136 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 4);
1137 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 5);
1138 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 6);
1139 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 7);
1141 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1143 IOService
* IODTPlatformExpert::probe( IOService
* provider
,
1146 if( !super::probe( provider
, score
))
1149 // check machine types
1150 if( !provider
->compareNames( getProperty( gIONameMatchKey
) ))
1156 bool IODTPlatformExpert::configure( IOService
* provider
)
1158 if( !super::configure( provider
))
1161 processTopLevel( provider
);
1166 IOService
* IODTPlatformExpert::createNub( IORegistryEntry
* from
)
1170 nub
= new IOPlatformDevice
;
1172 if( !nub
->init( from
, gIODTPlane
)) {
1180 bool IODTPlatformExpert::createNubs( IOService
* parent
, OSIterator
* iter
)
1182 IORegistryEntry
* next
;
1187 while( (next
= (IORegistryEntry
*) iter
->getNextObject())) {
1189 if( 0 == (nub
= createNub( next
)))
1192 nub
->attach( parent
);
1193 nub
->registerService();
1201 void IODTPlatformExpert::processTopLevel( IORegistryEntry
* rootEntry
)
1204 IORegistryEntry
* next
;
1205 IORegistryEntry
* cpus
;
1206 IORegistryEntry
* options
;
1209 kids
= IODTFindMatchingEntries( rootEntry
, 0, deleteList() );
1211 while( (next
= (IORegistryEntry
*)kids
->getNextObject())) {
1212 next
->detachAll( gIODTPlane
);
1217 // Publish an IODTNVRAM class on /options.
1218 options
= rootEntry
->childFromPath("options", gIODTPlane
);
1220 dtNVRAM
= new IODTNVRAM
;
1222 if (!dtNVRAM
->init(options
, gIODTPlane
)) {
1226 dtNVRAM
->attach(this);
1227 dtNVRAM
->registerService();
1233 // Publish the cpus.
1234 cpus
= rootEntry
->childFromPath( "cpus", gIODTPlane
);
1237 createNubs( this, IODTFindMatchingEntries( cpus
, kIODTExclusive
, 0));
1241 // publish top level, minus excludeList
1242 createNubs( this, IODTFindMatchingEntries( rootEntry
, kIODTExclusive
, excludeList()));
1245 IOReturn
IODTPlatformExpert::getNubResources( IOService
* nub
)
1247 if( nub
->getDeviceMemory())
1248 return( kIOReturnSuccess
);
1250 IODTResolveAddressing( nub
, "reg", 0);
1252 return( kIOReturnSuccess
);
1255 bool IODTPlatformExpert::compareNubName( const IOService
* nub
,
1256 OSString
* name
, OSString
** matched
) const
1258 return( IODTCompareNubName( nub
, name
, matched
)
1259 || super::compareNubName( nub
, name
, matched
) );
1262 bool IODTPlatformExpert::getModelName( char * name
, int maxLength
)
1272 prop
= (OSData
*) getProvider()->getProperty( gIODTCompatibleKey
);
1274 str
= (const char *) prop
->getBytesNoCopy();
1276 if( 0 == strncmp( str
, "AAPL,", strlen( "AAPL," ) ))
1277 str
+= strlen( "AAPL," );
1280 while( (c
= *str
++)) {
1281 if( (c
== '/') || (c
== ' '))
1285 if( len
>= maxLength
)
1295 bool IODTPlatformExpert::getMachineName( char * name
, int maxLength
)
1301 prop
= (OSData
*) getProvider()->getProperty( gIODTModelKey
);
1305 strlcpy( name
, (const char *) prop
->getBytesNoCopy(), maxLength
);
1310 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1312 void IODTPlatformExpert::registerNVRAMController( IONVRAMController
* nvram
)
1314 if (dtNVRAM
) dtNVRAM
->registerNVRAMController(nvram
);
1316 super::registerNVRAMController(nvram
);
1319 int IODTPlatformExpert::haltRestart(unsigned int type
)
1321 if (dtNVRAM
) dtNVRAM
->sync();
1323 return super::haltRestart(type
);
1326 IOReturn
IODTPlatformExpert::readXPRAM(IOByteCount offset
, UInt8
* buffer
,
1329 if (dtNVRAM
) return dtNVRAM
->readXPRAM(offset
, buffer
, length
);
1330 else return kIOReturnNotReady
;
1333 IOReturn
IODTPlatformExpert::writeXPRAM(IOByteCount offset
, UInt8
* buffer
,
1336 if (dtNVRAM
) return dtNVRAM
->writeXPRAM(offset
, buffer
, length
);
1337 else return kIOReturnNotReady
;
1340 IOReturn
IODTPlatformExpert::readNVRAMProperty(
1341 IORegistryEntry
* entry
,
1342 const OSSymbol
** name
, OSData
** value
)
1344 if (dtNVRAM
) return dtNVRAM
->readNVRAMProperty(entry
, name
, value
);
1345 else return kIOReturnNotReady
;
1348 IOReturn
IODTPlatformExpert::writeNVRAMProperty(
1349 IORegistryEntry
* entry
,
1350 const OSSymbol
* name
, OSData
* value
)
1352 if (dtNVRAM
) return dtNVRAM
->writeNVRAMProperty(entry
, name
, value
);
1353 else return kIOReturnNotReady
;
1356 OSDictionary
*IODTPlatformExpert::getNVRAMPartitions(void)
1358 if (dtNVRAM
) return dtNVRAM
->getNVRAMPartitions();
1362 IOReturn
IODTPlatformExpert::readNVRAMPartition(const OSSymbol
* partitionID
,
1363 IOByteCount offset
, UInt8
* buffer
,
1366 if (dtNVRAM
) return dtNVRAM
->readNVRAMPartition(partitionID
, offset
,
1368 else return kIOReturnNotReady
;
1371 IOReturn
IODTPlatformExpert::writeNVRAMPartition(const OSSymbol
* partitionID
,
1372 IOByteCount offset
, UInt8
* buffer
,
1375 if (dtNVRAM
) return dtNVRAM
->writeNVRAMPartition(partitionID
, offset
,
1377 else return kIOReturnNotReady
;
1380 IOByteCount
IODTPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1382 IOByteCount lengthSaved
= 0;
1384 if (dtNVRAM
) lengthSaved
= dtNVRAM
->savePanicInfo(buffer
, length
);
1386 if (lengthSaved
== 0) lengthSaved
= super::savePanicInfo(buffer
, length
);
1391 OSString
* IODTPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
) {
1392 UInt8
* serialNumber
;
1393 unsigned int serialNumberSize
;
1394 unsigned short pos
= 0;
1398 if (myProperty
!= NULL
) {
1399 serialNumberSize
= myProperty
->getLength();
1400 serialNumber
= (UInt8
*)(myProperty
->getBytesNoCopy());
1401 temp
= (char*)serialNumber
;
1402 if (serialNumberSize
> 0) {
1403 // check to see if this is a CTO serial number...
1404 while (pos
< serialNumberSize
&& temp
[pos
] != '-') pos
++;
1406 if (pos
< serialNumberSize
) { // there was a hyphen, so it's a CTO serial number
1407 memcpy(SerialNo
, serialNumber
+ 12, 8);
1408 memcpy(&SerialNo
[8], serialNumber
, 3);
1410 memcpy(&SerialNo
[12], serialNumber
+ 3, 8);
1412 } else { // just a normal serial number
1413 memcpy(SerialNo
, serialNumber
+ 13, 8);
1414 memcpy(&SerialNo
[8], serialNumber
, 3);
1417 return OSString::withCString(SerialNo
);
1424 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1427 #define super IOService
1429 OSDefineMetaClassAndStructors(IOPlatformExpertDevice
, IOService
)
1431 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 0);
1432 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 1);
1433 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 2);
1434 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 3);
1436 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1438 bool IOPlatformExpertDevice::compareName( OSString
* name
,
1439 OSString
** matched
) const
1441 return( IODTCompareNubName( this, name
, matched
));
1445 IOPlatformExpertDevice::initWithArgs(
1446 void * dtTop
, void * p2
, void * p3
, void * p4
)
1448 IORegistryEntry
* dt
= 0;
1451 // dtTop may be zero on non- device tree systems
1452 if( dtTop
&& (dt
= IODeviceTreeAlloc( dtTop
)))
1453 ok
= super::init( dt
, gIODTPlane
);
1461 workLoop
= IOWorkLoop::workLoop();
1468 IOWorkLoop
*IOPlatformExpertDevice::getWorkLoop() const
1473 IOReturn
IOPlatformExpertDevice::setProperties( OSObject
* properties
)
1475 OSDictionary
* dictionary
;
1479 status
= super::setProperties( properties
);
1480 if ( status
!= kIOReturnUnsupported
) return status
;
1482 status
= IOUserClient::clientHasPrivilege( current_task( ), kIOClientPrivilegeAdministrator
);
1483 if ( status
!= kIOReturnSuccess
) return status
;
1485 dictionary
= OSDynamicCast( OSDictionary
, properties
);
1486 if ( dictionary
== 0 ) return kIOReturnBadArgument
;
1488 object
= dictionary
->getObject( kIOPlatformUUIDKey
);
1491 IORegistryEntry
* entry
;
1495 string
= ( OSString
* ) getProperty( kIOPlatformUUIDKey
);
1496 if ( string
) return kIOReturnNotPermitted
;
1498 string
= OSDynamicCast( OSString
, object
);
1499 if ( string
== 0 ) return kIOReturnBadArgument
;
1501 status
= uuid_parse( string
->getCStringNoCopy( ), uuid
);
1502 if ( status
!= 0 ) return kIOReturnBadArgument
;
1504 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
1507 entry
->setProperty( "platform-uuid", uuid
, sizeof( uuid_t
) );
1511 setProperty( kIOPlatformUUIDKey
, string
);
1512 publishResource( kIOPlatformUUIDKey
, string
);
1514 return kIOReturnSuccess
;
1517 return kIOReturnUnsupported
;
1520 IOReturn
IOPlatformExpertDevice::newUserClient( task_t owningTask
, void * securityID
,
1521 UInt32 type
, OSDictionary
* properties
,
1522 IOUserClient
** handler
)
1524 IOReturn err
= kIOReturnSuccess
;
1525 IOUserClient
* newConnect
= 0;
1526 IOUserClient
* theConnect
= 0;
1530 case kIOKitDiagnosticsClientType
:
1531 newConnect
= IOKitDiagnosticsClient::withTask(owningTask
);
1532 if (!newConnect
) err
= kIOReturnNotPermitted
;
1535 err
= kIOReturnBadArgument
;
1540 if ((false == newConnect
->attach(this))
1541 || (false == newConnect
->start(this)))
1543 newConnect
->detach( this );
1544 newConnect
->release();
1547 theConnect
= newConnect
;
1550 *handler
= theConnect
;
1554 void IOPlatformExpertDevice::free()
1557 workLoop
->release();
1560 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1563 #define super IOService
1565 OSDefineMetaClassAndStructors(IOPlatformDevice
, IOService
)
1567 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 0);
1568 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 1);
1569 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 2);
1570 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 3);
1572 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1574 bool IOPlatformDevice::compareName( OSString
* name
,
1575 OSString
** matched
) const
1577 return( ((IOPlatformExpert
*)getProvider())->
1578 compareNubName( this, name
, matched
));
1581 IOService
* IOPlatformDevice::matchLocation( IOService
* /* client */ )
1586 IOReturn
IOPlatformDevice::getResources( void )
1588 return( ((IOPlatformExpert
*)getProvider())->getNubResources( this ));
1591 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1593 /*********************************************************************
1594 * IOPanicPlatform class
1596 * If no legitimate IOPlatformDevice matches, this one does and panics
1597 * the kernel with a suitable message.
1598 *********************************************************************/
1600 class IOPanicPlatform
: IOPlatformExpert
{
1601 OSDeclareDefaultStructors(IOPanicPlatform
);
1604 bool start(IOService
* provider
) APPLE_KEXT_OVERRIDE
;
1608 OSDefineMetaClassAndStructors(IOPanicPlatform
, IOPlatformExpert
);
1611 bool IOPanicPlatform::start(IOService
* provider
) {
1612 const char * platform_name
= "(unknown platform name)";
1614 if (provider
) platform_name
= provider
->getName();
1616 panic("Unable to find driver for this platform: \"%s\".\n",