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
);
108 if (PE_parse_boot_argn("-x", &debugFlags
, sizeof (debugFlags
)))
109 removeProperty(kIOPlatformMapperPresentKey
);
111 // Register the presence or lack thereof a system
112 // PCI address mapper with the IOMapper class
113 IOMapper::setMapperRequired(0 != getProperty(kIOPlatformMapperPresentKey
));
115 gIOInterruptControllers
= OSDictionary::withCapacity(1);
116 gIOInterruptControllersLock
= IOLockAlloc();
118 // Correct the bus frequency in the device tree.
119 busFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.bus_clock_rate_hz
, 4);
120 provider
->setProperty("clock-frequency", busFrequency
);
121 busFrequency
->release();
123 gPlatformInterruptControllerName
= (OSSymbol
*)OSSymbol::withCStringNoCopy("IOPlatformInterruptController");
125 physicalRanges
= IORangeAllocator::withRange(0xffffffff, 1, 16,
126 IORangeAllocator::kLocking
);
127 assert(physicalRanges
);
128 setProperty("Platform Memory Ranges", physicalRanges
);
133 PMInstantiatePowerDomains();
135 // Parse the serial-number data and publish a user-readable string
136 OSData
* mydata
= (OSData
*) (provider
->getProperty("serial-number"));
137 if (mydata
!= NULL
) {
138 OSString
*serNoString
= createSystemSerialNumberString(mydata
);
139 if (serNoString
!= NULL
) {
140 provider
->setProperty(kIOPlatformSerialNumberKey
, serNoString
);
141 serNoString
->release();
145 return( configure(provider
) );
148 bool IOPlatformExpert::configure( IOService
* provider
)
154 topLevel
= OSDynamicCast( OSSet
, getProperty("top-level"));
157 while( (dict
= OSDynamicCast( OSDictionary
,
158 topLevel
->getAnyObject()))) {
160 topLevel
->removeObject( dict
);
161 nub
= createNub( dict
);
166 nub
->registerService();
173 IOService
* IOPlatformExpert::createNub( OSDictionary
* from
)
177 nub
= new IOPlatformDevice
;
179 if( !nub
->init( from
)) {
187 bool IOPlatformExpert::compareNubName( const IOService
* nub
,
188 OSString
* name
, OSString
** matched
) const
190 return( nub
->IORegistryEntry::compareName( name
, matched
));
193 IOReturn
IOPlatformExpert::getNubResources( IOService
* nub
)
195 return( kIOReturnSuccess
);
198 long IOPlatformExpert::getBootROMType(void)
200 return _peBootROMType
;
203 long IOPlatformExpert::getChipSetType(void)
205 return _peChipSetType
;
208 long IOPlatformExpert::getMachineType(void)
210 return _peMachineType
;
213 void IOPlatformExpert::setBootROMType(long peBootROMType
)
215 _peBootROMType
= peBootROMType
;
218 void IOPlatformExpert::setChipSetType(long peChipSetType
)
220 _peChipSetType
= peChipSetType
;
223 void IOPlatformExpert::setMachineType(long peMachineType
)
225 _peMachineType
= peMachineType
;
228 bool IOPlatformExpert::getMachineName( char * /*name*/, int /*maxLength*/)
233 bool IOPlatformExpert::getModelName( char * /*name*/, int /*maxLength*/)
238 OSString
* IOPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
)
243 IORangeAllocator
* IOPlatformExpert::getPhysicalRangeAllocator(void)
245 return(OSDynamicCast(IORangeAllocator
,
246 getProperty("Platform Memory Ranges")));
249 int (*PE_halt_restart
)(unsigned int type
) = 0;
251 int IOPlatformExpert::haltRestart(unsigned int type
)
253 if (type
== kPEPanicSync
) return 0;
255 if (type
== kPEHangCPU
) while (true) {}
257 if (type
== kPEUPSDelayHaltCPU
) {
258 // RestartOnPowerLoss feature was turned on, proceed with shutdown.
262 // On ARM kPEPanicRestartCPU is supported in the drivers
263 if (type
== kPEPanicRestartCPU
)
264 type
= kPERestartCPU
;
266 if (PE_halt_restart
) return (*PE_halt_restart
)(type
);
270 void IOPlatformExpert::sleepKernel(void)
276 intState
= ml_set_interrupts_enabled(false);
278 for (cnt
= 0; cnt
< 10000; cnt
++) {
282 ml_set_interrupts_enabled(intState
);
284 // PE_initialize_console(0, kPEDisableScreen);
288 // PE_initialize_console(0, kPEEnableScreen);
292 long IOPlatformExpert::getGMTTimeOfDay(void)
297 void IOPlatformExpert::setGMTTimeOfDay(long secs
)
302 IOReturn
IOPlatformExpert::getConsoleInfo( PE_Video
* consoleInfo
)
304 return( PE_current_console( consoleInfo
));
307 IOReturn
IOPlatformExpert::setConsoleInfo( PE_Video
* consoleInfo
,
310 return( PE_initialize_console( consoleInfo
, op
));
313 IOReturn
IOPlatformExpert::registerInterruptController(OSSymbol
*name
, IOInterruptController
*interruptController
)
315 IOLockLock(gIOInterruptControllersLock
);
317 gIOInterruptControllers
->setObject(name
, interruptController
);
319 IOLockWakeup(gIOInterruptControllersLock
,
320 gIOInterruptControllers
, /* one-thread */ false);
322 IOLockUnlock(gIOInterruptControllersLock
);
324 return kIOReturnSuccess
;
327 IOInterruptController
*IOPlatformExpert::lookUpInterruptController(OSSymbol
*name
)
331 IOLockLock(gIOInterruptControllersLock
);
334 object
= gIOInterruptControllers
->getObject(name
);
339 IOLockSleep(gIOInterruptControllersLock
,
340 gIOInterruptControllers
, THREAD_UNINT
);
343 IOLockUnlock(gIOInterruptControllersLock
);
344 return OSDynamicCast(IOInterruptController
, object
);
348 void IOPlatformExpert::setCPUInterruptProperties(IOService
*service
)
350 IOCPUInterruptController
*controller
;
352 controller
= OSDynamicCast(IOCPUInterruptController
, waitForService(serviceMatching("IOCPUInterruptController")));
353 if (controller
) controller
->setCPUInterruptProperties(service
);
356 bool IOPlatformExpert::atInterruptLevel(void)
358 return ml_at_interrupt_context();
361 bool IOPlatformExpert::platformAdjustService(IOService */
*service*/
)
367 //*********************************************************************************
370 //*********************************************************************************
372 void IOPlatformExpert::
373 PMLog(const char *who
, unsigned long event
,
374 unsigned long param1
, unsigned long param2
)
376 UInt32 debugFlags
= gIOKitDebug
;
377 UInt32 traceFlags
= gIOKitTrace
;
381 if (debugFlags
& kIOLogPower
) {
385 clock_get_system_microtime(&nows
, &nowus
);
386 nowus
+= (nows
% 1000) * 1000000;
388 kprintf("pm%u %p %.30s %d %lx %lx\n",
389 nowus
, current_thread(), who
, // Identity
390 (int) event
, (long) param1
, (long) param2
); // Args
392 if (traceFlags
& kIOTracePowerMgmt
) {
393 static const UInt32 sStartStopBitField
[] =
394 { 0x00000000, 0x00000040 }; // Only Program Hardware so far
396 // Arcane formula from Hacker's Delight by Warren
397 // abs(x) = ((int) x >> 31) ^ (x + ((int) x >> 31))
398 UInt32 sgnevent
= ((long) event
>> 31);
399 UInt32 absevent
= sgnevent
^ (event
+ sgnevent
);
400 UInt32 code
= IODBG_POWER(absevent
);
402 UInt32 bit
= 1 << (absevent
& 0x1f);
403 if (absevent
< sizeof(sStartStopBitField
) * 8
404 && (sStartStopBitField
[absevent
>> 5] & bit
) ) {
405 // Or in the START or END bits, Start = 1 & END = 2
406 // If sgnevent == 0 then START - 0 => START
407 // else if sgnevent == -1 then START - -1 => END
408 code
|= DBG_FUNC_START
- sgnevent
;
411 // Get first 8 characters of the name
412 while ( i
< sizeof(uintptr_t) && who
[i
] != 0)
413 { ((char *)&name
)[sizeof(uintptr_t)-i
-1]=who
[i
]; i
++; }
414 // Record the timestamp.
415 IOTimeStampConstant(code
, name
, event
, param1
, param2
);
421 //*********************************************************************************
422 // PMInstantiatePowerDomains
424 // In this vanilla implementation, a Root Power Domain is instantiated.
425 // All other objects which register will be children of this Root.
426 // Where this is inappropriate, PMInstantiatePowerDomains is overridden
427 // in a platform-specific subclass.
428 //*********************************************************************************
430 void IOPlatformExpert::PMInstantiatePowerDomains ( void )
432 root
= new IOPMrootDomain
;
439 //*********************************************************************************
442 // In this vanilla implementation, all callers are made children of the root power domain.
443 // Where this is inappropriate, PMRegisterDevice is overridden in a platform-specific subclass.
444 //*********************************************************************************
446 void IOPlatformExpert::PMRegisterDevice(IOService
* theNub
, IOService
* theDevice
)
448 root
->addPowerChild ( theDevice
);
451 //*********************************************************************************
454 //*********************************************************************************
456 bool IOPlatformExpert::hasPMFeature (unsigned long featureMask
)
458 return ((_pePMFeatures
& featureMask
) != 0);
461 //*********************************************************************************
464 //*********************************************************************************
466 bool IOPlatformExpert::hasPrivPMFeature (unsigned long privFeatureMask
)
468 return ((_pePrivPMFeatures
& privFeatureMask
) != 0);
471 //*********************************************************************************
472 // numBatteriesSupported
474 //*********************************************************************************
476 int IOPlatformExpert::numBatteriesSupported (void)
478 return (_peNumBatteriesSupported
);
481 //*********************************************************************************
484 // This method is called by the instantiated sublass of the platform expert to
485 // determine how a device should be inserted into the Power Domain. The subclass
486 // provides an XML power tree description against which a device is matched based
487 // on class and provider. If a match is found this routine returns true in addition
488 // to flagging the description tree at the appropriate node that a device has been
489 // registered for the given service.
490 //*********************************************************************************
492 bool IOPlatformExpert::CheckSubTree (OSArray
* inSubTree
, IOService
* theNub
, IOService
* theDevice
, OSDictionary
* theParent
)
495 unsigned int numPowerTreeNodes
;
496 OSDictionary
* entry
;
497 OSDictionary
* matchingDictionary
;
498 OSDictionary
* providerDictionary
;
499 OSDictionary
* deviceDictionary
;
500 OSDictionary
* nubDictionary
;
502 bool nodeFound
= false;
503 bool continueSearch
= false;
504 bool deviceMatch
= false;
505 bool providerMatch
= false;
506 bool multiParentMatch
= false;
508 if ( (NULL
== theDevice
) || (NULL
== inSubTree
) )
511 numPowerTreeNodes
= inSubTree
->getCount ();
513 // iterate through the power tree to find a home for this device
515 for ( i
= 0; i
< numPowerTreeNodes
; i
++ ) {
517 entry
= (OSDictionary
*) inSubTree
->getObject (i
);
519 matchingDictionary
= (OSDictionary
*) entry
->getObject ("device");
520 providerDictionary
= (OSDictionary
*) entry
->getObject ("provider");
522 deviceMatch
= true; // if no matching dictionary, this is not a criteria and so must match
523 if ( matchingDictionary
) {
525 if ( NULL
!= (deviceDictionary
= theDevice
->dictionaryWithProperties ())) {
526 deviceMatch
= deviceDictionary
->isEqualTo ( matchingDictionary
, matchingDictionary
);
527 deviceDictionary
->release ();
531 providerMatch
= true; // we indicate a match if there is no nub or provider
532 if ( theNub
&& providerDictionary
) {
533 providerMatch
= false;
534 if ( NULL
!= (nubDictionary
= theNub
->dictionaryWithProperties ()) ) {
535 providerMatch
= nubDictionary
->isEqualTo ( providerDictionary
, providerDictionary
);
536 nubDictionary
->release ();
540 multiParentMatch
= true; // again we indicate a match if there is no multi-parent node
541 if (deviceMatch
&& providerMatch
) {
542 if (NULL
!= multipleParentKeyValue
) {
543 OSNumber
* aNumber
= (OSNumber
*) entry
->getObject ("multiple-parent");
544 multiParentMatch
= (NULL
!= aNumber
) ? multipleParentKeyValue
->isEqualTo (aNumber
) : false;
548 nodeFound
= (deviceMatch
&& providerMatch
&& multiParentMatch
);
550 // if the power tree specifies a provider dictionary but theNub is
551 // NULL then we cannot match with this entry.
553 if ( theNub
== NULL
&& providerDictionary
!= NULL
)
556 // if this node is THE ONE...then register the device
559 if (RegisterServiceInTree (theDevice
, entry
, theParent
, theNub
) ) {
561 if ( kIOLogPower
& gIOKitDebug
)
562 IOLog ("PMRegisterDevice/CheckSubTree - service registered!\n");
564 numInstancesRegistered
++;
566 // determine if we need to search for additional nodes for this item
567 multipleParentKeyValue
= (OSNumber
*) entry
->getObject ("multiple-parent");
573 continueSearch
= ( (false == nodeFound
) || (NULL
!= multipleParentKeyValue
) );
575 if ( continueSearch
&& (NULL
!= (children
= (OSArray
*) entry
->getObject ("children"))) ) {
576 nodeFound
= CheckSubTree ( children
, theNub
, theDevice
, entry
);
577 continueSearch
= ( (false == nodeFound
) || (NULL
!= multipleParentKeyValue
) );
580 if ( false == continueSearch
)
584 return ( nodeFound
);
587 //*********************************************************************************
588 // RegisterServiceInTree
590 // Register a device at the specified node of our power tree.
591 //*********************************************************************************
593 bool IOPlatformExpert::RegisterServiceInTree (IOService
* theService
, OSDictionary
* theTreeNode
, OSDictionary
* theTreeParentNode
, IOService
* theProvider
)
595 IOService
* aService
;
596 bool registered
= false;
598 unsigned int numChildren
;
599 OSDictionary
* child
;
601 // make sure someone is not already registered here
603 if ( NULL
== theTreeNode
->getObject ("service") ) {
605 if ( theTreeNode
->setObject ("service", OSDynamicCast ( OSObject
, theService
)) ) {
607 // 1. CHILDREN ------------------
609 // we registered the node in the tree...now if the node has children
610 // registered we must tell this service to add them.
612 if ( NULL
!= (children
= (OSArray
*) theTreeNode
->getObject ("children")) ) {
613 numChildren
= children
->getCount ();
614 for ( unsigned int i
= 0; i
< numChildren
; i
++ ) {
615 if ( NULL
!= (child
= (OSDictionary
*) children
->getObject (i
)) ) {
616 if ( NULL
!= (aService
= (IOService
*) child
->getObject ("service")) )
617 theService
->addPowerChild (aService
);
622 // 2. PARENT --------------------
624 // also we must notify the parent of this node (if a registered service
625 // exists there) of a new child.
627 if ( theTreeParentNode
) {
628 if ( NULL
!= (aService
= (IOService
*) theTreeParentNode
->getObject ("service")) )
629 if (aService
!= theProvider
)
630 aService
->addPowerChild (theService
);
640 //*********************************************************************************
641 // printDictionaryKeys
643 // Print the keys for the given dictionary and selected contents.
644 //*********************************************************************************
645 void printDictionaryKeys (OSDictionary
* inDictionary
, char * inMsg
)
647 OSCollectionIterator
* mcoll
= OSCollectionIterator::withCollection (inDictionary
);
654 mkey
= OSDynamicCast (OSSymbol
, mcoll
->getNextObject ());
658 // kprintf ("dictionary key #%d: %s\n", i, mkey->getCStringNoCopy () );
660 // if this is the IOClass key, print it's contents
662 if ( mkey
->isEqualTo ("IOClass") ) {
663 ioClass
= (OSString
*) inDictionary
->getObject ("IOClass");
664 if ( ioClass
) IOLog ("%s IOClass is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
667 // if this is an IOProviderClass key print it
669 if ( mkey
->isEqualTo ("IOProviderClass") ) {
670 ioClass
= (OSString
*) inDictionary
->getObject ("IOProviderClass");
671 if ( ioClass
) IOLog ("%s IOProviderClass is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
675 // also print IONameMatch keys
676 if ( mkey
->isEqualTo ("IONameMatch") ) {
677 ioClass
= (OSString
*) inDictionary
->getObject ("IONameMatch");
678 if ( ioClass
) IOLog ("%s IONameMatch is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
681 // also print IONameMatched keys
683 if ( mkey
->isEqualTo ("IONameMatched") ) {
684 ioClass
= (OSString
*) inDictionary
->getObject ("IONameMatched");
685 if ( ioClass
) IOLog ("%s IONameMatched is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
691 if ( mkey
->isEqualTo ("AAPL,clock-id") ) {
693 cstr
= getCStringForObject (inDictionary
->getObject ("AAPL,clock-id"));
695 kprintf (" ===> AAPL,clock-id is %s\n", cstr
);
701 if ( mkey
->isEqualTo ("name") ) {
704 getCStringForObject(inDictionary
->getObject("name"), nameStr
,
706 if (strlen(nameStr
) > 0)
707 IOLog ("%s name is %s\n", inMsg
, nameStr
);
710 mkey
= (OSSymbol
*) mcoll
->getNextObject ();
719 getCStringForObject(OSObject
*inObj
, char *outStr
, size_t outStrLen
)
724 if ( (NULL
== inObj
) || (NULL
== outStr
))
727 char * objString
= (char *) (inObj
->getMetaClass())->getClassName();
729 if ((0 == strncmp(objString
, "OSString", sizeof("OSString"))) ||
730 (0 == strncmp(objString
, "OSSymbol", sizeof("OSSymbol"))))
731 strlcpy(outStr
, ((OSString
*)inObj
)->getCStringNoCopy(), outStrLen
);
733 else if (0 == strncmp(objString
, "OSData", sizeof("OSData"))) {
734 len
= ((OSData
*)inObj
)->getLength();
735 buffer
= (char *)((OSData
*)inObj
)->getBytesNoCopy();
736 if (buffer
&& (len
> 0)) {
737 for (i
=0; i
< len
; i
++) {
738 outStr
[i
] = buffer
[i
];
745 /* IOShutdownNotificationsTimedOut
746 * - Called from a timer installed by PEHaltRestart
748 static void IOShutdownNotificationsTimedOut(
749 thread_call_param_t p0
,
750 thread_call_param_t p1
)
752 #ifdef CONFIG_EMBEDDED
753 /* 30 seconds has elapsed - panic */
754 panic("Halt/Restart Timed Out");
756 #else /* ! CONFIG_EMBEDDED */
757 int type
= (int)(long)p0
;
759 /* 30 seconds has elapsed - resume shutdown */
760 if(gIOPlatform
) gIOPlatform
->haltRestart(type
);
761 #endif /* CONFIG_EMBEDDED */
768 * Callouts from BSD for machine name & model
771 boolean_t
PEGetMachineName( char * name
, int maxLength
)
774 return( gIOPlatform
->getMachineName( name
, maxLength
));
779 boolean_t
PEGetModelName( char * name
, int maxLength
)
782 return( gIOPlatform
->getModelName( name
, maxLength
));
787 int PEGetPlatformEpoch(void)
790 return( gIOPlatform
->getBootROMType());
795 int PEHaltRestart(unsigned int type
)
797 IOPMrootDomain
*pmRootDomain
;
798 AbsoluteTime deadline
;
799 thread_call_t shutdown_hang
;
801 if(type
== kPEHaltCPU
|| type
== kPERestartCPU
|| type
== kPEUPSDelayHaltCPU
)
803 pmRootDomain
= IOService::getPMRootDomain();
804 /* Notify IOKit PM clients of shutdown/restart
805 Clients subscribe to this message with a call to
806 IOService::registerInterest()
809 /* Spawn a thread that will panic in 30 seconds.
810 If all goes well the machine will be off by the time
813 shutdown_hang
= thread_call_allocate( &IOShutdownNotificationsTimedOut
,
814 (thread_call_param_t
) type
);
815 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
816 thread_call_enter1_delayed( shutdown_hang
, 0, deadline
);
818 pmRootDomain
->handlePlatformHaltRestart(type
);
819 /* This notification should have few clients who all do
820 their work synchronously.
822 In this "shutdown notification" context we don't give
823 drivers the option of working asynchronously and responding
824 later. PM internals make it very hard to wait for asynchronous
829 if (gIOPlatform
) return gIOPlatform
->haltRestart(type
);
833 UInt32
PESavePanicInfo(UInt8
*buffer
, UInt32 length
)
835 if (gIOPlatform
!= 0) return gIOPlatform
->savePanicInfo(buffer
, length
);
841 inline static int init_gIOOptionsEntry(void)
843 IORegistryEntry
*entry
;
845 volatile void **options
;
851 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
855 nvram_entry
= (void *) OSDynamicCast(IODTNVRAM
, entry
);
859 options
= (volatile void **) &gIOOptionsEntry
;
860 if (!OSCompareAndSwapPtr(NULL
, nvram_entry
, options
)) {
873 /* pass in a NULL value if you just want to figure out the len */
874 boolean_t
PEReadNVRAMProperty(const char *symbol
, void *value
,
884 if (init_gIOOptionsEntry() < 0)
890 obj
= gIOOptionsEntry
->getProperty(symbol
);
894 /* convert to data */
895 data
= OSDynamicCast(OSData
, obj
);
899 *len
= data
->getLength();
900 vlen
= min(vlen
, *len
);
902 memcpy((void *) value
, data
->getBytesNoCopy(), vlen
);
911 boolean_t
PEWriteNVRAMProperty(const char *symbol
, const void *value
,
912 const unsigned int len
)
918 if (!symbol
|| !value
|| !len
)
921 if (init_gIOOptionsEntry() < 0)
924 sym
= OSSymbol::withCStringNoCopy(symbol
);
928 data
= OSData::withBytes((void *) value
, len
);
932 ret
= gIOOptionsEntry
->setProperty(sym
, data
);
939 gIOOptionsEntry
->sync();
948 long PEGetGMTTimeOfDay(void)
952 if( gIOPlatform
) result
= gIOPlatform
->getGMTTimeOfDay();
957 void PESetGMTTimeOfDay(long secs
)
959 if( gIOPlatform
) gIOPlatform
->setGMTTimeOfDay(secs
);
964 void IOPlatformExpert::registerNVRAMController(IONVRAMController
* caller
)
967 IORegistryEntry
* entry
;
968 OSString
* string
= 0;
972 entry
= IORegistryEntry::fromPath( "/chosen", gIODTPlane
);
977 data1
= OSDynamicCast( OSData
, entry
->getProperty( "unique-chip-id" ) );
978 if ( data1
&& data1
->getLength( ) == 8 )
982 data2
= OSDynamicCast( OSData
, entry
->getProperty( "chip-id" ) );
983 if ( data2
&& data2
->getLength( ) == 4 )
986 uint8_t digest
[ SHA_DIGEST_LENGTH
];
987 const uuid_t space
= { 0xA6, 0xDD, 0x4C, 0xCB, 0xB5, 0xE8, 0x4A, 0xF5, 0xAC, 0xDD, 0xB6, 0xDC, 0x6A, 0x05, 0x42, 0xB8 };
989 SHA1Init( &context
);
990 SHA1Update( &context
, space
, sizeof( space
) );
991 SHA1Update( &context
, data1
->getBytesNoCopy( ), data1
->getLength( ) );
992 SHA1Update( &context
, data2
->getBytesNoCopy( ), data2
->getLength( ) );
993 SHA1Final( digest
, &context
);
995 digest
[ 6 ] = ( digest
[ 6 ] & 0x0F ) | 0x50;
996 digest
[ 8 ] = ( digest
[ 8 ] & 0x3F ) | 0x80;
998 uuid_unparse( digest
, uuid
);
999 string
= OSString::withCString( uuid
);
1005 #else /* !CONFIG_EMBEDDED */
1006 entry
= IORegistryEntry::fromPath( "/efi/platform", gIODTPlane
);
1009 data
= OSDynamicCast( OSData
, entry
->getProperty( "system-id" ) );
1010 if ( data
&& data
->getLength( ) == 16 )
1013 uint8_t digest
[ SHA_DIGEST_LENGTH
];
1014 const uuid_t space
= { 0x2A, 0x06, 0x19, 0x90, 0xD3, 0x8D, 0x44, 0x40, 0xA1, 0x39, 0xC4, 0x97, 0x70, 0x37, 0x65, 0xAC };
1016 SHA1Init( &context
);
1017 SHA1Update( &context
, space
, sizeof( space
) );
1018 SHA1Update( &context
, data
->getBytesNoCopy( ), data
->getLength( ) );
1019 SHA1Final( digest
, &context
);
1021 digest
[ 6 ] = ( digest
[ 6 ] & 0x0F ) | 0x50;
1022 digest
[ 8 ] = ( digest
[ 8 ] & 0x3F ) | 0x80;
1024 uuid_unparse( digest
, uuid
);
1025 string
= OSString::withCString( uuid
);
1030 #endif /* !CONFIG_EMBEDDED */
1034 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
1037 data
= OSDynamicCast( OSData
, entry
->getProperty( "platform-uuid" ) );
1038 if ( data
&& data
->getLength( ) == sizeof( uuid_t
) )
1040 uuid_unparse( ( uint8_t * ) data
->getBytesNoCopy( ), uuid
);
1041 string
= OSString::withCString( uuid
);
1050 getProvider( )->setProperty( kIOPlatformUUIDKey
, string
);
1051 publishResource( kIOPlatformUUIDKey
, string
);
1056 publishResource("IONVRAM");
1059 IOReturn
IOPlatformExpert::callPlatformFunction(const OSSymbol
*functionName
,
1060 bool waitForFunction
,
1061 void *param1
, void *param2
,
1062 void *param3
, void *param4
)
1064 IOService
*service
, *_resources
;
1066 if (waitForFunction
) {
1067 _resources
= waitForService(resourceMatching(functionName
));
1069 _resources
= getResourceService();
1071 if (_resources
== 0) return kIOReturnUnsupported
;
1073 service
= OSDynamicCast(IOService
, _resources
->getProperty(functionName
));
1074 if (service
== 0) return kIOReturnUnsupported
;
1076 return service
->callPlatformFunction(functionName
, waitForFunction
,
1077 param1
, param2
, param3
, param4
);
1080 IOByteCount
IOPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1085 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1088 #define super IOPlatformExpert
1090 OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert
, IOPlatformExpert
)
1092 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 0);
1093 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 1);
1094 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 2);
1095 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 3);
1096 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 4);
1097 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 5);
1098 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 6);
1099 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 7);
1101 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1103 IOService
* IODTPlatformExpert::probe( IOService
* provider
,
1106 if( !super::probe( provider
, score
))
1109 // check machine types
1110 if( !provider
->compareNames( getProperty( gIONameMatchKey
) ))
1116 bool IODTPlatformExpert::configure( IOService
* provider
)
1118 if( !super::configure( provider
))
1121 processTopLevel( provider
);
1126 IOService
* IODTPlatformExpert::createNub( IORegistryEntry
* from
)
1130 nub
= new IOPlatformDevice
;
1132 if( !nub
->init( from
, gIODTPlane
)) {
1140 bool IODTPlatformExpert::createNubs( IOService
* parent
, OSIterator
* iter
)
1142 IORegistryEntry
* next
;
1147 while( (next
= (IORegistryEntry
*) iter
->getNextObject())) {
1149 if( 0 == (nub
= createNub( next
)))
1152 nub
->attach( parent
);
1153 nub
->registerService();
1161 void IODTPlatformExpert::processTopLevel( IORegistryEntry
* rootEntry
)
1164 IORegistryEntry
* next
;
1165 IORegistryEntry
* cpus
;
1166 IORegistryEntry
* options
;
1169 kids
= IODTFindMatchingEntries( rootEntry
, 0, deleteList() );
1171 while( (next
= (IORegistryEntry
*)kids
->getNextObject())) {
1172 next
->detachAll( gIODTPlane
);
1177 // Publish an IODTNVRAM class on /options.
1178 options
= rootEntry
->childFromPath("options", gIODTPlane
);
1180 dtNVRAM
= new IODTNVRAM
;
1182 if (!dtNVRAM
->init(options
, gIODTPlane
)) {
1186 dtNVRAM
->attach(this);
1187 dtNVRAM
->registerService();
1192 // Publish the cpus.
1193 cpus
= rootEntry
->childFromPath( "cpus", gIODTPlane
);
1195 createNubs( this, IODTFindMatchingEntries( cpus
, kIODTExclusive
, 0));
1197 // publish top level, minus excludeList
1198 createNubs( this, IODTFindMatchingEntries( rootEntry
, kIODTExclusive
, excludeList()));
1201 IOReturn
IODTPlatformExpert::getNubResources( IOService
* nub
)
1203 if( nub
->getDeviceMemory())
1204 return( kIOReturnSuccess
);
1206 IODTResolveAddressing( nub
, "reg", 0);
1208 return( kIOReturnSuccess
);
1211 bool IODTPlatformExpert::compareNubName( const IOService
* nub
,
1212 OSString
* name
, OSString
** matched
) const
1214 return( IODTCompareNubName( nub
, name
, matched
)
1215 || super::compareNubName( nub
, name
, matched
) );
1218 bool IODTPlatformExpert::getModelName( char * name
, int maxLength
)
1228 prop
= (OSData
*) getProvider()->getProperty( gIODTCompatibleKey
);
1230 str
= (const char *) prop
->getBytesNoCopy();
1232 if( 0 == strncmp( str
, "AAPL,", strlen( "AAPL," ) ))
1233 str
+= strlen( "AAPL," );
1236 while( (c
= *str
++)) {
1237 if( (c
== '/') || (c
== ' '))
1241 if( len
>= maxLength
)
1251 bool IODTPlatformExpert::getMachineName( char * name
, int maxLength
)
1257 prop
= (OSData
*) getProvider()->getProperty( gIODTModelKey
);
1261 strlcpy( name
, (const char *) prop
->getBytesNoCopy(), maxLength
);
1266 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1268 void IODTPlatformExpert::registerNVRAMController( IONVRAMController
* nvram
)
1270 if (dtNVRAM
) dtNVRAM
->registerNVRAMController(nvram
);
1272 super::registerNVRAMController(nvram
);
1275 int IODTPlatformExpert::haltRestart(unsigned int type
)
1277 if (dtNVRAM
) dtNVRAM
->sync();
1279 return super::haltRestart(type
);
1282 IOReturn
IODTPlatformExpert::readXPRAM(IOByteCount offset
, UInt8
* buffer
,
1285 if (dtNVRAM
) return dtNVRAM
->readXPRAM(offset
, buffer
, length
);
1286 else return kIOReturnNotReady
;
1289 IOReturn
IODTPlatformExpert::writeXPRAM(IOByteCount offset
, UInt8
* buffer
,
1292 if (dtNVRAM
) return dtNVRAM
->writeXPRAM(offset
, buffer
, length
);
1293 else return kIOReturnNotReady
;
1296 IOReturn
IODTPlatformExpert::readNVRAMProperty(
1297 IORegistryEntry
* entry
,
1298 const OSSymbol
** name
, OSData
** value
)
1300 if (dtNVRAM
) return dtNVRAM
->readNVRAMProperty(entry
, name
, value
);
1301 else return kIOReturnNotReady
;
1304 IOReturn
IODTPlatformExpert::writeNVRAMProperty(
1305 IORegistryEntry
* entry
,
1306 const OSSymbol
* name
, OSData
* value
)
1308 if (dtNVRAM
) return dtNVRAM
->writeNVRAMProperty(entry
, name
, value
);
1309 else return kIOReturnNotReady
;
1312 OSDictionary
*IODTPlatformExpert::getNVRAMPartitions(void)
1314 if (dtNVRAM
) return dtNVRAM
->getNVRAMPartitions();
1318 IOReturn
IODTPlatformExpert::readNVRAMPartition(const OSSymbol
* partitionID
,
1319 IOByteCount offset
, UInt8
* buffer
,
1322 if (dtNVRAM
) return dtNVRAM
->readNVRAMPartition(partitionID
, offset
,
1324 else return kIOReturnNotReady
;
1327 IOReturn
IODTPlatformExpert::writeNVRAMPartition(const OSSymbol
* partitionID
,
1328 IOByteCount offset
, UInt8
* buffer
,
1331 if (dtNVRAM
) return dtNVRAM
->writeNVRAMPartition(partitionID
, offset
,
1333 else return kIOReturnNotReady
;
1336 IOByteCount
IODTPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1338 IOByteCount lengthSaved
= 0;
1340 if (dtNVRAM
) lengthSaved
= dtNVRAM
->savePanicInfo(buffer
, length
);
1342 if (lengthSaved
== 0) lengthSaved
= super::savePanicInfo(buffer
, length
);
1347 OSString
* IODTPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
) {
1348 UInt8
* serialNumber
;
1349 unsigned int serialNumberSize
;
1350 unsigned short pos
= 0;
1354 if (myProperty
!= NULL
) {
1355 serialNumberSize
= myProperty
->getLength();
1356 serialNumber
= (UInt8
*)(myProperty
->getBytesNoCopy());
1357 temp
= (char*)serialNumber
;
1358 if (serialNumberSize
> 0) {
1359 // check to see if this is a CTO serial number...
1360 while (pos
< serialNumberSize
&& temp
[pos
] != '-') pos
++;
1362 if (pos
< serialNumberSize
) { // there was a hyphen, so it's a CTO serial number
1363 memcpy(SerialNo
, serialNumber
+ 12, 8);
1364 memcpy(&SerialNo
[8], serialNumber
, 3);
1366 memcpy(&SerialNo
[12], serialNumber
+ 3, 8);
1368 } else { // just a normal serial number
1369 memcpy(SerialNo
, serialNumber
+ 13, 8);
1370 memcpy(&SerialNo
[8], serialNumber
, 3);
1373 return OSString::withCString(SerialNo
);
1380 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1383 #define super IOService
1385 OSDefineMetaClassAndStructors(IOPlatformExpertDevice
, IOService
)
1387 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 0);
1388 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 1);
1389 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 2);
1390 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 3);
1392 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1394 bool IOPlatformExpertDevice::compareName( OSString
* name
,
1395 OSString
** matched
) const
1397 return( IODTCompareNubName( this, name
, matched
));
1401 IOPlatformExpertDevice::initWithArgs(
1402 void * dtTop
, void * p2
, void * p3
, void * p4
)
1404 IORegistryEntry
* dt
= 0;
1405 void * argsData
[ 4 ];
1408 // dtTop may be zero on non- device tree systems
1409 if( dtTop
&& (dt
= IODeviceTreeAlloc( dtTop
)))
1410 ok
= super::init( dt
, gIODTPlane
);
1417 workLoop
= IOWorkLoop::workLoop();
1421 argsData
[ 0 ] = dtTop
;
1426 setProperty("IOPlatformArgs", (void *)argsData
, sizeof(argsData
));
1431 IOWorkLoop
*IOPlatformExpertDevice::getWorkLoop() const
1436 IOReturn
IOPlatformExpertDevice::setProperties( OSObject
* properties
)
1438 OSDictionary
* dictionary
;
1442 status
= super::setProperties( properties
);
1443 if ( status
!= kIOReturnUnsupported
) return status
;
1445 status
= IOUserClient::clientHasPrivilege( current_task( ), kIOClientPrivilegeAdministrator
);
1446 if ( status
!= kIOReturnSuccess
) return status
;
1448 dictionary
= OSDynamicCast( OSDictionary
, properties
);
1449 if ( dictionary
== 0 ) return kIOReturnBadArgument
;
1451 object
= dictionary
->getObject( kIOPlatformUUIDKey
);
1454 IORegistryEntry
* entry
;
1458 string
= ( OSString
* ) getProperty( kIOPlatformUUIDKey
);
1459 if ( string
) return kIOReturnNotPermitted
;
1461 string
= OSDynamicCast( OSString
, object
);
1462 if ( string
== 0 ) return kIOReturnBadArgument
;
1464 status
= uuid_parse( string
->getCStringNoCopy( ), uuid
);
1465 if ( status
!= 0 ) return kIOReturnBadArgument
;
1467 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
1470 entry
->setProperty( "platform-uuid", uuid
, sizeof( uuid_t
) );
1474 setProperty( kIOPlatformUUIDKey
, string
);
1475 publishResource( kIOPlatformUUIDKey
, string
);
1477 return kIOReturnSuccess
;
1480 return kIOReturnUnsupported
;
1483 void IOPlatformExpertDevice::free()
1486 workLoop
->release();
1489 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1492 #define super IOService
1494 OSDefineMetaClassAndStructors(IOPlatformDevice
, IOService
)
1496 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 0);
1497 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 1);
1498 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 2);
1499 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 3);
1501 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1503 bool IOPlatformDevice::compareName( OSString
* name
,
1504 OSString
** matched
) const
1506 return( ((IOPlatformExpert
*)getProvider())->
1507 compareNubName( this, name
, matched
));
1510 IOService
* IOPlatformDevice::matchLocation( IOService
* /* client */ )
1515 IOReturn
IOPlatformDevice::getResources( void )
1517 return( ((IOPlatformExpert
*)getProvider())->getNubResources( this ));
1520 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1522 /*********************************************************************
1523 * IOPanicPlatform class
1525 * If no legitimate IOPlatformDevice matches, this one does and panics
1526 * the kernel with a suitable message.
1527 *********************************************************************/
1529 class IOPanicPlatform
: IOPlatformExpert
{
1530 OSDeclareDefaultStructors(IOPanicPlatform
);
1533 bool start(IOService
* provider
);
1537 OSDefineMetaClassAndStructors(IOPanicPlatform
, IOPlatformExpert
);
1540 bool IOPanicPlatform::start(IOService
* provider
) {
1541 const char * platform_name
= "(unknown platform name)";
1543 if (provider
) platform_name
= provider
->getName();
1545 panic("Unable to find driver for this platform: \"%s\".\n",