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
);
826 PE_sync_panic_buffers();
829 if (gIOPlatform
) return gIOPlatform
->haltRestart(type
);
833 UInt32
PESavePanicInfo(UInt8
*buffer
, UInt32 length
)
835 if (gIOPlatform
!= 0) return gIOPlatform
->savePanicInfo(buffer
, length
);
841 inline static int init_gIOOptionsEntry(void)
843 IORegistryEntry
*entry
;
845 volatile void **options
;
851 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
855 nvram_entry
= (void *) OSDynamicCast(IODTNVRAM
, entry
);
859 options
= (volatile void **) &gIOOptionsEntry
;
860 if (!OSCompareAndSwapPtr(NULL
, nvram_entry
, options
)) {
873 /* pass in a NULL value if you just want to figure out the len */
874 boolean_t
PEReadNVRAMProperty(const char *symbol
, void *value
,
884 if (init_gIOOptionsEntry() < 0)
890 obj
= gIOOptionsEntry
->getProperty(symbol
);
894 /* convert to data */
895 data
= OSDynamicCast(OSData
, obj
);
899 *len
= data
->getLength();
900 vlen
= min(vlen
, *len
);
902 memcpy((void *) value
, data
->getBytesNoCopy(), vlen
);
911 PEWriteNVRAMBooleanProperty(const char *symbol
, boolean_t value
)
913 const OSSymbol
*sym
= NULL
;
914 OSBoolean
*data
= NULL
;
917 if (symbol
== NULL
) {
921 if (init_gIOOptionsEntry() < 0) {
925 if ((sym
= OSSymbol::withCStringNoCopy(symbol
)) == NULL
) {
929 data
= value
? kOSBooleanTrue
: kOSBooleanFalse
;
930 ret
= gIOOptionsEntry
->setProperty(sym
, data
);
934 /* success, force the NVRAM to flush writes */
936 gIOOptionsEntry
->sync();
943 boolean_t
PEWriteNVRAMProperty(const char *symbol
, const void *value
,
944 const unsigned int len
)
950 if (!symbol
|| !value
|| !len
)
953 if (init_gIOOptionsEntry() < 0)
956 sym
= OSSymbol::withCStringNoCopy(symbol
);
960 data
= OSData::withBytes((void *) value
, len
);
964 ret
= gIOOptionsEntry
->setProperty(sym
, data
);
971 gIOOptionsEntry
->sync();
980 boolean_t
PERemoveNVRAMProperty(const char *symbol
)
987 if (init_gIOOptionsEntry() < 0)
990 sym
= OSSymbol::withCStringNoCopy(symbol
);
994 gIOOptionsEntry
->removeProperty(sym
);
998 gIOOptionsEntry
->sync();
1006 long PEGetGMTTimeOfDay(void)
1011 PEGetUTCTimeOfDay(&secs
, &usecs
);
1015 void PESetGMTTimeOfDay(long secs
)
1017 PESetUTCTimeOfDay(secs
, 0);
1020 void PEGetUTCTimeOfDay(clock_sec_t
* secs
, clock_usec_t
* usecs
)
1022 clock_nsec_t nsecs
= 0;
1026 gIOPlatform
->getUTCTimeOfDay(secs
, &nsecs
);
1028 assert(nsecs
< NSEC_PER_SEC
);
1029 *usecs
= nsecs
/ NSEC_PER_USEC
;
1032 void PESetUTCTimeOfDay(clock_sec_t secs
, clock_usec_t usecs
)
1034 assert(usecs
< USEC_PER_SEC
);
1036 gIOPlatform
->setUTCTimeOfDay(secs
, usecs
* NSEC_PER_USEC
);
1041 void IOPlatformExpert::registerNVRAMController(IONVRAMController
* caller
)
1044 IORegistryEntry
* entry
;
1045 OSString
* string
= 0;
1048 entry
= IORegistryEntry::fromPath( "/efi/platform", gIODTPlane
);
1051 data
= OSDynamicCast( OSData
, entry
->getProperty( "system-id" ) );
1052 if ( data
&& data
->getLength( ) == 16 )
1055 uint8_t digest
[ SHA_DIGEST_LENGTH
];
1056 const uuid_t space
= { 0x2A, 0x06, 0x19, 0x90, 0xD3, 0x8D, 0x44, 0x40, 0xA1, 0x39, 0xC4, 0x97, 0x70, 0x37, 0x65, 0xAC };
1058 SHA1Init( &context
);
1059 SHA1Update( &context
, space
, sizeof( space
) );
1060 SHA1Update( &context
, data
->getBytesNoCopy( ), data
->getLength( ) );
1061 SHA1Final( digest
, &context
);
1063 digest
[ 6 ] = ( digest
[ 6 ] & 0x0F ) | 0x50;
1064 digest
[ 8 ] = ( digest
[ 8 ] & 0x3F ) | 0x80;
1066 uuid_unparse( digest
, uuid
);
1067 string
= OSString::withCString( uuid
);
1075 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
1078 data
= OSDynamicCast( OSData
, entry
->getProperty( "platform-uuid" ) );
1079 if ( data
&& data
->getLength( ) == sizeof( uuid_t
) )
1081 uuid_unparse( ( uint8_t * ) data
->getBytesNoCopy( ), uuid
);
1082 string
= OSString::withCString( uuid
);
1091 getProvider( )->setProperty( kIOPlatformUUIDKey
, string
);
1092 publishResource( kIOPlatformUUIDKey
, string
);
1097 publishResource("IONVRAM");
1100 IOReturn
IOPlatformExpert::callPlatformFunction(const OSSymbol
*functionName
,
1101 bool waitForFunction
,
1102 void *param1
, void *param2
,
1103 void *param3
, void *param4
)
1105 IOService
*service
, *_resources
;
1107 if (waitForFunction
) {
1108 _resources
= waitForService(resourceMatching(functionName
));
1110 _resources
= getResourceService();
1112 if (_resources
== 0) return kIOReturnUnsupported
;
1114 service
= OSDynamicCast(IOService
, _resources
->getProperty(functionName
));
1115 if (service
== 0) return kIOReturnUnsupported
;
1117 return service
->callPlatformFunction(functionName
, waitForFunction
,
1118 param1
, param2
, param3
, param4
);
1121 IOByteCount
IOPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1126 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1129 #define super IOPlatformExpert
1131 OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert
, IOPlatformExpert
)
1133 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 0);
1134 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 1);
1135 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 2);
1136 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 3);
1137 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 4);
1138 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 5);
1139 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 6);
1140 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 7);
1142 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1144 IOService
* IODTPlatformExpert::probe( IOService
* provider
,
1147 if( !super::probe( provider
, score
))
1150 // check machine types
1151 if( !provider
->compareNames( getProperty( gIONameMatchKey
) ))
1157 bool IODTPlatformExpert::configure( IOService
* provider
)
1159 if( !super::configure( provider
))
1162 processTopLevel( provider
);
1167 IOService
* IODTPlatformExpert::createNub( IORegistryEntry
* from
)
1171 nub
= new IOPlatformDevice
;
1173 if( !nub
->init( from
, gIODTPlane
)) {
1181 bool IODTPlatformExpert::createNubs( IOService
* parent
, OSIterator
* iter
)
1183 IORegistryEntry
* next
;
1188 while( (next
= (IORegistryEntry
*) iter
->getNextObject())) {
1190 if( 0 == (nub
= createNub( next
)))
1193 nub
->attach( parent
);
1194 nub
->registerService();
1202 void IODTPlatformExpert::processTopLevel( IORegistryEntry
* rootEntry
)
1205 IORegistryEntry
* next
;
1206 IORegistryEntry
* cpus
;
1207 IORegistryEntry
* options
;
1210 kids
= IODTFindMatchingEntries( rootEntry
, 0, deleteList() );
1212 while( (next
= (IORegistryEntry
*)kids
->getNextObject())) {
1213 next
->detachAll( gIODTPlane
);
1218 // Publish an IODTNVRAM class on /options.
1219 options
= rootEntry
->childFromPath("options", gIODTPlane
);
1221 dtNVRAM
= new IODTNVRAM
;
1223 if (!dtNVRAM
->init(options
, gIODTPlane
)) {
1227 dtNVRAM
->attach(this);
1228 dtNVRAM
->registerService();
1234 // Publish the cpus.
1235 cpus
= rootEntry
->childFromPath( "cpus", gIODTPlane
);
1238 createNubs( this, IODTFindMatchingEntries( cpus
, kIODTExclusive
, 0));
1242 // publish top level, minus excludeList
1243 createNubs( this, IODTFindMatchingEntries( rootEntry
, kIODTExclusive
, excludeList()));
1246 IOReturn
IODTPlatformExpert::getNubResources( IOService
* nub
)
1248 if( nub
->getDeviceMemory())
1249 return( kIOReturnSuccess
);
1251 IODTResolveAddressing( nub
, "reg", 0);
1253 return( kIOReturnSuccess
);
1256 bool IODTPlatformExpert::compareNubName( const IOService
* nub
,
1257 OSString
* name
, OSString
** matched
) const
1259 return( IODTCompareNubName( nub
, name
, matched
)
1260 || super::compareNubName( nub
, name
, matched
) );
1263 bool IODTPlatformExpert::getModelName( char * name
, int maxLength
)
1273 prop
= (OSData
*) getProvider()->getProperty( gIODTCompatibleKey
);
1275 str
= (const char *) prop
->getBytesNoCopy();
1277 if( 0 == strncmp( str
, "AAPL,", strlen( "AAPL," ) ))
1278 str
+= strlen( "AAPL," );
1281 while( (c
= *str
++)) {
1282 if( (c
== '/') || (c
== ' '))
1286 if( len
>= maxLength
)
1296 bool IODTPlatformExpert::getMachineName( char * name
, int maxLength
)
1302 prop
= (OSData
*) getProvider()->getProperty( gIODTModelKey
);
1306 strlcpy( name
, (const char *) prop
->getBytesNoCopy(), maxLength
);
1311 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1313 void IODTPlatformExpert::registerNVRAMController( IONVRAMController
* nvram
)
1315 if (dtNVRAM
) dtNVRAM
->registerNVRAMController(nvram
);
1317 super::registerNVRAMController(nvram
);
1320 int IODTPlatformExpert::haltRestart(unsigned int type
)
1322 if (dtNVRAM
) dtNVRAM
->sync();
1324 return super::haltRestart(type
);
1327 IOReturn
IODTPlatformExpert::readXPRAM(IOByteCount offset
, UInt8
* buffer
,
1330 if (dtNVRAM
) return dtNVRAM
->readXPRAM(offset
, buffer
, length
);
1331 else return kIOReturnNotReady
;
1334 IOReturn
IODTPlatformExpert::writeXPRAM(IOByteCount offset
, UInt8
* buffer
,
1337 if (dtNVRAM
) return dtNVRAM
->writeXPRAM(offset
, buffer
, length
);
1338 else return kIOReturnNotReady
;
1341 IOReturn
IODTPlatformExpert::readNVRAMProperty(
1342 IORegistryEntry
* entry
,
1343 const OSSymbol
** name
, OSData
** value
)
1345 if (dtNVRAM
) return dtNVRAM
->readNVRAMProperty(entry
, name
, value
);
1346 else return kIOReturnNotReady
;
1349 IOReturn
IODTPlatformExpert::writeNVRAMProperty(
1350 IORegistryEntry
* entry
,
1351 const OSSymbol
* name
, OSData
* value
)
1353 if (dtNVRAM
) return dtNVRAM
->writeNVRAMProperty(entry
, name
, value
);
1354 else return kIOReturnNotReady
;
1357 OSDictionary
*IODTPlatformExpert::getNVRAMPartitions(void)
1359 if (dtNVRAM
) return dtNVRAM
->getNVRAMPartitions();
1363 IOReturn
IODTPlatformExpert::readNVRAMPartition(const OSSymbol
* partitionID
,
1364 IOByteCount offset
, UInt8
* buffer
,
1367 if (dtNVRAM
) return dtNVRAM
->readNVRAMPartition(partitionID
, offset
,
1369 else return kIOReturnNotReady
;
1372 IOReturn
IODTPlatformExpert::writeNVRAMPartition(const OSSymbol
* partitionID
,
1373 IOByteCount offset
, UInt8
* buffer
,
1376 if (dtNVRAM
) return dtNVRAM
->writeNVRAMPartition(partitionID
, offset
,
1378 else return kIOReturnNotReady
;
1381 IOByteCount
IODTPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1383 IOByteCount lengthSaved
= 0;
1385 if (dtNVRAM
) lengthSaved
= dtNVRAM
->savePanicInfo(buffer
, length
);
1387 if (lengthSaved
== 0) lengthSaved
= super::savePanicInfo(buffer
, length
);
1392 OSString
* IODTPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
) {
1393 UInt8
* serialNumber
;
1394 unsigned int serialNumberSize
;
1395 unsigned short pos
= 0;
1399 if (myProperty
!= NULL
) {
1400 serialNumberSize
= myProperty
->getLength();
1401 serialNumber
= (UInt8
*)(myProperty
->getBytesNoCopy());
1402 temp
= (char*)serialNumber
;
1403 if (serialNumberSize
> 0) {
1404 // check to see if this is a CTO serial number...
1405 while (pos
< serialNumberSize
&& temp
[pos
] != '-') pos
++;
1407 if (pos
< serialNumberSize
) { // there was a hyphen, so it's a CTO serial number
1408 memcpy(SerialNo
, serialNumber
+ 12, 8);
1409 memcpy(&SerialNo
[8], serialNumber
, 3);
1411 memcpy(&SerialNo
[12], serialNumber
+ 3, 8);
1413 } else { // just a normal serial number
1414 memcpy(SerialNo
, serialNumber
+ 13, 8);
1415 memcpy(&SerialNo
[8], serialNumber
, 3);
1418 return OSString::withCString(SerialNo
);
1425 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1428 #define super IOService
1430 OSDefineMetaClassAndStructors(IOPlatformExpertDevice
, IOService
)
1432 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 0);
1433 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 1);
1434 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 2);
1435 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 3);
1437 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1439 bool IOPlatformExpertDevice::compareName( OSString
* name
,
1440 OSString
** matched
) const
1442 return( IODTCompareNubName( this, name
, matched
));
1446 IOPlatformExpertDevice::initWithArgs(
1447 void * dtTop
, void * p2
, void * p3
, void * p4
)
1449 IORegistryEntry
* dt
= 0;
1452 // dtTop may be zero on non- device tree systems
1453 if( dtTop
&& (dt
= IODeviceTreeAlloc( dtTop
)))
1454 ok
= super::init( dt
, gIODTPlane
);
1462 workLoop
= IOWorkLoop::workLoop();
1469 IOWorkLoop
*IOPlatformExpertDevice::getWorkLoop() const
1474 IOReturn
IOPlatformExpertDevice::setProperties( OSObject
* properties
)
1476 OSDictionary
* dictionary
;
1480 status
= super::setProperties( properties
);
1481 if ( status
!= kIOReturnUnsupported
) return status
;
1483 status
= IOUserClient::clientHasPrivilege( current_task( ), kIOClientPrivilegeAdministrator
);
1484 if ( status
!= kIOReturnSuccess
) return status
;
1486 dictionary
= OSDynamicCast( OSDictionary
, properties
);
1487 if ( dictionary
== 0 ) return kIOReturnBadArgument
;
1489 object
= dictionary
->getObject( kIOPlatformUUIDKey
);
1492 IORegistryEntry
* entry
;
1496 string
= ( OSString
* ) getProperty( kIOPlatformUUIDKey
);
1497 if ( string
) return kIOReturnNotPermitted
;
1499 string
= OSDynamicCast( OSString
, object
);
1500 if ( string
== 0 ) return kIOReturnBadArgument
;
1502 status
= uuid_parse( string
->getCStringNoCopy( ), uuid
);
1503 if ( status
!= 0 ) return kIOReturnBadArgument
;
1505 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
1508 entry
->setProperty( "platform-uuid", uuid
, sizeof( uuid_t
) );
1512 setProperty( kIOPlatformUUIDKey
, string
);
1513 publishResource( kIOPlatformUUIDKey
, string
);
1515 return kIOReturnSuccess
;
1518 return kIOReturnUnsupported
;
1521 IOReturn
IOPlatformExpertDevice::newUserClient( task_t owningTask
, void * securityID
,
1522 UInt32 type
, OSDictionary
* properties
,
1523 IOUserClient
** handler
)
1525 IOReturn err
= kIOReturnSuccess
;
1526 IOUserClient
* newConnect
= 0;
1527 IOUserClient
* theConnect
= 0;
1531 case kIOKitDiagnosticsClientType
:
1532 newConnect
= IOKitDiagnosticsClient::withTask(owningTask
);
1533 if (!newConnect
) err
= kIOReturnNotPermitted
;
1536 err
= kIOReturnBadArgument
;
1541 if ((false == newConnect
->attach(this))
1542 || (false == newConnect
->start(this)))
1544 newConnect
->detach( this );
1545 newConnect
->release();
1546 err
= kIOReturnNotPermitted
;
1549 theConnect
= newConnect
;
1552 *handler
= theConnect
;
1556 void IOPlatformExpertDevice::free()
1559 workLoop
->release();
1562 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1565 #define super IOService
1567 OSDefineMetaClassAndStructors(IOPlatformDevice
, IOService
)
1569 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 0);
1570 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 1);
1571 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 2);
1572 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 3);
1574 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1576 bool IOPlatformDevice::compareName( OSString
* name
,
1577 OSString
** matched
) const
1579 return( ((IOPlatformExpert
*)getProvider())->
1580 compareNubName( this, name
, matched
));
1583 IOService
* IOPlatformDevice::matchLocation( IOService
* /* client */ )
1588 IOReturn
IOPlatformDevice::getResources( void )
1590 return( ((IOPlatformExpert
*)getProvider())->getNubResources( this ));
1593 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1595 /*********************************************************************
1596 * IOPanicPlatform class
1598 * If no legitimate IOPlatformDevice matches, this one does and panics
1599 * the kernel with a suitable message.
1600 *********************************************************************/
1602 class IOPanicPlatform
: IOPlatformExpert
{
1603 OSDeclareDefaultStructors(IOPanicPlatform
);
1606 bool start(IOService
* provider
) APPLE_KEXT_OVERRIDE
;
1610 OSDefineMetaClassAndStructors(IOPanicPlatform
, IOPlatformExpert
);
1613 bool IOPanicPlatform::start(IOService
* provider
) {
1614 const char * platform_name
= "(unknown platform name)";
1616 if (provider
) platform_name
= provider
->getName();
1618 panic("Unable to find driver for this platform: \"%s\".\n",