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 #ifdef CONFIG_EMBEDDED
751 /* 30 seconds has elapsed - panic */
752 panic("Halt/Restart Timed Out");
754 #else /* ! CONFIG_EMBEDDED */
755 int type
= (int)(long)p0
;
757 /* 30 seconds has elapsed - resume shutdown */
758 if(gIOPlatform
) gIOPlatform
->haltRestart(type
);
759 #endif /* CONFIG_EMBEDDED */
766 * Callouts from BSD for machine name & model
769 boolean_t
PEGetMachineName( char * name
, int maxLength
)
772 return( gIOPlatform
->getMachineName( name
, maxLength
));
777 boolean_t
PEGetModelName( char * name
, int maxLength
)
780 return( gIOPlatform
->getModelName( name
, maxLength
));
785 int PEGetPlatformEpoch(void)
788 return( gIOPlatform
->getBootROMType());
793 int PEHaltRestart(unsigned int type
)
795 IOPMrootDomain
*pmRootDomain
;
796 AbsoluteTime deadline
;
797 thread_call_t shutdown_hang
;
799 if(type
== kPEHaltCPU
|| type
== kPERestartCPU
|| type
== kPEUPSDelayHaltCPU
)
801 pmRootDomain
= IOService::getPMRootDomain();
802 /* Notify IOKit PM clients of shutdown/restart
803 Clients subscribe to this message with a call to
804 IOService::registerInterest()
807 /* Spawn a thread that will panic in 30 seconds.
808 If all goes well the machine will be off by the time
811 shutdown_hang
= thread_call_allocate( &IOShutdownNotificationsTimedOut
,
812 (thread_call_param_t
) type
);
813 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
814 thread_call_enter1_delayed( shutdown_hang
, 0, deadline
);
816 pmRootDomain
->handlePlatformHaltRestart(type
);
817 /* This notification should have few clients who all do
818 their work synchronously.
820 In this "shutdown notification" context we don't give
821 drivers the option of working asynchronously and responding
822 later. PM internals make it very hard to wait for asynchronous
827 if (gIOPlatform
) return gIOPlatform
->haltRestart(type
);
831 UInt32
PESavePanicInfo(UInt8
*buffer
, UInt32 length
)
833 if (gIOPlatform
!= 0) return gIOPlatform
->savePanicInfo(buffer
, length
);
839 inline static int init_gIOOptionsEntry(void)
841 IORegistryEntry
*entry
;
843 volatile void **options
;
849 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
853 nvram_entry
= (void *) OSDynamicCast(IODTNVRAM
, entry
);
857 options
= (volatile void **) &gIOOptionsEntry
;
858 if (!OSCompareAndSwapPtr(NULL
, nvram_entry
, options
)) {
871 /* pass in a NULL value if you just want to figure out the len */
872 boolean_t
PEReadNVRAMProperty(const char *symbol
, void *value
,
882 if (init_gIOOptionsEntry() < 0)
888 obj
= gIOOptionsEntry
->getProperty(symbol
);
892 /* convert to data */
893 data
= OSDynamicCast(OSData
, obj
);
897 *len
= data
->getLength();
898 vlen
= min(vlen
, *len
);
900 memcpy((void *) value
, data
->getBytesNoCopy(), vlen
);
909 boolean_t
PEWriteNVRAMProperty(const char *symbol
, const void *value
,
910 const unsigned int len
)
916 if (!symbol
|| !value
|| !len
)
919 if (init_gIOOptionsEntry() < 0)
922 sym
= OSSymbol::withCStringNoCopy(symbol
);
926 data
= OSData::withBytes((void *) value
, len
);
930 ret
= gIOOptionsEntry
->setProperty(sym
, data
);
937 gIOOptionsEntry
->sync();
946 long PEGetGMTTimeOfDay(void)
950 if( gIOPlatform
) result
= gIOPlatform
->getGMTTimeOfDay();
955 void PESetGMTTimeOfDay(long secs
)
957 if( gIOPlatform
) gIOPlatform
->setGMTTimeOfDay(secs
);
962 void IOPlatformExpert::registerNVRAMController(IONVRAMController
* caller
)
965 IORegistryEntry
* entry
;
966 OSString
* string
= 0;
970 entry
= IORegistryEntry::fromPath( "/chosen", gIODTPlane
);
975 data1
= OSDynamicCast( OSData
, entry
->getProperty( "unique-chip-id" ) );
976 if ( data1
&& data1
->getLength( ) == 8 )
980 data2
= OSDynamicCast( OSData
, entry
->getProperty( "chip-id" ) );
981 if ( data2
&& data2
->getLength( ) == 4 )
984 uint8_t digest
[ SHA_DIGEST_LENGTH
];
985 const uuid_t space
= { 0xA6, 0xDD, 0x4C, 0xCB, 0xB5, 0xE8, 0x4A, 0xF5, 0xAC, 0xDD, 0xB6, 0xDC, 0x6A, 0x05, 0x42, 0xB8 };
987 SHA1Init( &context
);
988 SHA1Update( &context
, space
, sizeof( space
) );
989 SHA1Update( &context
, data1
->getBytesNoCopy( ), data1
->getLength( ) );
990 SHA1Update( &context
, data2
->getBytesNoCopy( ), data2
->getLength( ) );
991 SHA1Final( digest
, &context
);
993 digest
[ 6 ] = ( digest
[ 6 ] & 0x0F ) | 0x50;
994 digest
[ 8 ] = ( digest
[ 8 ] & 0x3F ) | 0x80;
996 uuid_unparse( digest
, uuid
);
997 string
= OSString::withCString( uuid
);
1003 #else /* !CONFIG_EMBEDDED */
1004 entry
= IORegistryEntry::fromPath( "/efi/platform", gIODTPlane
);
1007 data
= OSDynamicCast( OSData
, entry
->getProperty( "system-id" ) );
1008 if ( data
&& data
->getLength( ) == 16 )
1011 uint8_t digest
[ SHA_DIGEST_LENGTH
];
1012 const uuid_t space
= { 0x2A, 0x06, 0x19, 0x90, 0xD3, 0x8D, 0x44, 0x40, 0xA1, 0x39, 0xC4, 0x97, 0x70, 0x37, 0x65, 0xAC };
1014 SHA1Init( &context
);
1015 SHA1Update( &context
, space
, sizeof( space
) );
1016 SHA1Update( &context
, data
->getBytesNoCopy( ), data
->getLength( ) );
1017 SHA1Final( digest
, &context
);
1019 digest
[ 6 ] = ( digest
[ 6 ] & 0x0F ) | 0x50;
1020 digest
[ 8 ] = ( digest
[ 8 ] & 0x3F ) | 0x80;
1022 uuid_unparse( digest
, uuid
);
1023 string
= OSString::withCString( uuid
);
1028 #endif /* !CONFIG_EMBEDDED */
1032 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
1035 data
= OSDynamicCast( OSData
, entry
->getProperty( "platform-uuid" ) );
1036 if ( data
&& data
->getLength( ) == sizeof( uuid_t
) )
1038 uuid_unparse( ( uint8_t * ) data
->getBytesNoCopy( ), uuid
);
1039 string
= OSString::withCString( uuid
);
1048 getProvider( )->setProperty( kIOPlatformUUIDKey
, string
);
1049 publishResource( kIOPlatformUUIDKey
, string
);
1054 publishResource("IONVRAM");
1057 IOReturn
IOPlatformExpert::callPlatformFunction(const OSSymbol
*functionName
,
1058 bool waitForFunction
,
1059 void *param1
, void *param2
,
1060 void *param3
, void *param4
)
1062 IOService
*service
, *_resources
;
1064 if (waitForFunction
) {
1065 _resources
= waitForService(resourceMatching(functionName
));
1067 _resources
= getResourceService();
1069 if (_resources
== 0) return kIOReturnUnsupported
;
1071 service
= OSDynamicCast(IOService
, _resources
->getProperty(functionName
));
1072 if (service
== 0) return kIOReturnUnsupported
;
1074 return service
->callPlatformFunction(functionName
, waitForFunction
,
1075 param1
, param2
, param3
, param4
);
1078 IOByteCount
IOPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1083 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1086 #define super IOPlatformExpert
1088 OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert
, IOPlatformExpert
)
1090 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 0);
1091 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 1);
1092 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 2);
1093 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 3);
1094 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 4);
1095 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 5);
1096 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 6);
1097 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 7);
1099 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1101 IOService
* IODTPlatformExpert::probe( IOService
* provider
,
1104 if( !super::probe( provider
, score
))
1107 // check machine types
1108 if( !provider
->compareNames( getProperty( gIONameMatchKey
) ))
1114 bool IODTPlatformExpert::configure( IOService
* provider
)
1116 if( !super::configure( provider
))
1119 processTopLevel( provider
);
1124 IOService
* IODTPlatformExpert::createNub( IORegistryEntry
* from
)
1128 nub
= new IOPlatformDevice
;
1130 if( !nub
->init( from
, gIODTPlane
)) {
1138 bool IODTPlatformExpert::createNubs( IOService
* parent
, OSIterator
* iter
)
1140 IORegistryEntry
* next
;
1145 while( (next
= (IORegistryEntry
*) iter
->getNextObject())) {
1147 if( 0 == (nub
= createNub( next
)))
1150 nub
->attach( parent
);
1151 nub
->registerService();
1159 void IODTPlatformExpert::processTopLevel( IORegistryEntry
* rootEntry
)
1162 IORegistryEntry
* next
;
1163 IORegistryEntry
* cpus
;
1164 IORegistryEntry
* options
;
1167 kids
= IODTFindMatchingEntries( rootEntry
, 0, deleteList() );
1169 while( (next
= (IORegistryEntry
*)kids
->getNextObject())) {
1170 next
->detachAll( gIODTPlane
);
1175 // Publish an IODTNVRAM class on /options.
1176 options
= rootEntry
->childFromPath("options", gIODTPlane
);
1178 dtNVRAM
= new IODTNVRAM
;
1180 if (!dtNVRAM
->init(options
, gIODTPlane
)) {
1184 dtNVRAM
->attach(this);
1185 dtNVRAM
->registerService();
1190 // Publish the cpus.
1191 cpus
= rootEntry
->childFromPath( "cpus", gIODTPlane
);
1193 createNubs( this, IODTFindMatchingEntries( cpus
, kIODTExclusive
, 0));
1195 // publish top level, minus excludeList
1196 createNubs( this, IODTFindMatchingEntries( rootEntry
, kIODTExclusive
, excludeList()));
1199 IOReturn
IODTPlatformExpert::getNubResources( IOService
* nub
)
1201 if( nub
->getDeviceMemory())
1202 return( kIOReturnSuccess
);
1204 IODTResolveAddressing( nub
, "reg", 0);
1206 return( kIOReturnSuccess
);
1209 bool IODTPlatformExpert::compareNubName( const IOService
* nub
,
1210 OSString
* name
, OSString
** matched
) const
1212 return( IODTCompareNubName( nub
, name
, matched
)
1213 || super::compareNubName( nub
, name
, matched
) );
1216 bool IODTPlatformExpert::getModelName( char * name
, int maxLength
)
1226 prop
= (OSData
*) getProvider()->getProperty( gIODTCompatibleKey
);
1228 str
= (const char *) prop
->getBytesNoCopy();
1230 if( 0 == strncmp( str
, "AAPL,", strlen( "AAPL," ) ))
1231 str
+= strlen( "AAPL," );
1234 while( (c
= *str
++)) {
1235 if( (c
== '/') || (c
== ' '))
1239 if( len
>= maxLength
)
1249 bool IODTPlatformExpert::getMachineName( char * name
, int maxLength
)
1255 prop
= (OSData
*) getProvider()->getProperty( gIODTModelKey
);
1259 strlcpy( name
, (const char *) prop
->getBytesNoCopy(), maxLength
);
1264 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1266 void IODTPlatformExpert::registerNVRAMController( IONVRAMController
* nvram
)
1268 if (dtNVRAM
) dtNVRAM
->registerNVRAMController(nvram
);
1270 super::registerNVRAMController(nvram
);
1273 int IODTPlatformExpert::haltRestart(unsigned int type
)
1275 if (dtNVRAM
) dtNVRAM
->sync();
1277 return super::haltRestart(type
);
1280 IOReturn
IODTPlatformExpert::readXPRAM(IOByteCount offset
, UInt8
* buffer
,
1283 if (dtNVRAM
) return dtNVRAM
->readXPRAM(offset
, buffer
, length
);
1284 else return kIOReturnNotReady
;
1287 IOReturn
IODTPlatformExpert::writeXPRAM(IOByteCount offset
, UInt8
* buffer
,
1290 if (dtNVRAM
) return dtNVRAM
->writeXPRAM(offset
, buffer
, length
);
1291 else return kIOReturnNotReady
;
1294 IOReturn
IODTPlatformExpert::readNVRAMProperty(
1295 IORegistryEntry
* entry
,
1296 const OSSymbol
** name
, OSData
** value
)
1298 if (dtNVRAM
) return dtNVRAM
->readNVRAMProperty(entry
, name
, value
);
1299 else return kIOReturnNotReady
;
1302 IOReturn
IODTPlatformExpert::writeNVRAMProperty(
1303 IORegistryEntry
* entry
,
1304 const OSSymbol
* name
, OSData
* value
)
1306 if (dtNVRAM
) return dtNVRAM
->writeNVRAMProperty(entry
, name
, value
);
1307 else return kIOReturnNotReady
;
1310 OSDictionary
*IODTPlatformExpert::getNVRAMPartitions(void)
1312 if (dtNVRAM
) return dtNVRAM
->getNVRAMPartitions();
1316 IOReturn
IODTPlatformExpert::readNVRAMPartition(const OSSymbol
* partitionID
,
1317 IOByteCount offset
, UInt8
* buffer
,
1320 if (dtNVRAM
) return dtNVRAM
->readNVRAMPartition(partitionID
, offset
,
1322 else return kIOReturnNotReady
;
1325 IOReturn
IODTPlatformExpert::writeNVRAMPartition(const OSSymbol
* partitionID
,
1326 IOByteCount offset
, UInt8
* buffer
,
1329 if (dtNVRAM
) return dtNVRAM
->writeNVRAMPartition(partitionID
, offset
,
1331 else return kIOReturnNotReady
;
1334 IOByteCount
IODTPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1336 IOByteCount lengthSaved
= 0;
1338 if (dtNVRAM
) lengthSaved
= dtNVRAM
->savePanicInfo(buffer
, length
);
1340 if (lengthSaved
== 0) lengthSaved
= super::savePanicInfo(buffer
, length
);
1345 OSString
* IODTPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
) {
1346 UInt8
* serialNumber
;
1347 unsigned int serialNumberSize
;
1348 unsigned short pos
= 0;
1352 if (myProperty
!= NULL
) {
1353 serialNumberSize
= myProperty
->getLength();
1354 serialNumber
= (UInt8
*)(myProperty
->getBytesNoCopy());
1355 temp
= (char*)serialNumber
;
1356 if (serialNumberSize
> 0) {
1357 // check to see if this is a CTO serial number...
1358 while (pos
< serialNumberSize
&& temp
[pos
] != '-') pos
++;
1360 if (pos
< serialNumberSize
) { // there was a hyphen, so it's a CTO serial number
1361 memcpy(SerialNo
, serialNumber
+ 12, 8);
1362 memcpy(&SerialNo
[8], serialNumber
, 3);
1364 memcpy(&SerialNo
[12], serialNumber
+ 3, 8);
1366 } else { // just a normal serial number
1367 memcpy(SerialNo
, serialNumber
+ 13, 8);
1368 memcpy(&SerialNo
[8], serialNumber
, 3);
1371 return OSString::withCString(SerialNo
);
1378 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1381 #define super IOService
1383 OSDefineMetaClassAndStructors(IOPlatformExpertDevice
, IOService
)
1385 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 0);
1386 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 1);
1387 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 2);
1388 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 3);
1390 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1392 bool IOPlatformExpertDevice::compareName( OSString
* name
,
1393 OSString
** matched
) const
1395 return( IODTCompareNubName( this, name
, matched
));
1399 IOPlatformExpertDevice::initWithArgs(
1400 void * dtTop
, void * p2
, void * p3
, void * p4
)
1402 IORegistryEntry
* dt
= 0;
1403 void * argsData
[ 4 ];
1406 // dtTop may be zero on non- device tree systems
1407 if( dtTop
&& (dt
= IODeviceTreeAlloc( dtTop
)))
1408 ok
= super::init( dt
, gIODTPlane
);
1415 workLoop
= IOWorkLoop::workLoop();
1419 argsData
[ 0 ] = dtTop
;
1424 setProperty("IOPlatformArgs", (void *)argsData
, sizeof(argsData
));
1429 IOWorkLoop
*IOPlatformExpertDevice::getWorkLoop() const
1434 IOReturn
IOPlatformExpertDevice::setProperties( OSObject
* properties
)
1436 OSDictionary
* dictionary
;
1440 status
= super::setProperties( properties
);
1441 if ( status
!= kIOReturnUnsupported
) return status
;
1443 status
= IOUserClient::clientHasPrivilege( current_task( ), kIOClientPrivilegeAdministrator
);
1444 if ( status
!= kIOReturnSuccess
) return status
;
1446 dictionary
= OSDynamicCast( OSDictionary
, properties
);
1447 if ( dictionary
== 0 ) return kIOReturnBadArgument
;
1449 object
= dictionary
->getObject( kIOPlatformUUIDKey
);
1452 IORegistryEntry
* entry
;
1456 string
= ( OSString
* ) getProperty( kIOPlatformUUIDKey
);
1457 if ( string
) return kIOReturnNotPermitted
;
1459 string
= OSDynamicCast( OSString
, object
);
1460 if ( string
== 0 ) return kIOReturnBadArgument
;
1462 status
= uuid_parse( string
->getCStringNoCopy( ), uuid
);
1463 if ( status
!= 0 ) return kIOReturnBadArgument
;
1465 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
1468 entry
->setProperty( "platform-uuid", uuid
, sizeof( uuid_t
) );
1472 setProperty( kIOPlatformUUIDKey
, string
);
1473 publishResource( kIOPlatformUUIDKey
, string
);
1475 return kIOReturnSuccess
;
1478 return kIOReturnUnsupported
;
1481 void IOPlatformExpertDevice::free()
1484 workLoop
->release();
1487 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1490 #define super IOService
1492 OSDefineMetaClassAndStructors(IOPlatformDevice
, IOService
)
1494 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 0);
1495 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 1);
1496 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 2);
1497 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 3);
1499 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1501 bool IOPlatformDevice::compareName( OSString
* name
,
1502 OSString
** matched
) const
1504 return( ((IOPlatformExpert
*)getProvider())->
1505 compareNubName( this, name
, matched
));
1508 IOService
* IOPlatformDevice::matchLocation( IOService
* /* client */ )
1513 IOReturn
IOPlatformDevice::getResources( void )
1515 return( ((IOPlatformExpert
*)getProvider())->getNubResources( this ));
1518 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1520 /*********************************************************************
1521 * IOPanicPlatform class
1523 * If no legitimate IOPlatformDevice matches, this one does and panics
1524 * the kernel with a suitable message.
1525 *********************************************************************/
1527 class IOPanicPlatform
: IOPlatformExpert
{
1528 OSDeclareDefaultStructors(IOPanicPlatform
);
1531 bool start(IOService
* provider
);
1535 OSDefineMetaClassAndStructors(IOPanicPlatform
, IOPlatformExpert
);
1538 bool IOPanicPlatform::start(IOService
* provider
) {
1539 const char * platform_name
= "(unknown platform name)";
1541 if (provider
) platform_name
= provider
->getName();
1543 panic("Unable to find driver for this platform: \"%s\".\n",