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>
43 #include <IOKit/system.h>
45 #include <libkern/c++/OSContainers.h>
46 #include <libkern/crypto/sha1.h>
47 #include <libkern/OSAtomic.h>
50 #include <machine/machine_routines.h>
51 #include <pexpert/pexpert.h>
52 #include <uuid/uuid.h>
55 void printDictionaryKeys (OSDictionary
* inDictionary
, char * inMsg
);
56 static void getCStringForObject(OSObject
*inObj
, char *outStr
, size_t outStrLen
);
58 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
60 #define super IOService
62 OSDefineMetaClassAndStructors(IOPlatformExpert
, IOService
)
64 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 0);
65 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 1);
66 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 2);
67 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 3);
68 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 4);
70 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 5);
71 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 6);
72 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 7);
73 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 8);
74 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 9);
75 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 10);
76 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 11);
78 static IOPlatformExpert
* gIOPlatform
;
79 static OSDictionary
* gIOInterruptControllers
;
80 static IOLock
* gIOInterruptControllersLock
;
81 static IODTNVRAM
*gIOOptionsEntry
;
83 OSSymbol
* gPlatformInterruptControllerName
;
85 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
87 bool IOPlatformExpert::attach( IOService
* provider
)
90 if( !super::attach( provider
))
96 bool IOPlatformExpert::start( IOService
* provider
)
98 IORangeAllocator
* physicalRanges
;
99 OSData
* busFrequency
;
102 if (!super::start(provider
))
105 // Override the mapper present flag is requested by boot arguments.
106 if (PE_parse_boot_argn("dart", &debugFlags
, sizeof (debugFlags
)) && (debugFlags
== 0))
107 removeProperty(kIOPlatformMapperPresentKey
);
108 if (PE_parse_boot_argn("-x", &debugFlags
, sizeof (debugFlags
)))
109 removeProperty(kIOPlatformMapperPresentKey
);
111 // Register the presence or lack thereof a system
112 // PCI address mapper with the IOMapper class
113 IOMapper::setMapperRequired(0 != getProperty(kIOPlatformMapperPresentKey
));
115 gIOInterruptControllers
= OSDictionary::withCapacity(1);
116 gIOInterruptControllersLock
= IOLockAlloc();
118 // Correct the bus frequency in the device tree.
119 busFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.bus_clock_rate_hz
, 4);
120 provider
->setProperty("clock-frequency", busFrequency
);
121 busFrequency
->release();
123 gPlatformInterruptControllerName
= (OSSymbol
*)OSSymbol::withCStringNoCopy("IOPlatformInterruptController");
125 physicalRanges
= IORangeAllocator::withRange(0xffffffff, 1, 16,
126 IORangeAllocator::kLocking
);
127 assert(physicalRanges
);
128 setProperty("Platform Memory Ranges", physicalRanges
);
133 PMInstantiatePowerDomains();
135 // Parse the serial-number data and publish a user-readable string
136 OSData
* mydata
= (OSData
*) (provider
->getProperty("serial-number"));
137 if (mydata
!= NULL
) {
138 OSString
*serNoString
= createSystemSerialNumberString(mydata
);
139 if (serNoString
!= NULL
) {
140 provider
->setProperty(kIOPlatformSerialNumberKey
, serNoString
);
141 serNoString
->release();
145 return( configure(provider
) );
148 bool IOPlatformExpert::configure( IOService
* provider
)
154 topLevel
= OSDynamicCast( OSSet
, getProperty("top-level"));
157 while( (dict
= OSDynamicCast( OSDictionary
,
158 topLevel
->getAnyObject()))) {
160 topLevel
->removeObject( dict
);
161 nub
= createNub( dict
);
166 nub
->registerService();
173 IOService
* IOPlatformExpert::createNub( OSDictionary
* from
)
177 nub
= new IOPlatformDevice
;
179 if( !nub
->init( from
)) {
187 bool IOPlatformExpert::compareNubName( const IOService
* nub
,
188 OSString
* name
, OSString
** matched
) const
190 return( nub
->IORegistryEntry::compareName( name
, matched
));
193 IOReturn
IOPlatformExpert::getNubResources( IOService
* nub
)
195 return( kIOReturnSuccess
);
198 long IOPlatformExpert::getBootROMType(void)
200 return _peBootROMType
;
203 long IOPlatformExpert::getChipSetType(void)
205 return _peChipSetType
;
208 long IOPlatformExpert::getMachineType(void)
210 return _peMachineType
;
213 void IOPlatformExpert::setBootROMType(long peBootROMType
)
215 _peBootROMType
= peBootROMType
;
218 void IOPlatformExpert::setChipSetType(long peChipSetType
)
220 _peChipSetType
= peChipSetType
;
223 void IOPlatformExpert::setMachineType(long peMachineType
)
225 _peMachineType
= peMachineType
;
228 bool IOPlatformExpert::getMachineName( char * /*name*/, int /*maxLength*/)
233 bool IOPlatformExpert::getModelName( char * /*name*/, int /*maxLength*/)
238 OSString
* IOPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
)
243 IORangeAllocator
* IOPlatformExpert::getPhysicalRangeAllocator(void)
245 return(OSDynamicCast(IORangeAllocator
,
246 getProperty("Platform Memory Ranges")));
249 int (*PE_halt_restart
)(unsigned int type
) = 0;
251 int IOPlatformExpert::haltRestart(unsigned int type
)
253 if (type
== kPEPanicSync
) return 0;
255 if (type
== kPEHangCPU
) while (true) {}
257 if (type
== kPEUPSDelayHaltCPU
) {
258 // RestartOnPowerLoss feature was turned on, proceed with shutdown.
262 // On ARM kPEPanicRestartCPU is supported in the drivers
263 if (type
== kPEPanicRestartCPU
)
264 type
= kPERestartCPU
;
266 if (PE_halt_restart
) return (*PE_halt_restart
)(type
);
270 void IOPlatformExpert::sleepKernel(void)
276 intState
= ml_set_interrupts_enabled(false);
278 for (cnt
= 0; cnt
< 10000; cnt
++) {
282 ml_set_interrupts_enabled(intState
);
284 // PE_initialize_console(0, kPEDisableScreen);
288 // PE_initialize_console(0, kPEEnableScreen);
292 long IOPlatformExpert::getGMTTimeOfDay(void)
297 void IOPlatformExpert::setGMTTimeOfDay(long secs
)
302 IOReturn
IOPlatformExpert::getConsoleInfo( PE_Video
* consoleInfo
)
304 return( PE_current_console( consoleInfo
));
307 IOReturn
IOPlatformExpert::setConsoleInfo( PE_Video
* consoleInfo
,
310 return( PE_initialize_console( consoleInfo
, op
));
313 IOReturn
IOPlatformExpert::registerInterruptController(OSSymbol
*name
, IOInterruptController
*interruptController
)
315 IOLockLock(gIOInterruptControllersLock
);
317 gIOInterruptControllers
->setObject(name
, interruptController
);
319 IOLockWakeup(gIOInterruptControllersLock
,
320 gIOInterruptControllers
, /* one-thread */ false);
322 IOLockUnlock(gIOInterruptControllersLock
);
324 return kIOReturnSuccess
;
327 IOReturn
IOPlatformExpert::deregisterInterruptController(OSSymbol
*name
)
329 IOLockLock(gIOInterruptControllersLock
);
331 gIOInterruptControllers
->removeObject(name
);
333 IOLockUnlock(gIOInterruptControllersLock
);
335 return kIOReturnSuccess
;
338 IOInterruptController
*IOPlatformExpert::lookUpInterruptController(OSSymbol
*name
)
342 IOLockLock(gIOInterruptControllersLock
);
345 object
= gIOInterruptControllers
->getObject(name
);
350 IOLockSleep(gIOInterruptControllersLock
,
351 gIOInterruptControllers
, THREAD_UNINT
);
354 IOLockUnlock(gIOInterruptControllersLock
);
355 return OSDynamicCast(IOInterruptController
, object
);
359 void IOPlatformExpert::setCPUInterruptProperties(IOService
*service
)
361 IOCPUInterruptController
*controller
;
363 controller
= OSDynamicCast(IOCPUInterruptController
, waitForService(serviceMatching("IOCPUInterruptController")));
364 if (controller
) controller
->setCPUInterruptProperties(service
);
367 bool IOPlatformExpert::atInterruptLevel(void)
369 return ml_at_interrupt_context();
372 bool IOPlatformExpert::platformAdjustService(IOService */
*service*/
)
377 void IOPlatformExpert::getUTCTimeOfDay(clock_sec_t
* secs
, clock_nsec_t
* nsecs
)
379 *secs
= getGMTTimeOfDay();
383 void IOPlatformExpert::setUTCTimeOfDay(clock_sec_t secs
, __unused clock_nsec_t nsecs
)
385 setGMTTimeOfDay(secs
);
389 //*********************************************************************************
392 //*********************************************************************************
394 void IOPlatformExpert::
395 PMLog(const char *who
, unsigned long event
,
396 unsigned long param1
, unsigned long param2
)
400 clock_get_system_microtime(&nows
, &nowus
);
401 nowus
+= (nows
% 1000) * 1000000;
403 kprintf("pm%u %p %.30s %d %lx %lx\n",
404 nowus
, OBFUSCATE(current_thread()), who
, // Identity
405 (int) event
, (long)OBFUSCATE(param1
), (long)OBFUSCATE(param2
)); // Args
409 //*********************************************************************************
410 // PMInstantiatePowerDomains
412 // In this vanilla implementation, a Root Power Domain is instantiated.
413 // All other objects which register will be children of this Root.
414 // Where this is inappropriate, PMInstantiatePowerDomains is overridden
415 // in a platform-specific subclass.
416 //*********************************************************************************
418 void IOPlatformExpert::PMInstantiatePowerDomains ( void )
420 root
= new IOPMrootDomain
;
427 //*********************************************************************************
430 // In this vanilla implementation, all callers are made children of the root power domain.
431 // Where this is inappropriate, PMRegisterDevice is overridden in a platform-specific subclass.
432 //*********************************************************************************
434 void IOPlatformExpert::PMRegisterDevice(IOService
* theNub
, IOService
* theDevice
)
436 root
->addPowerChild ( theDevice
);
439 //*********************************************************************************
442 //*********************************************************************************
444 bool IOPlatformExpert::hasPMFeature (unsigned long featureMask
)
446 return ((_pePMFeatures
& featureMask
) != 0);
449 //*********************************************************************************
452 //*********************************************************************************
454 bool IOPlatformExpert::hasPrivPMFeature (unsigned long privFeatureMask
)
456 return ((_pePrivPMFeatures
& privFeatureMask
) != 0);
459 //*********************************************************************************
460 // numBatteriesSupported
462 //*********************************************************************************
464 int IOPlatformExpert::numBatteriesSupported (void)
466 return (_peNumBatteriesSupported
);
469 //*********************************************************************************
472 // This method is called by the instantiated sublass of the platform expert to
473 // determine how a device should be inserted into the Power Domain. The subclass
474 // provides an XML power tree description against which a device is matched based
475 // on class and provider. If a match is found this routine returns true in addition
476 // to flagging the description tree at the appropriate node that a device has been
477 // registered for the given service.
478 //*********************************************************************************
480 bool IOPlatformExpert::CheckSubTree (OSArray
* inSubTree
, IOService
* theNub
, IOService
* theDevice
, OSDictionary
* theParent
)
483 unsigned int numPowerTreeNodes
;
484 OSDictionary
* entry
;
485 OSDictionary
* matchingDictionary
;
486 OSDictionary
* providerDictionary
;
487 OSDictionary
* deviceDictionary
;
488 OSDictionary
* nubDictionary
;
490 bool nodeFound
= false;
491 bool continueSearch
= false;
492 bool deviceMatch
= false;
493 bool providerMatch
= false;
494 bool multiParentMatch
= false;
496 if ( (NULL
== theDevice
) || (NULL
== inSubTree
) )
499 numPowerTreeNodes
= inSubTree
->getCount ();
501 // iterate through the power tree to find a home for this device
503 for ( i
= 0; i
< numPowerTreeNodes
; i
++ ) {
505 entry
= (OSDictionary
*) inSubTree
->getObject (i
);
507 matchingDictionary
= (OSDictionary
*) entry
->getObject ("device");
508 providerDictionary
= (OSDictionary
*) entry
->getObject ("provider");
510 deviceMatch
= true; // if no matching dictionary, this is not a criteria and so must match
511 if ( matchingDictionary
) {
513 if ( NULL
!= (deviceDictionary
= theDevice
->dictionaryWithProperties ())) {
514 deviceMatch
= deviceDictionary
->isEqualTo ( matchingDictionary
, matchingDictionary
);
515 deviceDictionary
->release ();
519 providerMatch
= true; // we indicate a match if there is no nub or provider
520 if ( theNub
&& providerDictionary
) {
521 providerMatch
= false;
522 if ( NULL
!= (nubDictionary
= theNub
->dictionaryWithProperties ()) ) {
523 providerMatch
= nubDictionary
->isEqualTo ( providerDictionary
, providerDictionary
);
524 nubDictionary
->release ();
528 multiParentMatch
= true; // again we indicate a match if there is no multi-parent node
529 if (deviceMatch
&& providerMatch
) {
530 if (NULL
!= multipleParentKeyValue
) {
531 OSNumber
* aNumber
= (OSNumber
*) entry
->getObject ("multiple-parent");
532 multiParentMatch
= (NULL
!= aNumber
) ? multipleParentKeyValue
->isEqualTo (aNumber
) : false;
536 nodeFound
= (deviceMatch
&& providerMatch
&& multiParentMatch
);
538 // if the power tree specifies a provider dictionary but theNub is
539 // NULL then we cannot match with this entry.
541 if ( theNub
== NULL
&& providerDictionary
!= NULL
)
544 // if this node is THE ONE...then register the device
547 if (RegisterServiceInTree (theDevice
, entry
, theParent
, theNub
) ) {
549 if ( kIOLogPower
& gIOKitDebug
)
550 IOLog ("PMRegisterDevice/CheckSubTree - service registered!\n");
552 numInstancesRegistered
++;
554 // determine if we need to search for additional nodes for this item
555 multipleParentKeyValue
= (OSNumber
*) entry
->getObject ("multiple-parent");
561 continueSearch
= ( (false == nodeFound
) || (NULL
!= multipleParentKeyValue
) );
563 if ( continueSearch
&& (NULL
!= (children
= (OSArray
*) entry
->getObject ("children"))) ) {
564 nodeFound
= CheckSubTree ( children
, theNub
, theDevice
, entry
);
565 continueSearch
= ( (false == nodeFound
) || (NULL
!= multipleParentKeyValue
) );
568 if ( false == continueSearch
)
572 return ( nodeFound
);
575 //*********************************************************************************
576 // RegisterServiceInTree
578 // Register a device at the specified node of our power tree.
579 //*********************************************************************************
581 bool IOPlatformExpert::RegisterServiceInTree (IOService
* theService
, OSDictionary
* theTreeNode
, OSDictionary
* theTreeParentNode
, IOService
* theProvider
)
583 IOService
* aService
;
584 bool registered
= false;
586 unsigned int numChildren
;
587 OSDictionary
* child
;
589 // make sure someone is not already registered here
591 if ( NULL
== theTreeNode
->getObject ("service") ) {
593 if ( theTreeNode
->setObject ("service", OSDynamicCast ( OSObject
, theService
)) ) {
595 // 1. CHILDREN ------------------
597 // we registered the node in the tree...now if the node has children
598 // registered we must tell this service to add them.
600 if ( NULL
!= (children
= (OSArray
*) theTreeNode
->getObject ("children")) ) {
601 numChildren
= children
->getCount ();
602 for ( unsigned int i
= 0; i
< numChildren
; i
++ ) {
603 if ( NULL
!= (child
= (OSDictionary
*) children
->getObject (i
)) ) {
604 if ( NULL
!= (aService
= (IOService
*) child
->getObject ("service")) )
605 theService
->addPowerChild (aService
);
610 // 2. PARENT --------------------
612 // also we must notify the parent of this node (if a registered service
613 // exists there) of a new child.
615 if ( theTreeParentNode
) {
616 if ( NULL
!= (aService
= (IOService
*) theTreeParentNode
->getObject ("service")) )
617 if (aService
!= theProvider
)
618 aService
->addPowerChild (theService
);
628 //*********************************************************************************
629 // printDictionaryKeys
631 // Print the keys for the given dictionary and selected contents.
632 //*********************************************************************************
633 void printDictionaryKeys (OSDictionary
* inDictionary
, char * inMsg
)
635 OSCollectionIterator
* mcoll
= OSCollectionIterator::withCollection (inDictionary
);
642 mkey
= OSDynamicCast (OSSymbol
, mcoll
->getNextObject ());
646 // kprintf ("dictionary key #%d: %s\n", i, mkey->getCStringNoCopy () );
648 // if this is the IOClass key, print it's contents
650 if ( mkey
->isEqualTo ("IOClass") ) {
651 ioClass
= (OSString
*) inDictionary
->getObject ("IOClass");
652 if ( ioClass
) IOLog ("%s IOClass is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
655 // if this is an IOProviderClass key print it
657 if ( mkey
->isEqualTo ("IOProviderClass") ) {
658 ioClass
= (OSString
*) inDictionary
->getObject ("IOProviderClass");
659 if ( ioClass
) IOLog ("%s IOProviderClass is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
663 // also print IONameMatch keys
664 if ( mkey
->isEqualTo ("IONameMatch") ) {
665 ioClass
= (OSString
*) inDictionary
->getObject ("IONameMatch");
666 if ( ioClass
) IOLog ("%s IONameMatch is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
669 // also print IONameMatched keys
671 if ( mkey
->isEqualTo ("IONameMatched") ) {
672 ioClass
= (OSString
*) inDictionary
->getObject ("IONameMatched");
673 if ( ioClass
) IOLog ("%s IONameMatched is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
679 if ( mkey
->isEqualTo ("AAPL,clock-id") ) {
681 cstr
= getCStringForObject (inDictionary
->getObject ("AAPL,clock-id"));
683 kprintf (" ===> AAPL,clock-id is %s\n", cstr
);
689 if ( mkey
->isEqualTo ("name") ) {
692 getCStringForObject(inDictionary
->getObject("name"), nameStr
,
694 if (strlen(nameStr
) > 0)
695 IOLog ("%s name is %s\n", inMsg
, nameStr
);
698 mkey
= (OSSymbol
*) mcoll
->getNextObject ();
707 getCStringForObject(OSObject
*inObj
, char *outStr
, size_t outStrLen
)
712 if ( (NULL
== inObj
) || (NULL
== outStr
))
715 char * objString
= (char *) (inObj
->getMetaClass())->getClassName();
717 if ((0 == strncmp(objString
, "OSString", sizeof("OSString"))) ||
718 (0 == strncmp(objString
, "OSSymbol", sizeof("OSSymbol"))))
719 strlcpy(outStr
, ((OSString
*)inObj
)->getCStringNoCopy(), outStrLen
);
721 else if (0 == strncmp(objString
, "OSData", sizeof("OSData"))) {
722 len
= ((OSData
*)inObj
)->getLength();
723 buffer
= (char *)((OSData
*)inObj
)->getBytesNoCopy();
724 if (buffer
&& (len
> 0)) {
725 for (i
=0; i
< len
; i
++) {
726 outStr
[i
] = buffer
[i
];
733 /* IOShutdownNotificationsTimedOut
734 * - Called from a timer installed by PEHaltRestart
736 static void IOShutdownNotificationsTimedOut(
737 thread_call_param_t p0
,
738 thread_call_param_t p1
)
740 int type
= (int)(long)p0
;
742 /* 30 seconds has elapsed - resume shutdown */
743 if(gIOPlatform
) gIOPlatform
->haltRestart(type
);
750 * Callouts from BSD for machine name & model
753 boolean_t
PEGetMachineName( char * name
, int maxLength
)
756 return( gIOPlatform
->getMachineName( name
, maxLength
));
761 boolean_t
PEGetModelName( char * name
, int maxLength
)
764 return( gIOPlatform
->getModelName( name
, maxLength
));
769 int PEGetPlatformEpoch(void)
772 return( gIOPlatform
->getBootROMType());
777 int PEHaltRestart(unsigned int type
)
779 IOPMrootDomain
*pmRootDomain
;
780 AbsoluteTime deadline
;
781 thread_call_t shutdown_hang
;
782 IORegistryEntry
*node
;
784 uint32_t timeout
= 30;
786 if(type
== kPEHaltCPU
|| type
== kPERestartCPU
|| type
== kPEUPSDelayHaltCPU
)
788 pmRootDomain
= IOService::getPMRootDomain();
789 /* Notify IOKit PM clients of shutdown/restart
790 Clients subscribe to this message with a call to
791 IOService::registerInterest()
794 /* Spawn a thread that will panic in 30 seconds.
795 If all goes well the machine will be off by the time
796 the timer expires. If the device wants a different
797 timeout, use that value instead of 30 seconds.
799 #define RESTART_NODE_PATH "/chosen"
800 node
= IORegistryEntry::fromPath( RESTART_NODE_PATH
, gIODTPlane
);
802 data
= OSDynamicCast( OSData
, node
->getProperty( "halt-restart-timeout" ) );
803 if ( data
&& data
->getLength() == 4 )
804 timeout
= *((uint32_t *) data
->getBytesNoCopy());
807 shutdown_hang
= thread_call_allocate( &IOShutdownNotificationsTimedOut
,
808 (thread_call_param_t
)(uintptr_t) type
);
809 clock_interval_to_deadline( timeout
, kSecondScale
, &deadline
);
810 thread_call_enter1_delayed( shutdown_hang
, 0, deadline
);
812 pmRootDomain
->handlePlatformHaltRestart(type
);
813 /* This notification should have few clients who all do
814 their work synchronously.
816 In this "shutdown notification" context we don't give
817 drivers the option of working asynchronously and responding
818 later. PM internals make it very hard to wait for asynchronous
823 if (gIOPlatform
) return gIOPlatform
->haltRestart(type
);
827 UInt32
PESavePanicInfo(UInt8
*buffer
, UInt32 length
)
829 if (gIOPlatform
!= 0) return gIOPlatform
->savePanicInfo(buffer
, length
);
835 inline static int init_gIOOptionsEntry(void)
837 IORegistryEntry
*entry
;
839 volatile void **options
;
845 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
849 nvram_entry
= (void *) OSDynamicCast(IODTNVRAM
, entry
);
853 options
= (volatile void **) &gIOOptionsEntry
;
854 if (!OSCompareAndSwapPtr(NULL
, nvram_entry
, options
)) {
867 /* pass in a NULL value if you just want to figure out the len */
868 boolean_t
PEReadNVRAMProperty(const char *symbol
, void *value
,
878 if (init_gIOOptionsEntry() < 0)
884 obj
= gIOOptionsEntry
->getProperty(symbol
);
888 /* convert to data */
889 data
= OSDynamicCast(OSData
, obj
);
893 *len
= data
->getLength();
894 vlen
= min(vlen
, *len
);
896 memcpy((void *) value
, data
->getBytesNoCopy(), vlen
);
905 boolean_t
PEWriteNVRAMProperty(const char *symbol
, const void *value
,
906 const unsigned int len
)
912 if (!symbol
|| !value
|| !len
)
915 if (init_gIOOptionsEntry() < 0)
918 sym
= OSSymbol::withCStringNoCopy(symbol
);
922 data
= OSData::withBytes((void *) value
, len
);
926 ret
= gIOOptionsEntry
->setProperty(sym
, data
);
933 gIOOptionsEntry
->sync();
942 boolean_t
PERemoveNVRAMProperty(const char *symbol
)
949 if (init_gIOOptionsEntry() < 0)
952 sym
= OSSymbol::withCStringNoCopy(symbol
);
956 gIOOptionsEntry
->removeProperty(sym
);
960 gIOOptionsEntry
->sync();
968 long PEGetGMTTimeOfDay(void)
973 PEGetUTCTimeOfDay(&secs
, &usecs
);
977 void PESetGMTTimeOfDay(long secs
)
979 PESetUTCTimeOfDay(secs
, 0);
982 void PEGetUTCTimeOfDay(clock_sec_t
* secs
, clock_usec_t
* usecs
)
984 clock_nsec_t nsecs
= 0;
988 gIOPlatform
->getUTCTimeOfDay(secs
, &nsecs
);
990 assert(nsecs
< NSEC_PER_SEC
);
991 *usecs
= nsecs
/ NSEC_PER_USEC
;
994 void PESetUTCTimeOfDay(clock_sec_t secs
, clock_usec_t usecs
)
996 assert(usecs
< USEC_PER_SEC
);
998 gIOPlatform
->setUTCTimeOfDay(secs
, usecs
* NSEC_PER_USEC
);
1003 void IOPlatformExpert::registerNVRAMController(IONVRAMController
* caller
)
1006 IORegistryEntry
* entry
;
1007 OSString
* string
= 0;
1010 entry
= IORegistryEntry::fromPath( "/efi/platform", gIODTPlane
);
1013 data
= OSDynamicCast( OSData
, entry
->getProperty( "system-id" ) );
1014 if ( data
&& data
->getLength( ) == 16 )
1017 uint8_t digest
[ SHA_DIGEST_LENGTH
];
1018 const uuid_t space
= { 0x2A, 0x06, 0x19, 0x90, 0xD3, 0x8D, 0x44, 0x40, 0xA1, 0x39, 0xC4, 0x97, 0x70, 0x37, 0x65, 0xAC };
1020 SHA1Init( &context
);
1021 SHA1Update( &context
, space
, sizeof( space
) );
1022 SHA1Update( &context
, data
->getBytesNoCopy( ), data
->getLength( ) );
1023 SHA1Final( digest
, &context
);
1025 digest
[ 6 ] = ( digest
[ 6 ] & 0x0F ) | 0x50;
1026 digest
[ 8 ] = ( digest
[ 8 ] & 0x3F ) | 0x80;
1028 uuid_unparse( digest
, uuid
);
1029 string
= OSString::withCString( uuid
);
1037 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
1040 data
= OSDynamicCast( OSData
, entry
->getProperty( "platform-uuid" ) );
1041 if ( data
&& data
->getLength( ) == sizeof( uuid_t
) )
1043 uuid_unparse( ( uint8_t * ) data
->getBytesNoCopy( ), uuid
);
1044 string
= OSString::withCString( uuid
);
1053 getProvider( )->setProperty( kIOPlatformUUIDKey
, string
);
1054 publishResource( kIOPlatformUUIDKey
, string
);
1059 publishResource("IONVRAM");
1062 IOReturn
IOPlatformExpert::callPlatformFunction(const OSSymbol
*functionName
,
1063 bool waitForFunction
,
1064 void *param1
, void *param2
,
1065 void *param3
, void *param4
)
1067 IOService
*service
, *_resources
;
1069 if (waitForFunction
) {
1070 _resources
= waitForService(resourceMatching(functionName
));
1072 _resources
= getResourceService();
1074 if (_resources
== 0) return kIOReturnUnsupported
;
1076 service
= OSDynamicCast(IOService
, _resources
->getProperty(functionName
));
1077 if (service
== 0) return kIOReturnUnsupported
;
1079 return service
->callPlatformFunction(functionName
, waitForFunction
,
1080 param1
, param2
, param3
, param4
);
1083 IOByteCount
IOPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1088 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1091 #define super IOPlatformExpert
1093 OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert
, IOPlatformExpert
)
1095 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 0);
1096 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 1);
1097 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 2);
1098 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 3);
1099 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 4);
1100 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 5);
1101 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 6);
1102 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 7);
1104 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1106 IOService
* IODTPlatformExpert::probe( IOService
* provider
,
1109 if( !super::probe( provider
, score
))
1112 // check machine types
1113 if( !provider
->compareNames( getProperty( gIONameMatchKey
) ))
1119 bool IODTPlatformExpert::configure( IOService
* provider
)
1121 if( !super::configure( provider
))
1124 processTopLevel( provider
);
1129 IOService
* IODTPlatformExpert::createNub( IORegistryEntry
* from
)
1133 nub
= new IOPlatformDevice
;
1135 if( !nub
->init( from
, gIODTPlane
)) {
1143 bool IODTPlatformExpert::createNubs( IOService
* parent
, OSIterator
* iter
)
1145 IORegistryEntry
* next
;
1150 while( (next
= (IORegistryEntry
*) iter
->getNextObject())) {
1152 if( 0 == (nub
= createNub( next
)))
1155 nub
->attach( parent
);
1156 nub
->registerService();
1164 void IODTPlatformExpert::processTopLevel( IORegistryEntry
* rootEntry
)
1167 IORegistryEntry
* next
;
1168 IORegistryEntry
* cpus
;
1169 IORegistryEntry
* options
;
1172 kids
= IODTFindMatchingEntries( rootEntry
, 0, deleteList() );
1174 while( (next
= (IORegistryEntry
*)kids
->getNextObject())) {
1175 next
->detachAll( gIODTPlane
);
1180 // Publish an IODTNVRAM class on /options.
1181 options
= rootEntry
->childFromPath("options", gIODTPlane
);
1183 dtNVRAM
= new IODTNVRAM
;
1185 if (!dtNVRAM
->init(options
, gIODTPlane
)) {
1189 dtNVRAM
->attach(this);
1190 dtNVRAM
->registerService();
1195 // Publish the cpus.
1196 cpus
= rootEntry
->childFromPath( "cpus", gIODTPlane
);
1198 createNubs( this, IODTFindMatchingEntries( cpus
, kIODTExclusive
, 0));
1200 // publish top level, minus excludeList
1201 createNubs( this, IODTFindMatchingEntries( rootEntry
, kIODTExclusive
, excludeList()));
1204 IOReturn
IODTPlatformExpert::getNubResources( IOService
* nub
)
1206 if( nub
->getDeviceMemory())
1207 return( kIOReturnSuccess
);
1209 IODTResolveAddressing( nub
, "reg", 0);
1211 return( kIOReturnSuccess
);
1214 bool IODTPlatformExpert::compareNubName( const IOService
* nub
,
1215 OSString
* name
, OSString
** matched
) const
1217 return( IODTCompareNubName( nub
, name
, matched
)
1218 || super::compareNubName( nub
, name
, matched
) );
1221 bool IODTPlatformExpert::getModelName( char * name
, int maxLength
)
1231 prop
= (OSData
*) getProvider()->getProperty( gIODTCompatibleKey
);
1233 str
= (const char *) prop
->getBytesNoCopy();
1235 if( 0 == strncmp( str
, "AAPL,", strlen( "AAPL," ) ))
1236 str
+= strlen( "AAPL," );
1239 while( (c
= *str
++)) {
1240 if( (c
== '/') || (c
== ' '))
1244 if( len
>= maxLength
)
1254 bool IODTPlatformExpert::getMachineName( char * name
, int maxLength
)
1260 prop
= (OSData
*) getProvider()->getProperty( gIODTModelKey
);
1264 strlcpy( name
, (const char *) prop
->getBytesNoCopy(), maxLength
);
1269 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1271 void IODTPlatformExpert::registerNVRAMController( IONVRAMController
* nvram
)
1273 if (dtNVRAM
) dtNVRAM
->registerNVRAMController(nvram
);
1275 super::registerNVRAMController(nvram
);
1278 int IODTPlatformExpert::haltRestart(unsigned int type
)
1280 if (dtNVRAM
) dtNVRAM
->sync();
1282 return super::haltRestart(type
);
1285 IOReturn
IODTPlatformExpert::readXPRAM(IOByteCount offset
, UInt8
* buffer
,
1288 if (dtNVRAM
) return dtNVRAM
->readXPRAM(offset
, buffer
, length
);
1289 else return kIOReturnNotReady
;
1292 IOReturn
IODTPlatformExpert::writeXPRAM(IOByteCount offset
, UInt8
* buffer
,
1295 if (dtNVRAM
) return dtNVRAM
->writeXPRAM(offset
, buffer
, length
);
1296 else return kIOReturnNotReady
;
1299 IOReturn
IODTPlatformExpert::readNVRAMProperty(
1300 IORegistryEntry
* entry
,
1301 const OSSymbol
** name
, OSData
** value
)
1303 if (dtNVRAM
) return dtNVRAM
->readNVRAMProperty(entry
, name
, value
);
1304 else return kIOReturnNotReady
;
1307 IOReturn
IODTPlatformExpert::writeNVRAMProperty(
1308 IORegistryEntry
* entry
,
1309 const OSSymbol
* name
, OSData
* value
)
1311 if (dtNVRAM
) return dtNVRAM
->writeNVRAMProperty(entry
, name
, value
);
1312 else return kIOReturnNotReady
;
1315 OSDictionary
*IODTPlatformExpert::getNVRAMPartitions(void)
1317 if (dtNVRAM
) return dtNVRAM
->getNVRAMPartitions();
1321 IOReturn
IODTPlatformExpert::readNVRAMPartition(const OSSymbol
* partitionID
,
1322 IOByteCount offset
, UInt8
* buffer
,
1325 if (dtNVRAM
) return dtNVRAM
->readNVRAMPartition(partitionID
, offset
,
1327 else return kIOReturnNotReady
;
1330 IOReturn
IODTPlatformExpert::writeNVRAMPartition(const OSSymbol
* partitionID
,
1331 IOByteCount offset
, UInt8
* buffer
,
1334 if (dtNVRAM
) return dtNVRAM
->writeNVRAMPartition(partitionID
, offset
,
1336 else return kIOReturnNotReady
;
1339 IOByteCount
IODTPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1341 IOByteCount lengthSaved
= 0;
1343 if (dtNVRAM
) lengthSaved
= dtNVRAM
->savePanicInfo(buffer
, length
);
1345 if (lengthSaved
== 0) lengthSaved
= super::savePanicInfo(buffer
, length
);
1350 OSString
* IODTPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
) {
1351 UInt8
* serialNumber
;
1352 unsigned int serialNumberSize
;
1353 unsigned short pos
= 0;
1357 if (myProperty
!= NULL
) {
1358 serialNumberSize
= myProperty
->getLength();
1359 serialNumber
= (UInt8
*)(myProperty
->getBytesNoCopy());
1360 temp
= (char*)serialNumber
;
1361 if (serialNumberSize
> 0) {
1362 // check to see if this is a CTO serial number...
1363 while (pos
< serialNumberSize
&& temp
[pos
] != '-') pos
++;
1365 if (pos
< serialNumberSize
) { // there was a hyphen, so it's a CTO serial number
1366 memcpy(SerialNo
, serialNumber
+ 12, 8);
1367 memcpy(&SerialNo
[8], serialNumber
, 3);
1369 memcpy(&SerialNo
[12], serialNumber
+ 3, 8);
1371 } else { // just a normal serial number
1372 memcpy(SerialNo
, serialNumber
+ 13, 8);
1373 memcpy(&SerialNo
[8], serialNumber
, 3);
1376 return OSString::withCString(SerialNo
);
1383 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1386 #define super IOService
1388 OSDefineMetaClassAndStructors(IOPlatformExpertDevice
, IOService
)
1390 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 0);
1391 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 1);
1392 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 2);
1393 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 3);
1395 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1397 bool IOPlatformExpertDevice::compareName( OSString
* name
,
1398 OSString
** matched
) const
1400 return( IODTCompareNubName( this, name
, matched
));
1404 IOPlatformExpertDevice::initWithArgs(
1405 void * dtTop
, void * p2
, void * p3
, void * p4
)
1407 IORegistryEntry
* dt
= 0;
1410 // dtTop may be zero on non- device tree systems
1411 if( dtTop
&& (dt
= IODeviceTreeAlloc( dtTop
)))
1412 ok
= super::init( dt
, gIODTPlane
);
1420 workLoop
= IOWorkLoop::workLoop();
1427 IOWorkLoop
*IOPlatformExpertDevice::getWorkLoop() const
1432 IOReturn
IOPlatformExpertDevice::setProperties( OSObject
* properties
)
1434 OSDictionary
* dictionary
;
1438 status
= super::setProperties( properties
);
1439 if ( status
!= kIOReturnUnsupported
) return status
;
1441 status
= IOUserClient::clientHasPrivilege( current_task( ), kIOClientPrivilegeAdministrator
);
1442 if ( status
!= kIOReturnSuccess
) return status
;
1444 dictionary
= OSDynamicCast( OSDictionary
, properties
);
1445 if ( dictionary
== 0 ) return kIOReturnBadArgument
;
1447 object
= dictionary
->getObject( kIOPlatformUUIDKey
);
1450 IORegistryEntry
* entry
;
1454 string
= ( OSString
* ) getProperty( kIOPlatformUUIDKey
);
1455 if ( string
) return kIOReturnNotPermitted
;
1457 string
= OSDynamicCast( OSString
, object
);
1458 if ( string
== 0 ) return kIOReturnBadArgument
;
1460 status
= uuid_parse( string
->getCStringNoCopy( ), uuid
);
1461 if ( status
!= 0 ) return kIOReturnBadArgument
;
1463 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
1466 entry
->setProperty( "platform-uuid", uuid
, sizeof( uuid_t
) );
1470 setProperty( kIOPlatformUUIDKey
, string
);
1471 publishResource( kIOPlatformUUIDKey
, string
);
1473 return kIOReturnSuccess
;
1476 return kIOReturnUnsupported
;
1479 void IOPlatformExpertDevice::free()
1482 workLoop
->release();
1485 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1488 #define super IOService
1490 OSDefineMetaClassAndStructors(IOPlatformDevice
, IOService
)
1492 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 0);
1493 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 1);
1494 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 2);
1495 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 3);
1497 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1499 bool IOPlatformDevice::compareName( OSString
* name
,
1500 OSString
** matched
) const
1502 return( ((IOPlatformExpert
*)getProvider())->
1503 compareNubName( this, name
, matched
));
1506 IOService
* IOPlatformDevice::matchLocation( IOService
* /* client */ )
1511 IOReturn
IOPlatformDevice::getResources( void )
1513 return( ((IOPlatformExpert
*)getProvider())->getNubResources( this ));
1516 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1518 /*********************************************************************
1519 * IOPanicPlatform class
1521 * If no legitimate IOPlatformDevice matches, this one does and panics
1522 * the kernel with a suitable message.
1523 *********************************************************************/
1525 class IOPanicPlatform
: IOPlatformExpert
{
1526 OSDeclareDefaultStructors(IOPanicPlatform
);
1529 bool start(IOService
* provider
);
1533 OSDefineMetaClassAndStructors(IOPanicPlatform
, IOPlatformExpert
);
1536 bool IOPanicPlatform::start(IOService
* provider
) {
1537 const char * platform_name
= "(unknown platform name)";
1539 if (provider
) platform_name
= provider
->getName();
1541 panic("Unable to find driver for this platform: \"%s\".\n",