2 * Copyright (c) 1998-2008 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@
32 #include <IOKit/IOCPU.h>
33 #include <IOKit/IODeviceTreeSupport.h>
34 #include <IOKit/IOKitDebug.h>
35 #include <IOKit/IOMapper.h>
36 #include <IOKit/IOMessage.h>
37 #include <IOKit/IONVRAM.h>
38 #include <IOKit/IOPlatformExpert.h>
39 #include <IOKit/IORangeAllocator.h>
40 #include <IOKit/IOWorkLoop.h>
41 #include <IOKit/pwr_mgt/RootDomain.h>
42 #include <IOKit/IOKitKeys.h>
43 #include <IOKit/IOTimeStamp.h>
44 #include <IOKit/IOUserClient.h>
46 #include <IOKit/system.h>
48 #include <libkern/c++/OSContainers.h>
49 #include <libkern/crypto/sha1.h>
52 #include <machine/machine_routines.h>
53 #include <pexpert/pexpert.h>
54 #include <uuid/uuid.h>
57 void printDictionaryKeys (OSDictionary
* inDictionary
, char * inMsg
);
58 static void getCStringForObject(OSObject
*inObj
, char *outStr
, size_t outStrLen
);
60 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
62 #define super IOService
64 OSDefineMetaClassAndStructors(IOPlatformExpert
, IOService
)
66 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 0);
68 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 1);
69 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 2);
70 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 3);
71 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 4);
72 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 5);
73 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 6);
74 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 7);
75 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 8);
76 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 9);
77 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 10);
78 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 11);
80 static IOPlatformExpert
* gIOPlatform
;
81 static OSDictionary
* gIOInterruptControllers
;
82 static IOLock
* gIOInterruptControllersLock
;
84 OSSymbol
* gPlatformInterruptControllerName
;
86 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
88 bool IOPlatformExpert::attach( IOService
* provider
)
91 if( !super::attach( provider
))
97 bool IOPlatformExpert::start( IOService
* provider
)
99 IORangeAllocator
* physicalRanges
;
100 OSData
* busFrequency
;
103 if (!super::start(provider
))
106 // Override the mapper present flag is requested by boot arguments.
107 if (PE_parse_boot_argn("dart", &debugFlags
, sizeof (debugFlags
)) && (debugFlags
== 0))
108 removeProperty(kIOPlatformMapperPresentKey
);
110 // Register the presence or lack thereof a system
111 // PCI address mapper with the IOMapper class
112 IOMapper::setMapperRequired(0 != getProperty(kIOPlatformMapperPresentKey
));
114 gIOInterruptControllers
= OSDictionary::withCapacity(1);
115 gIOInterruptControllersLock
= IOLockAlloc();
117 // Correct the bus frequency in the device tree.
118 busFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.bus_clock_rate_hz
, 4);
119 provider
->setProperty("clock-frequency", busFrequency
);
120 busFrequency
->release();
122 gPlatformInterruptControllerName
= (OSSymbol
*)OSSymbol::withCStringNoCopy("IOPlatformInterruptController");
124 physicalRanges
= IORangeAllocator::withRange(0xffffffff, 1, 16,
125 IORangeAllocator::kLocking
);
126 assert(physicalRanges
);
127 setProperty("Platform Memory Ranges", physicalRanges
);
132 PMInstantiatePowerDomains();
134 // Parse the serial-number data and publish a user-readable string
135 OSData
* mydata
= (OSData
*) (provider
->getProperty("serial-number"));
136 if (mydata
!= NULL
) {
137 OSString
*serNoString
= createSystemSerialNumberString(mydata
);
138 if (serNoString
!= NULL
) {
139 provider
->setProperty(kIOPlatformSerialNumberKey
, serNoString
);
140 serNoString
->release();
144 return( configure(provider
) );
147 bool IOPlatformExpert::configure( IOService
* provider
)
153 topLevel
= OSDynamicCast( OSSet
, getProperty("top-level"));
156 while( (dict
= OSDynamicCast( OSDictionary
,
157 topLevel
->getAnyObject()))) {
159 topLevel
->removeObject( dict
);
160 nub
= createNub( dict
);
165 nub
->registerService();
172 IOService
* IOPlatformExpert::createNub( OSDictionary
* from
)
176 nub
= new IOPlatformDevice
;
178 if( !nub
->init( from
)) {
186 bool IOPlatformExpert::compareNubName( const IOService
* nub
,
187 OSString
* name
, OSString
** matched
) const
189 return( nub
->IORegistryEntry::compareName( name
, matched
));
192 IOReturn
IOPlatformExpert::getNubResources( IOService
* nub
)
194 return( kIOReturnSuccess
);
197 long IOPlatformExpert::getBootROMType(void)
199 return _peBootROMType
;
202 long IOPlatformExpert::getChipSetType(void)
204 return _peChipSetType
;
207 long IOPlatformExpert::getMachineType(void)
209 return _peMachineType
;
212 void IOPlatformExpert::setBootROMType(long peBootROMType
)
214 _peBootROMType
= peBootROMType
;
217 void IOPlatformExpert::setChipSetType(long peChipSetType
)
219 _peChipSetType
= peChipSetType
;
222 void IOPlatformExpert::setMachineType(long peMachineType
)
224 _peMachineType
= peMachineType
;
227 bool IOPlatformExpert::getMachineName( char * /*name*/, int /*maxLength*/)
232 bool IOPlatformExpert::getModelName( char * /*name*/, int /*maxLength*/)
237 OSString
* IOPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
)
242 IORangeAllocator
* IOPlatformExpert::getPhysicalRangeAllocator(void)
244 return(OSDynamicCast(IORangeAllocator
,
245 getProperty("Platform Memory Ranges")));
248 int (*PE_halt_restart
)(unsigned int type
) = 0;
250 int IOPlatformExpert::haltRestart(unsigned int type
)
252 if (type
== kPEPanicSync
) return 0;
254 if (type
== kPEHangCPU
) while (true) {}
256 if (type
== kPEUPSDelayHaltCPU
) {
257 // RestartOnPowerLoss feature was turned on, proceed with shutdown.
261 // On ARM kPEPanicRestartCPU is supported in the drivers
262 if (type
== kPEPanicRestartCPU
)
263 type
= kPERestartCPU
;
265 if (PE_halt_restart
) return (*PE_halt_restart
)(type
);
269 void IOPlatformExpert::sleepKernel(void)
275 intState
= ml_set_interrupts_enabled(false);
277 for (cnt
= 0; cnt
< 10000; cnt
++) {
281 ml_set_interrupts_enabled(intState
);
283 // PE_initialize_console(0, kPEDisableScreen);
287 // PE_initialize_console(0, kPEEnableScreen);
291 long IOPlatformExpert::getGMTTimeOfDay(void)
296 void IOPlatformExpert::setGMTTimeOfDay(long secs
)
301 IOReturn
IOPlatformExpert::getConsoleInfo( PE_Video
* consoleInfo
)
303 return( PE_current_console( consoleInfo
));
306 IOReturn
IOPlatformExpert::setConsoleInfo( PE_Video
* consoleInfo
,
309 return( PE_initialize_console( consoleInfo
, op
));
312 IOReturn
IOPlatformExpert::registerInterruptController(OSSymbol
*name
, IOInterruptController
*interruptController
)
314 IOLockLock(gIOInterruptControllersLock
);
316 gIOInterruptControllers
->setObject(name
, interruptController
);
318 IOLockWakeup(gIOInterruptControllersLock
,
319 gIOInterruptControllers
, /* one-thread */ false);
321 IOLockUnlock(gIOInterruptControllersLock
);
323 return kIOReturnSuccess
;
326 IOInterruptController
*IOPlatformExpert::lookUpInterruptController(OSSymbol
*name
)
330 IOLockLock(gIOInterruptControllersLock
);
333 object
= gIOInterruptControllers
->getObject(name
);
338 IOLockSleep(gIOInterruptControllersLock
,
339 gIOInterruptControllers
, THREAD_UNINT
);
342 IOLockUnlock(gIOInterruptControllersLock
);
343 return OSDynamicCast(IOInterruptController
, object
);
347 void IOPlatformExpert::setCPUInterruptProperties(IOService
*service
)
349 IOCPUInterruptController
*controller
;
351 controller
= OSDynamicCast(IOCPUInterruptController
, waitForService(serviceMatching("IOCPUInterruptController")));
352 if (controller
) controller
->setCPUInterruptProperties(service
);
355 bool IOPlatformExpert::atInterruptLevel(void)
357 return ml_at_interrupt_context();
360 bool IOPlatformExpert::platformAdjustService(IOService */
*service*/
)
366 //*********************************************************************************
369 //*********************************************************************************
371 void IOPlatformExpert::
372 PMLog(const char *who
, unsigned long event
,
373 unsigned long param1
, unsigned long param2
)
375 UInt32 debugFlags
= gIOKitDebug
;
377 if (debugFlags
& kIOLogPower
) {
381 clock_get_system_microtime(&nows
, &nowus
);
382 nowus
+= (nows
% 1000) * 1000000;
384 kprintf("pm%u %p %.30s %d %lx %lx\n",
385 nowus
, current_thread(), who
, // Identity
386 (int) event
, (long) param1
, (long) param2
); // Args
388 if (debugFlags
& kIOLogTracePower
) {
389 static const UInt32 sStartStopBitField
[] =
390 { 0x00000000, 0x00000040 }; // Only Program Hardware so far
392 // Arcane formula from Hacker's Delight by Warren
393 // abs(x) = ((int) x >> 31) ^ (x + ((int) x >> 31))
394 UInt32 sgnevent
= ((long) event
>> 31);
395 UInt32 absevent
= sgnevent
^ (event
+ sgnevent
);
396 UInt32 code
= IODBG_POWER(absevent
);
398 UInt32 bit
= 1 << (absevent
& 0x1f);
399 if (absevent
< sizeof(sStartStopBitField
) * 8
400 && (sStartStopBitField
[absevent
>> 5] & bit
) ) {
401 // Or in the START or END bits, Start = 1 & END = 2
402 // If sgnevent == 0 then START - 0 => START
403 // else if sgnevent == -1 then START - -1 => END
404 code
|= DBG_FUNC_START
- sgnevent
;
407 // Record the timestamp, wish I had a this pointer
408 IOTimeStampConstant(code
, (uintptr_t) who
, event
, param1
, param2
);
414 //*********************************************************************************
415 // PMInstantiatePowerDomains
417 // In this vanilla implementation, a Root Power Domain is instantiated.
418 // All other objects which register will be children of this Root.
419 // Where this is inappropriate, PMInstantiatePowerDomains is overridden
420 // in a platform-specific subclass.
421 //*********************************************************************************
423 void IOPlatformExpert::PMInstantiatePowerDomains ( void )
425 root
= new IOPMrootDomain
;
432 //*********************************************************************************
435 // In this vanilla implementation, all callers are made children of the root power domain.
436 // Where this is inappropriate, PMRegisterDevice is overridden in a platform-specific subclass.
437 //*********************************************************************************
439 void IOPlatformExpert::PMRegisterDevice(IOService
* theNub
, IOService
* theDevice
)
441 root
->addPowerChild ( theDevice
);
444 //*********************************************************************************
447 //*********************************************************************************
449 bool IOPlatformExpert::hasPMFeature (unsigned long featureMask
)
451 return ((_pePMFeatures
& featureMask
) != 0);
454 //*********************************************************************************
457 //*********************************************************************************
459 bool IOPlatformExpert::hasPrivPMFeature (unsigned long privFeatureMask
)
461 return ((_pePrivPMFeatures
& privFeatureMask
) != 0);
464 //*********************************************************************************
465 // numBatteriesSupported
467 //*********************************************************************************
469 int IOPlatformExpert::numBatteriesSupported (void)
471 return (_peNumBatteriesSupported
);
474 //*********************************************************************************
477 // This method is called by the instantiated sublass of the platform expert to
478 // determine how a device should be inserted into the Power Domain. The subclass
479 // provides an XML power tree description against which a device is matched based
480 // on class and provider. If a match is found this routine returns true in addition
481 // to flagging the description tree at the appropriate node that a device has been
482 // registered for the given service.
483 //*********************************************************************************
485 bool IOPlatformExpert::CheckSubTree (OSArray
* inSubTree
, IOService
* theNub
, IOService
* theDevice
, OSDictionary
* theParent
)
488 unsigned int numPowerTreeNodes
;
489 OSDictionary
* entry
;
490 OSDictionary
* matchingDictionary
;
491 OSDictionary
* providerDictionary
;
492 OSDictionary
* deviceDictionary
;
493 OSDictionary
* nubDictionary
;
495 bool nodeFound
= false;
496 bool continueSearch
= false;
497 bool deviceMatch
= false;
498 bool providerMatch
= false;
499 bool multiParentMatch
= false;
501 if ( (NULL
== theDevice
) || (NULL
== inSubTree
) )
504 numPowerTreeNodes
= inSubTree
->getCount ();
506 // iterate through the power tree to find a home for this device
508 for ( i
= 0; i
< numPowerTreeNodes
; i
++ ) {
510 entry
= (OSDictionary
*) inSubTree
->getObject (i
);
512 matchingDictionary
= (OSDictionary
*) entry
->getObject ("device");
513 providerDictionary
= (OSDictionary
*) entry
->getObject ("provider");
515 deviceMatch
= true; // if no matching dictionary, this is not a criteria and so must match
516 if ( matchingDictionary
) {
518 if ( NULL
!= (deviceDictionary
= theDevice
->dictionaryWithProperties ())) {
519 deviceMatch
= deviceDictionary
->isEqualTo ( matchingDictionary
, matchingDictionary
);
520 deviceDictionary
->release ();
524 providerMatch
= true; // we indicate a match if there is no nub or provider
525 if ( theNub
&& providerDictionary
) {
526 providerMatch
= false;
527 if ( NULL
!= (nubDictionary
= theNub
->dictionaryWithProperties ()) ) {
528 providerMatch
= nubDictionary
->isEqualTo ( providerDictionary
, providerDictionary
);
529 nubDictionary
->release ();
533 multiParentMatch
= true; // again we indicate a match if there is no multi-parent node
534 if (deviceMatch
&& providerMatch
) {
535 if (NULL
!= multipleParentKeyValue
) {
536 OSNumber
* aNumber
= (OSNumber
*) entry
->getObject ("multiple-parent");
537 multiParentMatch
= (NULL
!= aNumber
) ? multipleParentKeyValue
->isEqualTo (aNumber
) : false;
541 nodeFound
= (deviceMatch
&& providerMatch
&& multiParentMatch
);
543 // if the power tree specifies a provider dictionary but theNub is
544 // NULL then we cannot match with this entry.
546 if ( theNub
== NULL
&& providerDictionary
!= NULL
)
549 // if this node is THE ONE...then register the device
552 if (RegisterServiceInTree (theDevice
, entry
, theParent
, theNub
) ) {
554 if ( kIOLogPower
& gIOKitDebug
)
555 IOLog ("PMRegisterDevice/CheckSubTree - service registered!\n");
557 numInstancesRegistered
++;
559 // determine if we need to search for additional nodes for this item
560 multipleParentKeyValue
= (OSNumber
*) entry
->getObject ("multiple-parent");
566 continueSearch
= ( (false == nodeFound
) || (NULL
!= multipleParentKeyValue
) );
568 if ( continueSearch
&& (NULL
!= (children
= (OSArray
*) entry
->getObject ("children"))) ) {
569 nodeFound
= CheckSubTree ( children
, theNub
, theDevice
, entry
);
570 continueSearch
= ( (false == nodeFound
) || (NULL
!= multipleParentKeyValue
) );
573 if ( false == continueSearch
)
577 return ( nodeFound
);
580 //*********************************************************************************
581 // RegisterServiceInTree
583 // Register a device at the specified node of our power tree.
584 //*********************************************************************************
586 bool IOPlatformExpert::RegisterServiceInTree (IOService
* theService
, OSDictionary
* theTreeNode
, OSDictionary
* theTreeParentNode
, IOService
* theProvider
)
588 IOService
* aService
;
589 bool registered
= false;
591 unsigned int numChildren
;
592 OSDictionary
* child
;
594 // make sure someone is not already registered here
596 if ( NULL
== theTreeNode
->getObject ("service") ) {
598 if ( theTreeNode
->setObject ("service", OSDynamicCast ( OSObject
, theService
)) ) {
600 // 1. CHILDREN ------------------
602 // we registered the node in the tree...now if the node has children
603 // registered we must tell this service to add them.
605 if ( NULL
!= (children
= (OSArray
*) theTreeNode
->getObject ("children")) ) {
606 numChildren
= children
->getCount ();
607 for ( unsigned int i
= 0; i
< numChildren
; i
++ ) {
608 if ( NULL
!= (child
= (OSDictionary
*) children
->getObject (i
)) ) {
609 if ( NULL
!= (aService
= (IOService
*) child
->getObject ("service")) )
610 theService
->addPowerChild (aService
);
615 // 2. PARENT --------------------
617 // also we must notify the parent of this node (if a registered service
618 // exists there) of a new child.
620 if ( theTreeParentNode
) {
621 if ( NULL
!= (aService
= (IOService
*) theTreeParentNode
->getObject ("service")) )
622 if (aService
!= theProvider
)
623 aService
->addPowerChild (theService
);
633 //*********************************************************************************
634 // printDictionaryKeys
636 // Print the keys for the given dictionary and selected contents.
637 //*********************************************************************************
638 void printDictionaryKeys (OSDictionary
* inDictionary
, char * inMsg
)
640 OSCollectionIterator
* mcoll
= OSCollectionIterator::withCollection (inDictionary
);
647 mkey
= OSDynamicCast (OSSymbol
, mcoll
->getNextObject ());
651 // kprintf ("dictionary key #%d: %s\n", i, mkey->getCStringNoCopy () );
653 // if this is the IOClass key, print it's contents
655 if ( mkey
->isEqualTo ("IOClass") ) {
656 ioClass
= (OSString
*) inDictionary
->getObject ("IOClass");
657 if ( ioClass
) IOLog ("%s IOClass is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
660 // if this is an IOProviderClass key print it
662 if ( mkey
->isEqualTo ("IOProviderClass") ) {
663 ioClass
= (OSString
*) inDictionary
->getObject ("IOProviderClass");
664 if ( ioClass
) IOLog ("%s IOProviderClass is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
668 // also print IONameMatch keys
669 if ( mkey
->isEqualTo ("IONameMatch") ) {
670 ioClass
= (OSString
*) inDictionary
->getObject ("IONameMatch");
671 if ( ioClass
) IOLog ("%s IONameMatch is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
674 // also print IONameMatched keys
676 if ( mkey
->isEqualTo ("IONameMatched") ) {
677 ioClass
= (OSString
*) inDictionary
->getObject ("IONameMatched");
678 if ( ioClass
) IOLog ("%s IONameMatched is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
684 if ( mkey
->isEqualTo ("AAPL,clock-id") ) {
686 cstr
= getCStringForObject (inDictionary
->getObject ("AAPL,clock-id"));
688 kprintf (" ===> AAPL,clock-id is %s\n", cstr
);
694 if ( mkey
->isEqualTo ("name") ) {
697 getCStringForObject(inDictionary
->getObject("name"), nameStr
,
699 if (strlen(nameStr
) > 0)
700 IOLog ("%s name is %s\n", inMsg
, nameStr
);
703 mkey
= (OSSymbol
*) mcoll
->getNextObject ();
712 getCStringForObject(OSObject
*inObj
, char *outStr
, size_t outStrLen
)
717 if ( (NULL
== inObj
) || (NULL
== outStr
))
720 char * objString
= (char *) (inObj
->getMetaClass())->getClassName();
722 if ((0 == strncmp(objString
, "OSString", sizeof("OSString"))) ||
723 (0 == strncmp(objString
, "OSSymbol", sizeof("OSSymbol"))))
724 strlcpy(outStr
, ((OSString
*)inObj
)->getCStringNoCopy(), outStrLen
);
726 else if (0 == strncmp(objString
, "OSData", sizeof("OSData"))) {
727 len
= ((OSData
*)inObj
)->getLength();
728 buffer
= (char *)((OSData
*)inObj
)->getBytesNoCopy();
729 if (buffer
&& (len
> 0)) {
730 for (i
=0; i
< len
; i
++) {
731 outStr
[i
] = buffer
[i
];
738 /* IOShutdownNotificationsTimedOut
739 * - Called from a timer installed by PEHaltRestart
741 static void IOShutdownNotificationsTimedOut(
742 thread_call_param_t p0
,
743 thread_call_param_t p1
)
745 int type
= (int)(long)p0
;
747 /* 30 seconds has elapsed - resume shutdown */
748 if(gIOPlatform
) gIOPlatform
->haltRestart(type
);
755 * Callouts from BSD for machine name & model
758 boolean_t
PEGetMachineName( char * name
, int maxLength
)
761 return( gIOPlatform
->getMachineName( name
, maxLength
));
766 boolean_t
PEGetModelName( char * name
, int maxLength
)
769 return( gIOPlatform
->getModelName( name
, maxLength
));
774 int PEGetPlatformEpoch(void)
777 return( gIOPlatform
->getBootROMType());
782 int PEHaltRestart(unsigned int type
)
784 IOPMrootDomain
*pmRootDomain
= IOService::getPMRootDomain();
785 AbsoluteTime deadline
;
786 thread_call_t shutdown_hang
;
788 if(type
== kPEHaltCPU
|| type
== kPERestartCPU
|| type
== kPEUPSDelayHaltCPU
)
790 /* Notify IOKit PM clients of shutdown/restart
791 Clients subscribe to this message with a call to
792 IOService::registerInterest()
795 /* Spawn a thread that will panic in 30 seconds.
796 If all goes well the machine will be off by the time
799 shutdown_hang
= thread_call_allocate( &IOShutdownNotificationsTimedOut
,
800 (thread_call_param_t
) type
);
801 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
802 thread_call_enter1_delayed( shutdown_hang
, 0, deadline
);
804 pmRootDomain
->handlePlatformHaltRestart(type
);
805 /* This notification should have few clients who all do
806 their work synchronously.
808 In this "shutdown notification" context we don't give
809 drivers the option of working asynchronously and responding
810 later. PM internals make it very hard to wait for asynchronous
815 if (gIOPlatform
) return gIOPlatform
->haltRestart(type
);
819 UInt32
PESavePanicInfo(UInt8
*buffer
, UInt32 length
)
821 if (gIOPlatform
!= 0) return gIOPlatform
->savePanicInfo(buffer
, length
);
825 long PEGetGMTTimeOfDay(void)
829 if( gIOPlatform
) result
= gIOPlatform
->getGMTTimeOfDay();
834 void PESetGMTTimeOfDay(long secs
)
836 if( gIOPlatform
) gIOPlatform
->setGMTTimeOfDay(secs
);
841 void IOPlatformExpert::registerNVRAMController(IONVRAMController
* caller
)
844 IORegistryEntry
* entry
;
845 OSString
* string
= 0;
848 entry
= IORegistryEntry::fromPath( "/efi/platform", gIODTPlane
);
851 data
= OSDynamicCast( OSData
, entry
->getProperty( "system-id" ) );
852 if ( data
&& data
->getLength( ) == 16 )
855 uint8_t digest
[ SHA_DIGEST_LENGTH
];
856 const uuid_t space
= { 0x2A, 0x06, 0x19, 0x90, 0xD3, 0x8D, 0x44, 0x40, 0xA1, 0x39, 0xC4, 0x97, 0x70, 0x37, 0x65, 0xAC };
858 SHA1Init( &context
);
859 SHA1Update( &context
, space
, sizeof( space
) );
860 SHA1Update( &context
, data
->getBytesNoCopy( ), data
->getLength( ) );
861 SHA1Final( digest
, &context
);
863 digest
[ 6 ] = ( digest
[ 6 ] & 0x0F ) | 0x50;
864 digest
[ 8 ] = ( digest
[ 8 ] & 0x3F ) | 0x80;
866 uuid_unparse( digest
, uuid
);
867 string
= OSString::withCString( uuid
);
875 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
878 data
= OSDynamicCast( OSData
, entry
->getProperty( "platform-uuid" ) );
879 if ( data
&& data
->getLength( ) == sizeof( uuid_t
) )
881 uuid_unparse( ( uint8_t * ) data
->getBytesNoCopy( ), uuid
);
882 string
= OSString::withCString( uuid
);
891 getProvider( )->setProperty( kIOPlatformUUIDKey
, string
);
892 publishResource( kIOPlatformUUIDKey
, string
);
897 publishResource("IONVRAM");
900 IOReturn
IOPlatformExpert::callPlatformFunction(const OSSymbol
*functionName
,
901 bool waitForFunction
,
902 void *param1
, void *param2
,
903 void *param3
, void *param4
)
905 IOService
*service
, *_resources
;
907 if (waitForFunction
) {
908 _resources
= waitForService(resourceMatching(functionName
));
910 _resources
= getResourceService();
912 if (_resources
== 0) return kIOReturnUnsupported
;
914 service
= OSDynamicCast(IOService
, _resources
->getProperty(functionName
));
915 if (service
== 0) return kIOReturnUnsupported
;
917 return service
->callPlatformFunction(functionName
, waitForFunction
,
918 param1
, param2
, param3
, param4
);
921 IOByteCount
IOPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
926 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
929 #define super IOPlatformExpert
931 OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert
, IOPlatformExpert
)
933 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 0);
934 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 1);
935 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 2);
936 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 3);
937 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 4);
938 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 5);
939 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 6);
940 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 7);
942 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
944 IOService
* IODTPlatformExpert::probe( IOService
* provider
,
947 if( !super::probe( provider
, score
))
950 // check machine types
951 if( !provider
->compareNames( getProperty( gIONameMatchKey
) ))
957 bool IODTPlatformExpert::configure( IOService
* provider
)
959 if( !super::configure( provider
))
962 processTopLevel( provider
);
967 IOService
* IODTPlatformExpert::createNub( IORegistryEntry
* from
)
971 nub
= new IOPlatformDevice
;
973 if( !nub
->init( from
, gIODTPlane
)) {
981 bool IODTPlatformExpert::createNubs( IOService
* parent
, OSIterator
* iter
)
983 IORegistryEntry
* next
;
988 while( (next
= (IORegistryEntry
*) iter
->getNextObject())) {
990 if( 0 == (nub
= createNub( next
)))
993 nub
->attach( parent
);
994 nub
->registerService();
1002 void IODTPlatformExpert::processTopLevel( IORegistryEntry
* rootEntry
)
1005 IORegistryEntry
* next
;
1006 IORegistryEntry
* cpus
;
1007 IORegistryEntry
* options
;
1010 kids
= IODTFindMatchingEntries( rootEntry
, 0, deleteList() );
1012 while( (next
= (IORegistryEntry
*)kids
->getNextObject())) {
1013 next
->detachAll( gIODTPlane
);
1018 // Publish an IODTNVRAM class on /options.
1019 options
= rootEntry
->childFromPath("options", gIODTPlane
);
1021 dtNVRAM
= new IODTNVRAM
;
1023 if (!dtNVRAM
->init(options
, gIODTPlane
)) {
1027 dtNVRAM
->attach(this);
1028 dtNVRAM
->registerService();
1033 // Publish the cpus.
1034 cpus
= rootEntry
->childFromPath( "cpus", gIODTPlane
);
1036 createNubs( this, IODTFindMatchingEntries( cpus
, kIODTExclusive
, 0));
1038 // publish top level, minus excludeList
1039 createNubs( this, IODTFindMatchingEntries( rootEntry
, kIODTExclusive
, excludeList()));
1042 IOReturn
IODTPlatformExpert::getNubResources( IOService
* nub
)
1044 if( nub
->getDeviceMemory())
1045 return( kIOReturnSuccess
);
1047 IODTResolveAddressing( nub
, "reg", 0);
1049 return( kIOReturnSuccess
);
1052 bool IODTPlatformExpert::compareNubName( const IOService
* nub
,
1053 OSString
* name
, OSString
** matched
) const
1055 return( IODTCompareNubName( nub
, name
, matched
)
1056 || super::compareNubName( nub
, name
, matched
) );
1059 bool IODTPlatformExpert::getModelName( char * name
, int maxLength
)
1069 prop
= (OSData
*) getProvider()->getProperty( gIODTCompatibleKey
);
1071 str
= (const char *) prop
->getBytesNoCopy();
1073 if( 0 == strncmp( str
, "AAPL,", strlen( "AAPL," ) ))
1074 str
+= strlen( "AAPL," );
1077 while( (c
= *str
++)) {
1078 if( (c
== '/') || (c
== ' '))
1082 if( len
>= maxLength
)
1092 bool IODTPlatformExpert::getMachineName( char * name
, int maxLength
)
1098 prop
= (OSData
*) getProvider()->getProperty( gIODTModelKey
);
1102 strlcpy( name
, (const char *) prop
->getBytesNoCopy(), maxLength
);
1107 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1109 void IODTPlatformExpert::registerNVRAMController( IONVRAMController
* nvram
)
1111 if (dtNVRAM
) dtNVRAM
->registerNVRAMController(nvram
);
1113 super::registerNVRAMController(nvram
);
1116 int IODTPlatformExpert::haltRestart(unsigned int type
)
1118 if (dtNVRAM
) dtNVRAM
->sync();
1120 return super::haltRestart(type
);
1123 IOReturn
IODTPlatformExpert::readXPRAM(IOByteCount offset
, UInt8
* buffer
,
1126 if (dtNVRAM
) return dtNVRAM
->readXPRAM(offset
, buffer
, length
);
1127 else return kIOReturnNotReady
;
1130 IOReturn
IODTPlatformExpert::writeXPRAM(IOByteCount offset
, UInt8
* buffer
,
1133 if (dtNVRAM
) return dtNVRAM
->writeXPRAM(offset
, buffer
, length
);
1134 else return kIOReturnNotReady
;
1137 IOReturn
IODTPlatformExpert::readNVRAMProperty(
1138 IORegistryEntry
* entry
,
1139 const OSSymbol
** name
, OSData
** value
)
1141 if (dtNVRAM
) return dtNVRAM
->readNVRAMProperty(entry
, name
, value
);
1142 else return kIOReturnNotReady
;
1145 IOReturn
IODTPlatformExpert::writeNVRAMProperty(
1146 IORegistryEntry
* entry
,
1147 const OSSymbol
* name
, OSData
* value
)
1149 if (dtNVRAM
) return dtNVRAM
->writeNVRAMProperty(entry
, name
, value
);
1150 else return kIOReturnNotReady
;
1153 OSDictionary
*IODTPlatformExpert::getNVRAMPartitions(void)
1155 if (dtNVRAM
) return dtNVRAM
->getNVRAMPartitions();
1159 IOReturn
IODTPlatformExpert::readNVRAMPartition(const OSSymbol
* partitionID
,
1160 IOByteCount offset
, UInt8
* buffer
,
1163 if (dtNVRAM
) return dtNVRAM
->readNVRAMPartition(partitionID
, offset
,
1165 else return kIOReturnNotReady
;
1168 IOReturn
IODTPlatformExpert::writeNVRAMPartition(const OSSymbol
* partitionID
,
1169 IOByteCount offset
, UInt8
* buffer
,
1172 if (dtNVRAM
) return dtNVRAM
->writeNVRAMPartition(partitionID
, offset
,
1174 else return kIOReturnNotReady
;
1177 IOByteCount
IODTPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1179 IOByteCount lengthSaved
= 0;
1181 if (dtNVRAM
) lengthSaved
= dtNVRAM
->savePanicInfo(buffer
, length
);
1183 if (lengthSaved
== 0) lengthSaved
= super::savePanicInfo(buffer
, length
);
1188 OSString
* IODTPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
) {
1189 UInt8
* serialNumber
;
1190 unsigned int serialNumberSize
;
1191 unsigned short pos
= 0;
1195 if (myProperty
!= NULL
) {
1196 serialNumberSize
= myProperty
->getLength();
1197 serialNumber
= (UInt8
*)(myProperty
->getBytesNoCopy());
1198 temp
= (char*)serialNumber
;
1199 if (serialNumberSize
> 0) {
1200 // check to see if this is a CTO serial number...
1201 while (pos
< serialNumberSize
&& temp
[pos
] != '-') pos
++;
1203 if (pos
< serialNumberSize
) { // there was a hyphen, so it's a CTO serial number
1204 memcpy(SerialNo
, serialNumber
+ 12, 8);
1205 memcpy(&SerialNo
[8], serialNumber
, 3);
1207 memcpy(&SerialNo
[12], serialNumber
+ 3, 8);
1209 } else { // just a normal serial number
1210 memcpy(SerialNo
, serialNumber
+ 13, 8);
1211 memcpy(&SerialNo
[8], serialNumber
, 3);
1214 return OSString::withCString(SerialNo
);
1221 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1224 #define super IOService
1226 OSDefineMetaClassAndStructors(IOPlatformExpertDevice
, IOService
)
1228 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 0);
1229 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 1);
1230 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 2);
1231 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 3);
1233 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1235 bool IOPlatformExpertDevice::compareName( OSString
* name
,
1236 OSString
** matched
) const
1238 return( IODTCompareNubName( this, name
, matched
));
1242 IOPlatformExpertDevice::initWithArgs(
1243 void * dtTop
, void * p2
, void * p3
, void * p4
)
1245 IORegistryEntry
* dt
= 0;
1246 void * argsData
[ 4 ];
1249 // dtTop may be zero on non- device tree systems
1250 if( dtTop
&& (dt
= IODeviceTreeAlloc( dtTop
)))
1251 ok
= super::init( dt
, gIODTPlane
);
1258 workLoop
= IOWorkLoop::workLoop();
1262 argsData
[ 0 ] = dtTop
;
1267 setProperty("IOPlatformArgs", (void *)argsData
, sizeof(argsData
));
1272 IOWorkLoop
*IOPlatformExpertDevice::getWorkLoop() const
1277 IOReturn
IOPlatformExpertDevice::setProperties( OSObject
* properties
)
1279 OSDictionary
* dictionary
;
1283 status
= super::setProperties( properties
);
1284 if ( status
!= kIOReturnUnsupported
) return status
;
1286 status
= IOUserClient::clientHasPrivilege( current_task( ), kIOClientPrivilegeAdministrator
);
1287 if ( status
!= kIOReturnSuccess
) return status
;
1289 dictionary
= OSDynamicCast( OSDictionary
, properties
);
1290 if ( dictionary
== 0 ) return kIOReturnBadArgument
;
1292 object
= dictionary
->getObject( kIOPlatformUUIDKey
);
1295 IORegistryEntry
* entry
;
1299 string
= ( OSString
* ) getProperty( kIOPlatformUUIDKey
);
1300 if ( string
) return kIOReturnNotPermitted
;
1302 string
= OSDynamicCast( OSString
, object
);
1303 if ( string
== 0 ) return kIOReturnBadArgument
;
1305 status
= uuid_parse( string
->getCStringNoCopy( ), uuid
);
1306 if ( status
!= 0 ) return kIOReturnBadArgument
;
1308 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
1311 entry
->setProperty( "platform-uuid", uuid
, sizeof( uuid_t
) );
1315 setProperty( kIOPlatformUUIDKey
, string
);
1316 publishResource( kIOPlatformUUIDKey
, string
);
1318 return kIOReturnSuccess
;
1321 return kIOReturnUnsupported
;
1324 void IOPlatformExpertDevice::free()
1327 workLoop
->release();
1330 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1333 #define super IOService
1335 OSDefineMetaClassAndStructors(IOPlatformDevice
, IOService
)
1337 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 0);
1338 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 1);
1339 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 2);
1340 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 3);
1342 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1344 bool IOPlatformDevice::compareName( OSString
* name
,
1345 OSString
** matched
) const
1347 return( ((IOPlatformExpert
*)getProvider())->
1348 compareNubName( this, name
, matched
));
1351 IOService
* IOPlatformDevice::matchLocation( IOService
* /* client */ )
1356 IOReturn
IOPlatformDevice::getResources( void )
1358 return( ((IOPlatformExpert
*)getProvider())->getNubResources( this ));
1361 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1363 /*********************************************************************
1364 * IOPanicPlatform class
1366 * If no legitimate IOPlatformDevice matches, this one does and panics
1367 * the kernel with a suitable message.
1368 *********************************************************************/
1370 class IOPanicPlatform
: IOPlatformExpert
{
1371 OSDeclareDefaultStructors(IOPanicPlatform
);
1374 bool start(IOService
* provider
);
1378 OSDefineMetaClassAndStructors(IOPanicPlatform
, IOPlatformExpert
);
1381 bool IOPanicPlatform::start(IOService
* provider
) {
1382 const char * platform_name
= "(unknown platform name)";
1384 if (provider
) platform_name
= provider
->getName();
1386 panic("Unable to find driver for this platform: \"%s\".\n",