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 // Do an initial sync to flush as much panic data as possible,
826 // in case we have a problem in one of the platorm panic handlers.
827 // After running the platform handlers, do a final sync w/
828 // platform hardware quiesced for the panic.
829 PE_sync_panic_buffers();
830 IOCPURunPlatformPanicActions(type
);
831 PE_sync_panic_buffers();
834 if (gIOPlatform
) return gIOPlatform
->haltRestart(type
);
838 UInt32
PESavePanicInfo(UInt8
*buffer
, UInt32 length
)
840 if (gIOPlatform
!= 0) return gIOPlatform
->savePanicInfo(buffer
, length
);
846 inline static int init_gIOOptionsEntry(void)
848 IORegistryEntry
*entry
;
850 volatile void **options
;
856 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
860 nvram_entry
= (void *) OSDynamicCast(IODTNVRAM
, entry
);
864 options
= (volatile void **) &gIOOptionsEntry
;
865 if (!OSCompareAndSwapPtr(NULL
, nvram_entry
, options
)) {
878 /* pass in a NULL value if you just want to figure out the len */
879 boolean_t
PEReadNVRAMProperty(const char *symbol
, void *value
,
889 if (init_gIOOptionsEntry() < 0)
895 obj
= gIOOptionsEntry
->getProperty(symbol
);
899 /* convert to data */
900 data
= OSDynamicCast(OSData
, obj
);
904 *len
= data
->getLength();
905 vlen
= min(vlen
, *len
);
907 memcpy((void *) value
, data
->getBytesNoCopy(), vlen
);
916 PEWriteNVRAMBooleanProperty(const char *symbol
, boolean_t value
)
918 const OSSymbol
*sym
= NULL
;
919 OSBoolean
*data
= NULL
;
922 if (symbol
== NULL
) {
926 if (init_gIOOptionsEntry() < 0) {
930 if ((sym
= OSSymbol::withCStringNoCopy(symbol
)) == NULL
) {
934 data
= value
? kOSBooleanTrue
: kOSBooleanFalse
;
935 ret
= gIOOptionsEntry
->setProperty(sym
, data
);
939 /* success, force the NVRAM to flush writes */
941 gIOOptionsEntry
->sync();
948 boolean_t
PEWriteNVRAMProperty(const char *symbol
, const void *value
,
949 const unsigned int len
)
955 if (!symbol
|| !value
|| !len
)
958 if (init_gIOOptionsEntry() < 0)
961 sym
= OSSymbol::withCStringNoCopy(symbol
);
965 data
= OSData::withBytes((void *) value
, len
);
969 ret
= gIOOptionsEntry
->setProperty(sym
, data
);
976 gIOOptionsEntry
->sync();
985 boolean_t
PERemoveNVRAMProperty(const char *symbol
)
992 if (init_gIOOptionsEntry() < 0)
995 sym
= OSSymbol::withCStringNoCopy(symbol
);
999 gIOOptionsEntry
->removeProperty(sym
);
1003 gIOOptionsEntry
->sync();
1011 long PEGetGMTTimeOfDay(void)
1016 PEGetUTCTimeOfDay(&secs
, &usecs
);
1020 void PESetGMTTimeOfDay(long secs
)
1022 PESetUTCTimeOfDay(secs
, 0);
1025 void PEGetUTCTimeOfDay(clock_sec_t
* secs
, clock_usec_t
* usecs
)
1027 clock_nsec_t nsecs
= 0;
1031 gIOPlatform
->getUTCTimeOfDay(secs
, &nsecs
);
1033 assert(nsecs
< NSEC_PER_SEC
);
1034 *usecs
= nsecs
/ NSEC_PER_USEC
;
1037 void PESetUTCTimeOfDay(clock_sec_t secs
, clock_usec_t usecs
)
1039 assert(usecs
< USEC_PER_SEC
);
1041 gIOPlatform
->setUTCTimeOfDay(secs
, usecs
* NSEC_PER_USEC
);
1046 void IOPlatformExpert::registerNVRAMController(IONVRAMController
* caller
)
1049 IORegistryEntry
* entry
;
1050 OSString
* string
= 0;
1053 entry
= IORegistryEntry::fromPath( "/efi/platform", gIODTPlane
);
1056 data
= OSDynamicCast( OSData
, entry
->getProperty( "system-id" ) );
1057 if ( data
&& data
->getLength( ) == 16 )
1060 uint8_t digest
[ SHA_DIGEST_LENGTH
];
1061 const uuid_t space
= { 0x2A, 0x06, 0x19, 0x90, 0xD3, 0x8D, 0x44, 0x40, 0xA1, 0x39, 0xC4, 0x97, 0x70, 0x37, 0x65, 0xAC };
1063 SHA1Init( &context
);
1064 SHA1Update( &context
, space
, sizeof( space
) );
1065 SHA1Update( &context
, data
->getBytesNoCopy( ), data
->getLength( ) );
1066 SHA1Final( digest
, &context
);
1068 digest
[ 6 ] = ( digest
[ 6 ] & 0x0F ) | 0x50;
1069 digest
[ 8 ] = ( digest
[ 8 ] & 0x3F ) | 0x80;
1071 uuid_unparse( digest
, uuid
);
1072 string
= OSString::withCString( uuid
);
1080 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
1083 data
= OSDynamicCast( OSData
, entry
->getProperty( "platform-uuid" ) );
1084 if ( data
&& data
->getLength( ) == sizeof( uuid_t
) )
1086 uuid_unparse( ( uint8_t * ) data
->getBytesNoCopy( ), uuid
);
1087 string
= OSString::withCString( uuid
);
1096 getProvider( )->setProperty( kIOPlatformUUIDKey
, string
);
1097 publishResource( kIOPlatformUUIDKey
, string
);
1102 publishResource("IONVRAM");
1105 IOReturn
IOPlatformExpert::callPlatformFunction(const OSSymbol
*functionName
,
1106 bool waitForFunction
,
1107 void *param1
, void *param2
,
1108 void *param3
, void *param4
)
1110 IOService
*service
, *_resources
;
1112 if (waitForFunction
) {
1113 _resources
= waitForService(resourceMatching(functionName
));
1115 _resources
= getResourceService();
1117 if (_resources
== 0) return kIOReturnUnsupported
;
1119 service
= OSDynamicCast(IOService
, _resources
->getProperty(functionName
));
1120 if (service
== 0) return kIOReturnUnsupported
;
1122 return service
->callPlatformFunction(functionName
, waitForFunction
,
1123 param1
, param2
, param3
, param4
);
1126 IOByteCount
IOPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1131 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1134 #define super IOPlatformExpert
1136 OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert
, IOPlatformExpert
)
1138 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 0);
1139 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 1);
1140 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 2);
1141 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 3);
1142 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 4);
1143 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 5);
1144 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 6);
1145 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 7);
1147 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1149 IOService
* IODTPlatformExpert::probe( IOService
* provider
,
1152 if( !super::probe( provider
, score
))
1155 // check machine types
1156 if( !provider
->compareNames( getProperty( gIONameMatchKey
) ))
1162 bool IODTPlatformExpert::configure( IOService
* provider
)
1164 if( !super::configure( provider
))
1167 processTopLevel( provider
);
1172 IOService
* IODTPlatformExpert::createNub( IORegistryEntry
* from
)
1176 nub
= new IOPlatformDevice
;
1178 if( !nub
->init( from
, gIODTPlane
)) {
1186 bool IODTPlatformExpert::createNubs( IOService
* parent
, OSIterator
* iter
)
1188 IORegistryEntry
* next
;
1193 while( (next
= (IORegistryEntry
*) iter
->getNextObject())) {
1195 if( 0 == (nub
= createNub( next
)))
1198 nub
->attach( parent
);
1199 nub
->registerService();
1207 void IODTPlatformExpert::processTopLevel( IORegistryEntry
* rootEntry
)
1210 IORegistryEntry
* next
;
1211 IORegistryEntry
* cpus
;
1212 IORegistryEntry
* options
;
1215 kids
= IODTFindMatchingEntries( rootEntry
, 0, deleteList() );
1217 while( (next
= (IORegistryEntry
*)kids
->getNextObject())) {
1218 next
->detachAll( gIODTPlane
);
1223 // Publish an IODTNVRAM class on /options.
1224 options
= rootEntry
->childFromPath("options", gIODTPlane
);
1226 dtNVRAM
= new IODTNVRAM
;
1228 if (!dtNVRAM
->init(options
, gIODTPlane
)) {
1232 dtNVRAM
->attach(this);
1233 dtNVRAM
->registerService();
1239 // Publish the cpus.
1240 cpus
= rootEntry
->childFromPath( "cpus", gIODTPlane
);
1243 createNubs( this, IODTFindMatchingEntries( cpus
, kIODTExclusive
, 0));
1247 // publish top level, minus excludeList
1248 createNubs( this, IODTFindMatchingEntries( rootEntry
, kIODTExclusive
, excludeList()));
1251 IOReturn
IODTPlatformExpert::getNubResources( IOService
* nub
)
1253 if( nub
->getDeviceMemory())
1254 return( kIOReturnSuccess
);
1256 IODTResolveAddressing( nub
, "reg", 0);
1258 return( kIOReturnSuccess
);
1261 bool IODTPlatformExpert::compareNubName( const IOService
* nub
,
1262 OSString
* name
, OSString
** matched
) const
1264 return( IODTCompareNubName( nub
, name
, matched
)
1265 || super::compareNubName( nub
, name
, matched
) );
1268 bool IODTPlatformExpert::getModelName( char * name
, int maxLength
)
1278 prop
= (OSData
*) getProvider()->getProperty( gIODTCompatibleKey
);
1280 str
= (const char *) prop
->getBytesNoCopy();
1282 if( 0 == strncmp( str
, "AAPL,", strlen( "AAPL," ) ))
1283 str
+= strlen( "AAPL," );
1286 while( (c
= *str
++)) {
1287 if( (c
== '/') || (c
== ' '))
1291 if( len
>= maxLength
)
1301 bool IODTPlatformExpert::getMachineName( char * name
, int maxLength
)
1307 prop
= (OSData
*) getProvider()->getProperty( gIODTModelKey
);
1311 strlcpy( name
, (const char *) prop
->getBytesNoCopy(), maxLength
);
1316 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1318 void IODTPlatformExpert::registerNVRAMController( IONVRAMController
* nvram
)
1320 if (dtNVRAM
) dtNVRAM
->registerNVRAMController(nvram
);
1322 super::registerNVRAMController(nvram
);
1325 int IODTPlatformExpert::haltRestart(unsigned int type
)
1327 if (dtNVRAM
) dtNVRAM
->sync();
1329 return super::haltRestart(type
);
1332 IOReturn
IODTPlatformExpert::readXPRAM(IOByteCount offset
, UInt8
* buffer
,
1335 if (dtNVRAM
) return dtNVRAM
->readXPRAM(offset
, buffer
, length
);
1336 else return kIOReturnNotReady
;
1339 IOReturn
IODTPlatformExpert::writeXPRAM(IOByteCount offset
, UInt8
* buffer
,
1342 if (dtNVRAM
) return dtNVRAM
->writeXPRAM(offset
, buffer
, length
);
1343 else return kIOReturnNotReady
;
1346 IOReturn
IODTPlatformExpert::readNVRAMProperty(
1347 IORegistryEntry
* entry
,
1348 const OSSymbol
** name
, OSData
** value
)
1350 if (dtNVRAM
) return dtNVRAM
->readNVRAMProperty(entry
, name
, value
);
1351 else return kIOReturnNotReady
;
1354 IOReturn
IODTPlatformExpert::writeNVRAMProperty(
1355 IORegistryEntry
* entry
,
1356 const OSSymbol
* name
, OSData
* value
)
1358 if (dtNVRAM
) return dtNVRAM
->writeNVRAMProperty(entry
, name
, value
);
1359 else return kIOReturnNotReady
;
1362 OSDictionary
*IODTPlatformExpert::getNVRAMPartitions(void)
1364 if (dtNVRAM
) return dtNVRAM
->getNVRAMPartitions();
1368 IOReturn
IODTPlatformExpert::readNVRAMPartition(const OSSymbol
* partitionID
,
1369 IOByteCount offset
, UInt8
* buffer
,
1372 if (dtNVRAM
) return dtNVRAM
->readNVRAMPartition(partitionID
, offset
,
1374 else return kIOReturnNotReady
;
1377 IOReturn
IODTPlatformExpert::writeNVRAMPartition(const OSSymbol
* partitionID
,
1378 IOByteCount offset
, UInt8
* buffer
,
1381 if (dtNVRAM
) return dtNVRAM
->writeNVRAMPartition(partitionID
, offset
,
1383 else return kIOReturnNotReady
;
1386 IOByteCount
IODTPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1388 IOByteCount lengthSaved
= 0;
1390 if (dtNVRAM
) lengthSaved
= dtNVRAM
->savePanicInfo(buffer
, length
);
1392 if (lengthSaved
== 0) lengthSaved
= super::savePanicInfo(buffer
, length
);
1397 OSString
* IODTPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
) {
1398 UInt8
* serialNumber
;
1399 unsigned int serialNumberSize
;
1400 unsigned short pos
= 0;
1404 if (myProperty
!= NULL
) {
1405 serialNumberSize
= myProperty
->getLength();
1406 serialNumber
= (UInt8
*)(myProperty
->getBytesNoCopy());
1407 temp
= (char*)serialNumber
;
1408 if (serialNumberSize
> 0) {
1409 // check to see if this is a CTO serial number...
1410 while (pos
< serialNumberSize
&& temp
[pos
] != '-') pos
++;
1412 if (pos
< serialNumberSize
) { // there was a hyphen, so it's a CTO serial number
1413 memcpy(SerialNo
, serialNumber
+ 12, 8);
1414 memcpy(&SerialNo
[8], serialNumber
, 3);
1416 memcpy(&SerialNo
[12], serialNumber
+ 3, 8);
1418 } else { // just a normal serial number
1419 memcpy(SerialNo
, serialNumber
+ 13, 8);
1420 memcpy(&SerialNo
[8], serialNumber
, 3);
1423 return OSString::withCString(SerialNo
);
1430 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1433 #define super IOService
1435 OSDefineMetaClassAndStructors(IOPlatformExpertDevice
, IOService
)
1437 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 0);
1438 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 1);
1439 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 2);
1440 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 3);
1442 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1444 bool IOPlatformExpertDevice::compareName( OSString
* name
,
1445 OSString
** matched
) const
1447 return( IODTCompareNubName( this, name
, matched
));
1451 IOPlatformExpertDevice::initWithArgs(
1452 void * dtTop
, void * p2
, void * p3
, void * p4
)
1454 IORegistryEntry
* dt
= 0;
1457 // dtTop may be zero on non- device tree systems
1458 if( dtTop
&& (dt
= IODeviceTreeAlloc( dtTop
)))
1459 ok
= super::init( dt
, gIODTPlane
);
1467 workLoop
= IOWorkLoop::workLoop();
1474 IOWorkLoop
*IOPlatformExpertDevice::getWorkLoop() const
1479 IOReturn
IOPlatformExpertDevice::setProperties( OSObject
* properties
)
1481 OSDictionary
* dictionary
;
1485 status
= super::setProperties( properties
);
1486 if ( status
!= kIOReturnUnsupported
) return status
;
1488 status
= IOUserClient::clientHasPrivilege( current_task( ), kIOClientPrivilegeAdministrator
);
1489 if ( status
!= kIOReturnSuccess
) return status
;
1491 dictionary
= OSDynamicCast( OSDictionary
, properties
);
1492 if ( dictionary
== 0 ) return kIOReturnBadArgument
;
1494 object
= dictionary
->getObject( kIOPlatformUUIDKey
);
1497 IORegistryEntry
* entry
;
1501 string
= ( OSString
* ) getProperty( kIOPlatformUUIDKey
);
1502 if ( string
) return kIOReturnNotPermitted
;
1504 string
= OSDynamicCast( OSString
, object
);
1505 if ( string
== 0 ) return kIOReturnBadArgument
;
1507 status
= uuid_parse( string
->getCStringNoCopy( ), uuid
);
1508 if ( status
!= 0 ) return kIOReturnBadArgument
;
1510 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
1513 entry
->setProperty( "platform-uuid", uuid
, sizeof( uuid_t
) );
1517 setProperty( kIOPlatformUUIDKey
, string
);
1518 publishResource( kIOPlatformUUIDKey
, string
);
1520 return kIOReturnSuccess
;
1523 return kIOReturnUnsupported
;
1526 IOReturn
IOPlatformExpertDevice::newUserClient( task_t owningTask
, void * securityID
,
1527 UInt32 type
, OSDictionary
* properties
,
1528 IOUserClient
** handler
)
1530 IOReturn err
= kIOReturnSuccess
;
1531 IOUserClient
* newConnect
= 0;
1532 IOUserClient
* theConnect
= 0;
1536 case kIOKitDiagnosticsClientType
:
1537 newConnect
= IOKitDiagnosticsClient::withTask(owningTask
);
1538 if (!newConnect
) err
= kIOReturnNotPermitted
;
1541 err
= kIOReturnBadArgument
;
1546 if ((false == newConnect
->attach(this))
1547 || (false == newConnect
->start(this)))
1549 newConnect
->detach( this );
1550 newConnect
->release();
1551 err
= kIOReturnNotPermitted
;
1554 theConnect
= newConnect
;
1557 *handler
= theConnect
;
1561 void IOPlatformExpertDevice::free()
1564 workLoop
->release();
1567 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1570 #define super IOService
1572 OSDefineMetaClassAndStructors(IOPlatformDevice
, IOService
)
1574 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 0);
1575 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 1);
1576 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 2);
1577 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 3);
1579 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1581 bool IOPlatformDevice::compareName( OSString
* name
,
1582 OSString
** matched
) const
1584 return( ((IOPlatformExpert
*)getProvider())->
1585 compareNubName( this, name
, matched
));
1588 IOService
* IOPlatformDevice::matchLocation( IOService
* /* client */ )
1593 IOReturn
IOPlatformDevice::getResources( void )
1595 return( ((IOPlatformExpert
*)getProvider())->getNubResources( this ));
1598 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1600 /*********************************************************************
1601 * IOPanicPlatform class
1603 * If no legitimate IOPlatformDevice matches, this one does and panics
1604 * the kernel with a suitable message.
1605 *********************************************************************/
1607 class IOPanicPlatform
: IOPlatformExpert
{
1608 OSDeclareDefaultStructors(IOPanicPlatform
);
1611 bool start(IOService
* provider
) APPLE_KEXT_OVERRIDE
;
1615 OSDefineMetaClassAndStructors(IOPanicPlatform
, IOPlatformExpert
);
1618 bool IOPanicPlatform::start(IOService
* provider
) {
1619 const char * platform_name
= "(unknown platform name)";
1621 if (provider
) platform_name
= provider
->getName();
1623 panic("Unable to find driver for this platform: \"%s\".\n",