2 * Copyright (c) 1998-2010 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);
66 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 1);
67 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 2);
68 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 3);
69 OSMetaClassDefineReservedUnused(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
);
109 // Register the presence or lack thereof a system
110 // PCI address mapper with the IOMapper class
111 IOMapper::setMapperRequired(0 != getProperty(kIOPlatformMapperPresentKey
));
113 gIOInterruptControllers
= OSDictionary::withCapacity(1);
114 gIOInterruptControllersLock
= IOLockAlloc();
116 // Correct the bus frequency in the device tree.
117 busFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.bus_clock_rate_hz
, 4);
118 provider
->setProperty("clock-frequency", busFrequency
);
119 busFrequency
->release();
121 gPlatformInterruptControllerName
= (OSSymbol
*)OSSymbol::withCStringNoCopy("IOPlatformInterruptController");
123 physicalRanges
= IORangeAllocator::withRange(0xffffffff, 1, 16,
124 IORangeAllocator::kLocking
);
125 assert(physicalRanges
);
126 setProperty("Platform Memory Ranges", physicalRanges
);
131 PMInstantiatePowerDomains();
133 // Parse the serial-number data and publish a user-readable string
134 OSData
* mydata
= (OSData
*) (provider
->getProperty("serial-number"));
135 if (mydata
!= NULL
) {
136 OSString
*serNoString
= createSystemSerialNumberString(mydata
);
137 if (serNoString
!= NULL
) {
138 provider
->setProperty(kIOPlatformSerialNumberKey
, serNoString
);
139 serNoString
->release();
143 return( configure(provider
) );
146 bool IOPlatformExpert::configure( IOService
* provider
)
152 topLevel
= OSDynamicCast( OSSet
, getProperty("top-level"));
155 while( (dict
= OSDynamicCast( OSDictionary
,
156 topLevel
->getAnyObject()))) {
158 topLevel
->removeObject( dict
);
159 nub
= createNub( dict
);
164 nub
->registerService();
171 IOService
* IOPlatformExpert::createNub( OSDictionary
* from
)
175 nub
= new IOPlatformDevice
;
177 if( !nub
->init( from
)) {
185 bool IOPlatformExpert::compareNubName( const IOService
* nub
,
186 OSString
* name
, OSString
** matched
) const
188 return( nub
->IORegistryEntry::compareName( name
, matched
));
191 IOReturn
IOPlatformExpert::getNubResources( IOService
* nub
)
193 return( kIOReturnSuccess
);
196 long IOPlatformExpert::getBootROMType(void)
198 return _peBootROMType
;
201 long IOPlatformExpert::getChipSetType(void)
203 return _peChipSetType
;
206 long IOPlatformExpert::getMachineType(void)
208 return _peMachineType
;
211 void IOPlatformExpert::setBootROMType(long peBootROMType
)
213 _peBootROMType
= peBootROMType
;
216 void IOPlatformExpert::setChipSetType(long peChipSetType
)
218 _peChipSetType
= peChipSetType
;
221 void IOPlatformExpert::setMachineType(long peMachineType
)
223 _peMachineType
= peMachineType
;
226 bool IOPlatformExpert::getMachineName( char * /*name*/, int /*maxLength*/)
231 bool IOPlatformExpert::getModelName( char * /*name*/, int /*maxLength*/)
236 OSString
* IOPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
)
241 IORangeAllocator
* IOPlatformExpert::getPhysicalRangeAllocator(void)
243 return(OSDynamicCast(IORangeAllocator
,
244 getProperty("Platform Memory Ranges")));
247 int (*PE_halt_restart
)(unsigned int type
) = 0;
249 int IOPlatformExpert::haltRestart(unsigned int type
)
251 if (type
== kPEPanicSync
) return 0;
253 if (type
== kPEHangCPU
) while (true) {}
255 if (type
== kPEUPSDelayHaltCPU
) {
256 // RestartOnPowerLoss feature was turned on, proceed with shutdown.
260 // On ARM kPEPanicRestartCPU is supported in the drivers
261 if (type
== kPEPanicRestartCPU
)
262 type
= kPERestartCPU
;
264 if (PE_halt_restart
) return (*PE_halt_restart
)(type
);
268 void IOPlatformExpert::sleepKernel(void)
274 intState
= ml_set_interrupts_enabled(false);
276 for (cnt
= 0; cnt
< 10000; cnt
++) {
280 ml_set_interrupts_enabled(intState
);
282 // PE_initialize_console(0, kPEDisableScreen);
286 // PE_initialize_console(0, kPEEnableScreen);
290 long IOPlatformExpert::getGMTTimeOfDay(void)
295 void IOPlatformExpert::setGMTTimeOfDay(long secs
)
300 IOReturn
IOPlatformExpert::getConsoleInfo( PE_Video
* consoleInfo
)
302 return( PE_current_console( consoleInfo
));
305 IOReturn
IOPlatformExpert::setConsoleInfo( PE_Video
* consoleInfo
,
308 return( PE_initialize_console( consoleInfo
, op
));
311 IOReturn
IOPlatformExpert::registerInterruptController(OSSymbol
*name
, IOInterruptController
*interruptController
)
313 IOLockLock(gIOInterruptControllersLock
);
315 gIOInterruptControllers
->setObject(name
, interruptController
);
317 IOLockWakeup(gIOInterruptControllersLock
,
318 gIOInterruptControllers
, /* one-thread */ false);
320 IOLockUnlock(gIOInterruptControllersLock
);
322 return kIOReturnSuccess
;
325 IOInterruptController
*IOPlatformExpert::lookUpInterruptController(OSSymbol
*name
)
329 IOLockLock(gIOInterruptControllersLock
);
332 object
= gIOInterruptControllers
->getObject(name
);
337 IOLockSleep(gIOInterruptControllersLock
,
338 gIOInterruptControllers
, THREAD_UNINT
);
341 IOLockUnlock(gIOInterruptControllersLock
);
342 return OSDynamicCast(IOInterruptController
, object
);
346 void IOPlatformExpert::setCPUInterruptProperties(IOService
*service
)
348 IOCPUInterruptController
*controller
;
350 controller
= OSDynamicCast(IOCPUInterruptController
, waitForService(serviceMatching("IOCPUInterruptController")));
351 if (controller
) controller
->setCPUInterruptProperties(service
);
354 bool IOPlatformExpert::atInterruptLevel(void)
356 return ml_at_interrupt_context();
359 bool IOPlatformExpert::platformAdjustService(IOService */
*service*/
)
365 //*********************************************************************************
368 //*********************************************************************************
370 void IOPlatformExpert::
371 PMLog(const char *who
, unsigned long event
,
372 unsigned long param1
, unsigned long param2
)
374 UInt32 debugFlags
= gIOKitDebug
;
375 UInt32 traceFlags
= gIOKitTrace
;
379 if (debugFlags
& kIOLogPower
) {
383 clock_get_system_microtime(&nows
, &nowus
);
384 nowus
+= (nows
% 1000) * 1000000;
386 kprintf("pm%u %p %.30s %d %lx %lx\n",
387 nowus
, current_thread(), who
, // Identity
388 (int) event
, (long) param1
, (long) param2
); // Args
390 if (traceFlags
& kIOTracePowerMgmt
) {
391 static const UInt32 sStartStopBitField
[] =
392 { 0x00000000, 0x00000040 }; // Only Program Hardware so far
394 // Arcane formula from Hacker's Delight by Warren
395 // abs(x) = ((int) x >> 31) ^ (x + ((int) x >> 31))
396 UInt32 sgnevent
= ((long) event
>> 31);
397 UInt32 absevent
= sgnevent
^ (event
+ sgnevent
);
398 UInt32 code
= IODBG_POWER(absevent
);
400 UInt32 bit
= 1 << (absevent
& 0x1f);
401 if (absevent
< sizeof(sStartStopBitField
) * 8
402 && (sStartStopBitField
[absevent
>> 5] & bit
) ) {
403 // Or in the START or END bits, Start = 1 & END = 2
404 // If sgnevent == 0 then START - 0 => START
405 // else if sgnevent == -1 then START - -1 => END
406 code
|= DBG_FUNC_START
- sgnevent
;
409 // Get first 8 characters of the name
410 while ( i
< sizeof(uintptr_t) && who
[i
] != 0)
411 { ((char *)&name
)[sizeof(uintptr_t)-i
-1]=who
[i
]; i
++; }
412 // Record the timestamp.
413 IOTimeStampConstant(code
, name
, event
, param1
, param2
);
419 //*********************************************************************************
420 // PMInstantiatePowerDomains
422 // In this vanilla implementation, a Root Power Domain is instantiated.
423 // All other objects which register will be children of this Root.
424 // Where this is inappropriate, PMInstantiatePowerDomains is overridden
425 // in a platform-specific subclass.
426 //*********************************************************************************
428 void IOPlatformExpert::PMInstantiatePowerDomains ( void )
430 root
= new IOPMrootDomain
;
437 //*********************************************************************************
440 // In this vanilla implementation, all callers are made children of the root power domain.
441 // Where this is inappropriate, PMRegisterDevice is overridden in a platform-specific subclass.
442 //*********************************************************************************
444 void IOPlatformExpert::PMRegisterDevice(IOService
* theNub
, IOService
* theDevice
)
446 root
->addPowerChild ( theDevice
);
449 //*********************************************************************************
452 //*********************************************************************************
454 bool IOPlatformExpert::hasPMFeature (unsigned long featureMask
)
456 return ((_pePMFeatures
& featureMask
) != 0);
459 //*********************************************************************************
462 //*********************************************************************************
464 bool IOPlatformExpert::hasPrivPMFeature (unsigned long privFeatureMask
)
466 return ((_pePrivPMFeatures
& privFeatureMask
) != 0);
469 //*********************************************************************************
470 // numBatteriesSupported
472 //*********************************************************************************
474 int IOPlatformExpert::numBatteriesSupported (void)
476 return (_peNumBatteriesSupported
);
479 //*********************************************************************************
482 // This method is called by the instantiated sublass of the platform expert to
483 // determine how a device should be inserted into the Power Domain. The subclass
484 // provides an XML power tree description against which a device is matched based
485 // on class and provider. If a match is found this routine returns true in addition
486 // to flagging the description tree at the appropriate node that a device has been
487 // registered for the given service.
488 //*********************************************************************************
490 bool IOPlatformExpert::CheckSubTree (OSArray
* inSubTree
, IOService
* theNub
, IOService
* theDevice
, OSDictionary
* theParent
)
493 unsigned int numPowerTreeNodes
;
494 OSDictionary
* entry
;
495 OSDictionary
* matchingDictionary
;
496 OSDictionary
* providerDictionary
;
497 OSDictionary
* deviceDictionary
;
498 OSDictionary
* nubDictionary
;
500 bool nodeFound
= false;
501 bool continueSearch
= false;
502 bool deviceMatch
= false;
503 bool providerMatch
= false;
504 bool multiParentMatch
= false;
506 if ( (NULL
== theDevice
) || (NULL
== inSubTree
) )
509 numPowerTreeNodes
= inSubTree
->getCount ();
511 // iterate through the power tree to find a home for this device
513 for ( i
= 0; i
< numPowerTreeNodes
; i
++ ) {
515 entry
= (OSDictionary
*) inSubTree
->getObject (i
);
517 matchingDictionary
= (OSDictionary
*) entry
->getObject ("device");
518 providerDictionary
= (OSDictionary
*) entry
->getObject ("provider");
520 deviceMatch
= true; // if no matching dictionary, this is not a criteria and so must match
521 if ( matchingDictionary
) {
523 if ( NULL
!= (deviceDictionary
= theDevice
->dictionaryWithProperties ())) {
524 deviceMatch
= deviceDictionary
->isEqualTo ( matchingDictionary
, matchingDictionary
);
525 deviceDictionary
->release ();
529 providerMatch
= true; // we indicate a match if there is no nub or provider
530 if ( theNub
&& providerDictionary
) {
531 providerMatch
= false;
532 if ( NULL
!= (nubDictionary
= theNub
->dictionaryWithProperties ()) ) {
533 providerMatch
= nubDictionary
->isEqualTo ( providerDictionary
, providerDictionary
);
534 nubDictionary
->release ();
538 multiParentMatch
= true; // again we indicate a match if there is no multi-parent node
539 if (deviceMatch
&& providerMatch
) {
540 if (NULL
!= multipleParentKeyValue
) {
541 OSNumber
* aNumber
= (OSNumber
*) entry
->getObject ("multiple-parent");
542 multiParentMatch
= (NULL
!= aNumber
) ? multipleParentKeyValue
->isEqualTo (aNumber
) : false;
546 nodeFound
= (deviceMatch
&& providerMatch
&& multiParentMatch
);
548 // if the power tree specifies a provider dictionary but theNub is
549 // NULL then we cannot match with this entry.
551 if ( theNub
== NULL
&& providerDictionary
!= NULL
)
554 // if this node is THE ONE...then register the device
557 if (RegisterServiceInTree (theDevice
, entry
, theParent
, theNub
) ) {
559 if ( kIOLogPower
& gIOKitDebug
)
560 IOLog ("PMRegisterDevice/CheckSubTree - service registered!\n");
562 numInstancesRegistered
++;
564 // determine if we need to search for additional nodes for this item
565 multipleParentKeyValue
= (OSNumber
*) entry
->getObject ("multiple-parent");
571 continueSearch
= ( (false == nodeFound
) || (NULL
!= multipleParentKeyValue
) );
573 if ( continueSearch
&& (NULL
!= (children
= (OSArray
*) entry
->getObject ("children"))) ) {
574 nodeFound
= CheckSubTree ( children
, theNub
, theDevice
, entry
);
575 continueSearch
= ( (false == nodeFound
) || (NULL
!= multipleParentKeyValue
) );
578 if ( false == continueSearch
)
582 return ( nodeFound
);
585 //*********************************************************************************
586 // RegisterServiceInTree
588 // Register a device at the specified node of our power tree.
589 //*********************************************************************************
591 bool IOPlatformExpert::RegisterServiceInTree (IOService
* theService
, OSDictionary
* theTreeNode
, OSDictionary
* theTreeParentNode
, IOService
* theProvider
)
593 IOService
* aService
;
594 bool registered
= false;
596 unsigned int numChildren
;
597 OSDictionary
* child
;
599 // make sure someone is not already registered here
601 if ( NULL
== theTreeNode
->getObject ("service") ) {
603 if ( theTreeNode
->setObject ("service", OSDynamicCast ( OSObject
, theService
)) ) {
605 // 1. CHILDREN ------------------
607 // we registered the node in the tree...now if the node has children
608 // registered we must tell this service to add them.
610 if ( NULL
!= (children
= (OSArray
*) theTreeNode
->getObject ("children")) ) {
611 numChildren
= children
->getCount ();
612 for ( unsigned int i
= 0; i
< numChildren
; i
++ ) {
613 if ( NULL
!= (child
= (OSDictionary
*) children
->getObject (i
)) ) {
614 if ( NULL
!= (aService
= (IOService
*) child
->getObject ("service")) )
615 theService
->addPowerChild (aService
);
620 // 2. PARENT --------------------
622 // also we must notify the parent of this node (if a registered service
623 // exists there) of a new child.
625 if ( theTreeParentNode
) {
626 if ( NULL
!= (aService
= (IOService
*) theTreeParentNode
->getObject ("service")) )
627 if (aService
!= theProvider
)
628 aService
->addPowerChild (theService
);
638 //*********************************************************************************
639 // printDictionaryKeys
641 // Print the keys for the given dictionary and selected contents.
642 //*********************************************************************************
643 void printDictionaryKeys (OSDictionary
* inDictionary
, char * inMsg
)
645 OSCollectionIterator
* mcoll
= OSCollectionIterator::withCollection (inDictionary
);
652 mkey
= OSDynamicCast (OSSymbol
, mcoll
->getNextObject ());
656 // kprintf ("dictionary key #%d: %s\n", i, mkey->getCStringNoCopy () );
658 // if this is the IOClass key, print it's contents
660 if ( mkey
->isEqualTo ("IOClass") ) {
661 ioClass
= (OSString
*) inDictionary
->getObject ("IOClass");
662 if ( ioClass
) IOLog ("%s IOClass is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
665 // if this is an IOProviderClass key print it
667 if ( mkey
->isEqualTo ("IOProviderClass") ) {
668 ioClass
= (OSString
*) inDictionary
->getObject ("IOProviderClass");
669 if ( ioClass
) IOLog ("%s IOProviderClass is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
673 // also print IONameMatch keys
674 if ( mkey
->isEqualTo ("IONameMatch") ) {
675 ioClass
= (OSString
*) inDictionary
->getObject ("IONameMatch");
676 if ( ioClass
) IOLog ("%s IONameMatch is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
679 // also print IONameMatched keys
681 if ( mkey
->isEqualTo ("IONameMatched") ) {
682 ioClass
= (OSString
*) inDictionary
->getObject ("IONameMatched");
683 if ( ioClass
) IOLog ("%s IONameMatched is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
689 if ( mkey
->isEqualTo ("AAPL,clock-id") ) {
691 cstr
= getCStringForObject (inDictionary
->getObject ("AAPL,clock-id"));
693 kprintf (" ===> AAPL,clock-id is %s\n", cstr
);
699 if ( mkey
->isEqualTo ("name") ) {
702 getCStringForObject(inDictionary
->getObject("name"), nameStr
,
704 if (strlen(nameStr
) > 0)
705 IOLog ("%s name is %s\n", inMsg
, nameStr
);
708 mkey
= (OSSymbol
*) mcoll
->getNextObject ();
717 getCStringForObject(OSObject
*inObj
, char *outStr
, size_t outStrLen
)
722 if ( (NULL
== inObj
) || (NULL
== outStr
))
725 char * objString
= (char *) (inObj
->getMetaClass())->getClassName();
727 if ((0 == strncmp(objString
, "OSString", sizeof("OSString"))) ||
728 (0 == strncmp(objString
, "OSSymbol", sizeof("OSSymbol"))))
729 strlcpy(outStr
, ((OSString
*)inObj
)->getCStringNoCopy(), outStrLen
);
731 else if (0 == strncmp(objString
, "OSData", sizeof("OSData"))) {
732 len
= ((OSData
*)inObj
)->getLength();
733 buffer
= (char *)((OSData
*)inObj
)->getBytesNoCopy();
734 if (buffer
&& (len
> 0)) {
735 for (i
=0; i
< len
; i
++) {
736 outStr
[i
] = buffer
[i
];
743 /* IOShutdownNotificationsTimedOut
744 * - Called from a timer installed by PEHaltRestart
746 static void IOShutdownNotificationsTimedOut(
747 thread_call_param_t p0
,
748 thread_call_param_t p1
)
750 int type
= (int)(long)p0
;
752 /* 30 seconds has elapsed - resume shutdown */
753 if(gIOPlatform
) gIOPlatform
->haltRestart(type
);
760 * Callouts from BSD for machine name & model
763 boolean_t
PEGetMachineName( char * name
, int maxLength
)
766 return( gIOPlatform
->getMachineName( name
, maxLength
));
771 boolean_t
PEGetModelName( char * name
, int maxLength
)
774 return( gIOPlatform
->getModelName( name
, maxLength
));
779 int PEGetPlatformEpoch(void)
782 return( gIOPlatform
->getBootROMType());
787 int PEHaltRestart(unsigned int type
)
789 IOPMrootDomain
*pmRootDomain
;
790 AbsoluteTime deadline
;
791 thread_call_t shutdown_hang
;
793 if(type
== kPEHaltCPU
|| type
== kPERestartCPU
|| type
== kPEUPSDelayHaltCPU
)
795 pmRootDomain
= IOService::getPMRootDomain();
796 /* Notify IOKit PM clients of shutdown/restart
797 Clients subscribe to this message with a call to
798 IOService::registerInterest()
801 /* Spawn a thread that will panic in 30 seconds.
802 If all goes well the machine will be off by the time
805 shutdown_hang
= thread_call_allocate( &IOShutdownNotificationsTimedOut
,
806 (thread_call_param_t
) type
);
807 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
808 thread_call_enter1_delayed( shutdown_hang
, 0, deadline
);
810 pmRootDomain
->handlePlatformHaltRestart(type
);
811 /* This notification should have few clients who all do
812 their work synchronously.
814 In this "shutdown notification" context we don't give
815 drivers the option of working asynchronously and responding
816 later. PM internals make it very hard to wait for asynchronous
821 if (gIOPlatform
) return gIOPlatform
->haltRestart(type
);
825 UInt32
PESavePanicInfo(UInt8
*buffer
, UInt32 length
)
827 if (gIOPlatform
!= 0) return gIOPlatform
->savePanicInfo(buffer
, length
);
833 inline static int init_gIOOptionsEntry(void)
835 IORegistryEntry
*entry
;
837 volatile void **options
;
843 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
847 nvram_entry
= (void *) OSDynamicCast(IODTNVRAM
, entry
);
851 options
= (volatile void **) &gIOOptionsEntry
;
852 if (!OSCompareAndSwapPtr(NULL
, nvram_entry
, options
)) {
865 /* pass in a NULL value if you just want to figure out the len */
866 boolean_t
PEReadNVRAMProperty(const char *symbol
, void *value
,
876 if (init_gIOOptionsEntry() < 0)
882 obj
= gIOOptionsEntry
->getProperty(symbol
);
886 /* convert to data */
887 data
= OSDynamicCast(OSData
, obj
);
891 *len
= data
->getLength();
892 vlen
= min(vlen
, *len
);
894 memcpy((void *) value
, data
->getBytesNoCopy(), vlen
);
903 boolean_t
PEWriteNVRAMProperty(const char *symbol
, const void *value
,
904 const unsigned int len
)
910 if (!symbol
|| !value
|| !len
)
913 if (init_gIOOptionsEntry() < 0)
916 sym
= OSSymbol::withCStringNoCopy(symbol
);
920 data
= OSData::withBytes((void *) value
, len
);
924 ret
= gIOOptionsEntry
->setProperty(sym
, data
);
931 gIOOptionsEntry
->sync();
940 long PEGetGMTTimeOfDay(void)
944 if( gIOPlatform
) result
= gIOPlatform
->getGMTTimeOfDay();
949 void PESetGMTTimeOfDay(long secs
)
951 if( gIOPlatform
) gIOPlatform
->setGMTTimeOfDay(secs
);
956 void IOPlatformExpert::registerNVRAMController(IONVRAMController
* caller
)
959 IORegistryEntry
* entry
;
960 OSString
* string
= 0;
963 entry
= IORegistryEntry::fromPath( "/efi/platform", gIODTPlane
);
966 data
= OSDynamicCast( OSData
, entry
->getProperty( "system-id" ) );
967 if ( data
&& data
->getLength( ) == 16 )
970 uint8_t digest
[ SHA_DIGEST_LENGTH
];
971 const uuid_t space
= { 0x2A, 0x06, 0x19, 0x90, 0xD3, 0x8D, 0x44, 0x40, 0xA1, 0x39, 0xC4, 0x97, 0x70, 0x37, 0x65, 0xAC };
973 SHA1Init( &context
);
974 SHA1Update( &context
, space
, sizeof( space
) );
975 SHA1Update( &context
, data
->getBytesNoCopy( ), data
->getLength( ) );
976 SHA1Final( digest
, &context
);
978 digest
[ 6 ] = ( digest
[ 6 ] & 0x0F ) | 0x50;
979 digest
[ 8 ] = ( digest
[ 8 ] & 0x3F ) | 0x80;
981 uuid_unparse( digest
, uuid
);
982 string
= OSString::withCString( uuid
);
990 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
993 data
= OSDynamicCast( OSData
, entry
->getProperty( "platform-uuid" ) );
994 if ( data
&& data
->getLength( ) == sizeof( uuid_t
) )
996 uuid_unparse( ( uint8_t * ) data
->getBytesNoCopy( ), uuid
);
997 string
= OSString::withCString( uuid
);
1006 getProvider( )->setProperty( kIOPlatformUUIDKey
, string
);
1007 publishResource( kIOPlatformUUIDKey
, string
);
1012 publishResource("IONVRAM");
1015 IOReturn
IOPlatformExpert::callPlatformFunction(const OSSymbol
*functionName
,
1016 bool waitForFunction
,
1017 void *param1
, void *param2
,
1018 void *param3
, void *param4
)
1020 IOService
*service
, *_resources
;
1022 if (waitForFunction
) {
1023 _resources
= waitForService(resourceMatching(functionName
));
1025 _resources
= getResourceService();
1027 if (_resources
== 0) return kIOReturnUnsupported
;
1029 service
= OSDynamicCast(IOService
, _resources
->getProperty(functionName
));
1030 if (service
== 0) return kIOReturnUnsupported
;
1032 return service
->callPlatformFunction(functionName
, waitForFunction
,
1033 param1
, param2
, param3
, param4
);
1036 IOByteCount
IOPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1041 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1044 #define super IOPlatformExpert
1046 OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert
, IOPlatformExpert
)
1048 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 0);
1049 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 1);
1050 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 2);
1051 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 3);
1052 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 4);
1053 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 5);
1054 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 6);
1055 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 7);
1057 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1059 IOService
* IODTPlatformExpert::probe( IOService
* provider
,
1062 if( !super::probe( provider
, score
))
1065 // check machine types
1066 if( !provider
->compareNames( getProperty( gIONameMatchKey
) ))
1072 bool IODTPlatformExpert::configure( IOService
* provider
)
1074 if( !super::configure( provider
))
1077 processTopLevel( provider
);
1082 IOService
* IODTPlatformExpert::createNub( IORegistryEntry
* from
)
1086 nub
= new IOPlatformDevice
;
1088 if( !nub
->init( from
, gIODTPlane
)) {
1096 bool IODTPlatformExpert::createNubs( IOService
* parent
, OSIterator
* iter
)
1098 IORegistryEntry
* next
;
1103 while( (next
= (IORegistryEntry
*) iter
->getNextObject())) {
1105 if( 0 == (nub
= createNub( next
)))
1108 nub
->attach( parent
);
1109 nub
->registerService();
1117 void IODTPlatformExpert::processTopLevel( IORegistryEntry
* rootEntry
)
1120 IORegistryEntry
* next
;
1121 IORegistryEntry
* cpus
;
1122 IORegistryEntry
* options
;
1125 kids
= IODTFindMatchingEntries( rootEntry
, 0, deleteList() );
1127 while( (next
= (IORegistryEntry
*)kids
->getNextObject())) {
1128 next
->detachAll( gIODTPlane
);
1133 // Publish an IODTNVRAM class on /options.
1134 options
= rootEntry
->childFromPath("options", gIODTPlane
);
1136 dtNVRAM
= new IODTNVRAM
;
1138 if (!dtNVRAM
->init(options
, gIODTPlane
)) {
1142 dtNVRAM
->attach(this);
1143 dtNVRAM
->registerService();
1148 // Publish the cpus.
1149 cpus
= rootEntry
->childFromPath( "cpus", gIODTPlane
);
1151 createNubs( this, IODTFindMatchingEntries( cpus
, kIODTExclusive
, 0));
1153 // publish top level, minus excludeList
1154 createNubs( this, IODTFindMatchingEntries( rootEntry
, kIODTExclusive
, excludeList()));
1157 IOReturn
IODTPlatformExpert::getNubResources( IOService
* nub
)
1159 if( nub
->getDeviceMemory())
1160 return( kIOReturnSuccess
);
1162 IODTResolveAddressing( nub
, "reg", 0);
1164 return( kIOReturnSuccess
);
1167 bool IODTPlatformExpert::compareNubName( const IOService
* nub
,
1168 OSString
* name
, OSString
** matched
) const
1170 return( IODTCompareNubName( nub
, name
, matched
)
1171 || super::compareNubName( nub
, name
, matched
) );
1174 bool IODTPlatformExpert::getModelName( char * name
, int maxLength
)
1184 prop
= (OSData
*) getProvider()->getProperty( gIODTCompatibleKey
);
1186 str
= (const char *) prop
->getBytesNoCopy();
1188 if( 0 == strncmp( str
, "AAPL,", strlen( "AAPL," ) ))
1189 str
+= strlen( "AAPL," );
1192 while( (c
= *str
++)) {
1193 if( (c
== '/') || (c
== ' '))
1197 if( len
>= maxLength
)
1207 bool IODTPlatformExpert::getMachineName( char * name
, int maxLength
)
1213 prop
= (OSData
*) getProvider()->getProperty( gIODTModelKey
);
1217 strlcpy( name
, (const char *) prop
->getBytesNoCopy(), maxLength
);
1222 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1224 void IODTPlatformExpert::registerNVRAMController( IONVRAMController
* nvram
)
1226 if (dtNVRAM
) dtNVRAM
->registerNVRAMController(nvram
);
1228 super::registerNVRAMController(nvram
);
1231 int IODTPlatformExpert::haltRestart(unsigned int type
)
1233 if (dtNVRAM
) dtNVRAM
->sync();
1235 return super::haltRestart(type
);
1238 IOReturn
IODTPlatformExpert::readXPRAM(IOByteCount offset
, UInt8
* buffer
,
1241 if (dtNVRAM
) return dtNVRAM
->readXPRAM(offset
, buffer
, length
);
1242 else return kIOReturnNotReady
;
1245 IOReturn
IODTPlatformExpert::writeXPRAM(IOByteCount offset
, UInt8
* buffer
,
1248 if (dtNVRAM
) return dtNVRAM
->writeXPRAM(offset
, buffer
, length
);
1249 else return kIOReturnNotReady
;
1252 IOReturn
IODTPlatformExpert::readNVRAMProperty(
1253 IORegistryEntry
* entry
,
1254 const OSSymbol
** name
, OSData
** value
)
1256 if (dtNVRAM
) return dtNVRAM
->readNVRAMProperty(entry
, name
, value
);
1257 else return kIOReturnNotReady
;
1260 IOReturn
IODTPlatformExpert::writeNVRAMProperty(
1261 IORegistryEntry
* entry
,
1262 const OSSymbol
* name
, OSData
* value
)
1264 if (dtNVRAM
) return dtNVRAM
->writeNVRAMProperty(entry
, name
, value
);
1265 else return kIOReturnNotReady
;
1268 OSDictionary
*IODTPlatformExpert::getNVRAMPartitions(void)
1270 if (dtNVRAM
) return dtNVRAM
->getNVRAMPartitions();
1274 IOReturn
IODTPlatformExpert::readNVRAMPartition(const OSSymbol
* partitionID
,
1275 IOByteCount offset
, UInt8
* buffer
,
1278 if (dtNVRAM
) return dtNVRAM
->readNVRAMPartition(partitionID
, offset
,
1280 else return kIOReturnNotReady
;
1283 IOReturn
IODTPlatformExpert::writeNVRAMPartition(const OSSymbol
* partitionID
,
1284 IOByteCount offset
, UInt8
* buffer
,
1287 if (dtNVRAM
) return dtNVRAM
->writeNVRAMPartition(partitionID
, offset
,
1289 else return kIOReturnNotReady
;
1292 IOByteCount
IODTPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1294 IOByteCount lengthSaved
= 0;
1296 if (dtNVRAM
) lengthSaved
= dtNVRAM
->savePanicInfo(buffer
, length
);
1298 if (lengthSaved
== 0) lengthSaved
= super::savePanicInfo(buffer
, length
);
1303 OSString
* IODTPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
) {
1304 UInt8
* serialNumber
;
1305 unsigned int serialNumberSize
;
1306 unsigned short pos
= 0;
1310 if (myProperty
!= NULL
) {
1311 serialNumberSize
= myProperty
->getLength();
1312 serialNumber
= (UInt8
*)(myProperty
->getBytesNoCopy());
1313 temp
= (char*)serialNumber
;
1314 if (serialNumberSize
> 0) {
1315 // check to see if this is a CTO serial number...
1316 while (pos
< serialNumberSize
&& temp
[pos
] != '-') pos
++;
1318 if (pos
< serialNumberSize
) { // there was a hyphen, so it's a CTO serial number
1319 memcpy(SerialNo
, serialNumber
+ 12, 8);
1320 memcpy(&SerialNo
[8], serialNumber
, 3);
1322 memcpy(&SerialNo
[12], serialNumber
+ 3, 8);
1324 } else { // just a normal serial number
1325 memcpy(SerialNo
, serialNumber
+ 13, 8);
1326 memcpy(&SerialNo
[8], serialNumber
, 3);
1329 return OSString::withCString(SerialNo
);
1336 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1339 #define super IOService
1341 OSDefineMetaClassAndStructors(IOPlatformExpertDevice
, IOService
)
1343 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 0);
1344 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 1);
1345 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 2);
1346 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 3);
1348 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1350 bool IOPlatformExpertDevice::compareName( OSString
* name
,
1351 OSString
** matched
) const
1353 return( IODTCompareNubName( this, name
, matched
));
1357 IOPlatformExpertDevice::initWithArgs(
1358 void * dtTop
, void * p2
, void * p3
, void * p4
)
1360 IORegistryEntry
* dt
= 0;
1361 void * argsData
[ 4 ];
1364 // dtTop may be zero on non- device tree systems
1365 if( dtTop
&& (dt
= IODeviceTreeAlloc( dtTop
)))
1366 ok
= super::init( dt
, gIODTPlane
);
1373 workLoop
= IOWorkLoop::workLoop();
1377 argsData
[ 0 ] = dtTop
;
1382 setProperty("IOPlatformArgs", (void *)argsData
, sizeof(argsData
));
1387 IOWorkLoop
*IOPlatformExpertDevice::getWorkLoop() const
1392 IOReturn
IOPlatformExpertDevice::setProperties( OSObject
* properties
)
1394 OSDictionary
* dictionary
;
1398 status
= super::setProperties( properties
);
1399 if ( status
!= kIOReturnUnsupported
) return status
;
1401 status
= IOUserClient::clientHasPrivilege( current_task( ), kIOClientPrivilegeAdministrator
);
1402 if ( status
!= kIOReturnSuccess
) return status
;
1404 dictionary
= OSDynamicCast( OSDictionary
, properties
);
1405 if ( dictionary
== 0 ) return kIOReturnBadArgument
;
1407 object
= dictionary
->getObject( kIOPlatformUUIDKey
);
1410 IORegistryEntry
* entry
;
1414 string
= ( OSString
* ) getProperty( kIOPlatformUUIDKey
);
1415 if ( string
) return kIOReturnNotPermitted
;
1417 string
= OSDynamicCast( OSString
, object
);
1418 if ( string
== 0 ) return kIOReturnBadArgument
;
1420 status
= uuid_parse( string
->getCStringNoCopy( ), uuid
);
1421 if ( status
!= 0 ) return kIOReturnBadArgument
;
1423 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
1426 entry
->setProperty( "platform-uuid", uuid
, sizeof( uuid_t
) );
1430 setProperty( kIOPlatformUUIDKey
, string
);
1431 publishResource( kIOPlatformUUIDKey
, string
);
1433 return kIOReturnSuccess
;
1436 return kIOReturnUnsupported
;
1439 void IOPlatformExpertDevice::free()
1442 workLoop
->release();
1445 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1448 #define super IOService
1450 OSDefineMetaClassAndStructors(IOPlatformDevice
, IOService
)
1452 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 0);
1453 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 1);
1454 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 2);
1455 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 3);
1457 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1459 bool IOPlatformDevice::compareName( OSString
* name
,
1460 OSString
** matched
) const
1462 return( ((IOPlatformExpert
*)getProvider())->
1463 compareNubName( this, name
, matched
));
1466 IOService
* IOPlatformDevice::matchLocation( IOService
* /* client */ )
1471 IOReturn
IOPlatformDevice::getResources( void )
1473 return( ((IOPlatformExpert
*)getProvider())->getNubResources( this ));
1476 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1478 /*********************************************************************
1479 * IOPanicPlatform class
1481 * If no legitimate IOPlatformDevice matches, this one does and panics
1482 * the kernel with a suitable message.
1483 *********************************************************************/
1485 class IOPanicPlatform
: IOPlatformExpert
{
1486 OSDeclareDefaultStructors(IOPanicPlatform
);
1489 bool start(IOService
* provider
);
1493 OSDefineMetaClassAndStructors(IOPanicPlatform
, IOPlatformExpert
);
1496 bool IOPanicPlatform::start(IOService
* provider
) {
1497 const char * platform_name
= "(unknown platform name)";
1499 if (provider
) platform_name
= provider
->getName();
1501 panic("Unable to find driver for this platform: \"%s\".\n",