2 * Copyright (c) 1998-2006 Apple Computer, 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 /* Delay period for UPS halt */
58 #define kUPSDelayHaltCPU_msec (1000*60*5)
60 void printDictionaryKeys (OSDictionary
* inDictionary
, char * inMsg
);
61 static void getCStringForObject(OSObject
*inObj
, char *outStr
, size_t outStrLen
);
63 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
65 #define super IOService
67 OSDefineMetaClassAndStructors(IOPlatformExpert
, IOService
)
69 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 0);
71 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 1);
72 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 2);
73 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 3);
74 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 4);
75 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 5);
76 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 6);
77 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 7);
78 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 8);
79 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 9);
80 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 10);
81 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 11);
83 static IOPlatformExpert
* gIOPlatform
;
84 static OSDictionary
* gIOInterruptControllers
;
85 static IOLock
* gIOInterruptControllersLock
;
87 OSSymbol
* gPlatformInterruptControllerName
;
89 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
91 bool IOPlatformExpert::attach( IOService
* provider
)
94 if( !super::attach( provider
))
100 bool IOPlatformExpert::start( IOService
* provider
)
102 IORangeAllocator
* physicalRanges
;
103 OSData
* busFrequency
;
106 if (!super::start(provider
))
109 // Override the mapper present flag is requested by boot arguments.
110 if (PE_parse_boot_argn("dart", &debugFlags
, sizeof (debugFlags
)) && (debugFlags
== 0))
111 removeProperty(kIOPlatformMapperPresentKey
);
113 // Register the presence or lack thereof a system
114 // PCI address mapper with the IOMapper class
115 IOMapper::setMapperRequired(0 != getProperty(kIOPlatformMapperPresentKey
));
117 gIOInterruptControllers
= OSDictionary::withCapacity(1);
118 gIOInterruptControllersLock
= IOLockAlloc();
120 // Correct the bus frequency in the device tree.
121 busFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.bus_clock_rate_hz
, 4);
122 provider
->setProperty("clock-frequency", busFrequency
);
123 busFrequency
->release();
125 gPlatformInterruptControllerName
= (OSSymbol
*)OSSymbol::withCStringNoCopy("IOPlatformInterruptController");
127 physicalRanges
= IORangeAllocator::withRange(0xffffffff, 1, 16,
128 IORangeAllocator::kLocking
);
129 assert(physicalRanges
);
130 setProperty("Platform Memory Ranges", physicalRanges
);
135 PMInstantiatePowerDomains();
137 // Parse the serial-number data and publish a user-readable string
138 OSData
* mydata
= (OSData
*) (provider
->getProperty("serial-number"));
139 if (mydata
!= NULL
) {
140 OSString
*serNoString
= createSystemSerialNumberString(mydata
);
141 if (serNoString
!= NULL
) {
142 provider
->setProperty(kIOPlatformSerialNumberKey
, serNoString
);
143 serNoString
->release();
147 return( configure(provider
) );
150 bool IOPlatformExpert::configure( IOService
* provider
)
156 topLevel
= OSDynamicCast( OSSet
, getProperty("top-level"));
159 while( (dict
= OSDynamicCast( OSDictionary
,
160 topLevel
->getAnyObject()))) {
162 topLevel
->removeObject( dict
);
163 nub
= createNub( dict
);
168 nub
->registerService();
175 IOService
* IOPlatformExpert::createNub( OSDictionary
* from
)
179 nub
= new IOPlatformDevice
;
181 if( !nub
->init( from
)) {
189 bool IOPlatformExpert::compareNubName( const IOService
* nub
,
190 OSString
* name
, OSString
** matched
) const
192 return( nub
->IORegistryEntry::compareName( name
, matched
));
195 IOReturn
IOPlatformExpert::getNubResources( IOService
* nub
)
197 return( kIOReturnSuccess
);
200 long IOPlatformExpert::getBootROMType(void)
202 return _peBootROMType
;
205 long IOPlatformExpert::getChipSetType(void)
207 return _peChipSetType
;
210 long IOPlatformExpert::getMachineType(void)
212 return _peMachineType
;
215 void IOPlatformExpert::setBootROMType(long peBootROMType
)
217 _peBootROMType
= peBootROMType
;
220 void IOPlatformExpert::setChipSetType(long peChipSetType
)
222 _peChipSetType
= peChipSetType
;
225 void IOPlatformExpert::setMachineType(long peMachineType
)
227 _peMachineType
= peMachineType
;
230 bool IOPlatformExpert::getMachineName( char * /*name*/, int /*maxLength*/)
235 bool IOPlatformExpert::getModelName( char * /*name*/, int /*maxLength*/)
240 OSString
* IOPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
)
245 IORangeAllocator
* IOPlatformExpert::getPhysicalRangeAllocator(void)
247 return(OSDynamicCast(IORangeAllocator
,
248 getProperty("Platform Memory Ranges")));
251 int (*PE_halt_restart
)(unsigned int type
) = 0;
253 int IOPlatformExpert::haltRestart(unsigned int type
)
255 if (type
== kPEPanicSync
) return 0;
257 if (type
== kPEHangCPU
) while (1);
259 if (type
== kPEUPSDelayHaltCPU
) {
260 // Stall shutdown for 5 minutes, and if no outside force has
261 // removed our power at that point, proceed with a reboot.
262 IOSleep( kUPSDelayHaltCPU_msec
);
264 // Ideally we never reach this point.
266 type
= kPERestartCPU
;
269 // On ARM kPEPanicRestartCPU is supported in the drivers
270 if (type
== kPEPanicRestartCPU
)
271 type
= kPERestartCPU
;
273 if (PE_halt_restart
) return (*PE_halt_restart
)(type
);
277 void IOPlatformExpert::sleepKernel(void)
283 intState
= ml_set_interrupts_enabled(false);
285 for (cnt
= 0; cnt
< 10000; cnt
++) {
289 ml_set_interrupts_enabled(intState
);
291 // PE_initialize_console(0, kPEDisableScreen);
295 // PE_initialize_console(0, kPEEnableScreen);
299 long IOPlatformExpert::getGMTTimeOfDay(void)
304 void IOPlatformExpert::setGMTTimeOfDay(long secs
)
309 IOReturn
IOPlatformExpert::getConsoleInfo( PE_Video
* consoleInfo
)
311 return( PE_current_console( consoleInfo
));
314 IOReturn
IOPlatformExpert::setConsoleInfo( PE_Video
* consoleInfo
,
317 return( PE_initialize_console( consoleInfo
, op
));
320 IOReturn
IOPlatformExpert::registerInterruptController(OSSymbol
*name
, IOInterruptController
*interruptController
)
322 IOLockLock(gIOInterruptControllersLock
);
324 gIOInterruptControllers
->setObject(name
, interruptController
);
326 IOLockWakeup(gIOInterruptControllersLock
,
327 gIOInterruptControllers
, /* one-thread */ false);
329 IOLockUnlock(gIOInterruptControllersLock
);
331 return kIOReturnSuccess
;
334 IOInterruptController
*IOPlatformExpert::lookUpInterruptController(OSSymbol
*name
)
338 IOLockLock(gIOInterruptControllersLock
);
341 object
= gIOInterruptControllers
->getObject(name
);
346 IOLockSleep(gIOInterruptControllersLock
,
347 gIOInterruptControllers
, THREAD_UNINT
);
350 IOLockUnlock(gIOInterruptControllersLock
);
351 return OSDynamicCast(IOInterruptController
, object
);
355 void IOPlatformExpert::setCPUInterruptProperties(IOService
*service
)
357 IOCPUInterruptController
*controller
;
359 controller
= OSDynamicCast(IOCPUInterruptController
, waitForService(serviceMatching("IOCPUInterruptController")));
360 if (controller
) controller
->setCPUInterruptProperties(service
);
363 bool IOPlatformExpert::atInterruptLevel(void)
365 return ml_at_interrupt_context();
368 bool IOPlatformExpert::platformAdjustService(IOService */
*service*/
)
374 //*********************************************************************************
377 //*********************************************************************************
379 void IOPlatformExpert::
380 PMLog(const char *who
, unsigned long event
,
381 unsigned long param1
, unsigned long param2
)
383 UInt32 debugFlags
= gIOKitDebug
;
385 if (debugFlags
& kIOLogPower
) {
387 uint32_t nows
, nowus
;
388 clock_get_system_microtime(&nows
, &nowus
);
389 nowus
+= (nows
% 1000) * 1000000;
391 kprintf("pm%u %x %.30s %d %x %x\n",
392 nowus
, (unsigned) current_thread(), who
, // Identity
393 (int) event
, param1
, param2
); // Args
395 if (debugFlags
& kIOLogTracePower
) {
396 static const UInt32 sStartStopBitField
[] =
397 { 0x00000000, 0x00000040 }; // Only Program Hardware so far
399 // Arcane formula from Hacker's Delight by Warren
400 // abs(x) = ((int) x >> 31) ^ (x + ((int) x >> 31))
401 UInt32 sgnevent
= ((long) event
>> 31);
402 UInt32 absevent
= sgnevent
^ (event
+ sgnevent
);
403 UInt32 code
= IODBG_POWER(absevent
);
405 UInt32 bit
= 1 << (absevent
& 0x1f);
406 if (absevent
< sizeof(sStartStopBitField
) * 8
407 && (sStartStopBitField
[absevent
>> 5] & bit
) ) {
408 // Or in the START or END bits, Start = 1 & END = 2
409 // If sgnevent == 0 then START - 0 => START
410 // else if sgnevent == -1 then START - -1 => END
411 code
|= DBG_FUNC_START
- sgnevent
;
414 // Record the timestamp, wish I had a this pointer
415 IOTimeStampConstant(code
, (UInt32
) who
, 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
;
440 //*********************************************************************************
443 // In this vanilla implementation, all callers are made children of the root power domain.
444 // Where this is inappropriate, PMRegisterDevice is overridden in a platform-specific subclass.
445 //*********************************************************************************
447 void IOPlatformExpert::PMRegisterDevice(IOService
* theNub
, IOService
* theDevice
)
449 root
->addPowerChild ( theDevice
);
452 //*********************************************************************************
455 //*********************************************************************************
457 bool IOPlatformExpert::hasPMFeature (unsigned long featureMask
)
459 return ((_pePMFeatures
& featureMask
) != 0);
462 //*********************************************************************************
465 //*********************************************************************************
467 bool IOPlatformExpert::hasPrivPMFeature (unsigned long privFeatureMask
)
469 return ((_pePrivPMFeatures
& privFeatureMask
) != 0);
472 //*********************************************************************************
473 // numBatteriesSupported
475 //*********************************************************************************
477 int IOPlatformExpert::numBatteriesSupported (void)
479 return (_peNumBatteriesSupported
);
482 //*********************************************************************************
485 // This method is called by the instantiated sublass of the platform expert to
486 // determine how a device should be inserted into the Power Domain. The subclass
487 // provides an XML power tree description against which a device is matched based
488 // on class and provider. If a match is found this routine returns true in addition
489 // to flagging the description tree at the appropriate node that a device has been
490 // registered for the given service.
491 //*********************************************************************************
493 bool IOPlatformExpert::CheckSubTree (OSArray
* inSubTree
, IOService
* theNub
, IOService
* theDevice
, OSDictionary
* theParent
)
496 unsigned int numPowerTreeNodes
;
497 OSDictionary
* entry
;
498 OSDictionary
* matchingDictionary
;
499 OSDictionary
* providerDictionary
;
500 OSDictionary
* deviceDictionary
;
501 OSDictionary
* nubDictionary
;
503 bool nodeFound
= false;
504 bool continueSearch
= false;
505 bool deviceMatch
= false;
506 bool providerMatch
= false;
507 bool multiParentMatch
= false;
509 if ( (NULL
== theDevice
) || (NULL
== inSubTree
) )
512 numPowerTreeNodes
= inSubTree
->getCount ();
514 // iterate through the power tree to find a home for this device
516 for ( i
= 0; i
< numPowerTreeNodes
; i
++ ) {
518 entry
= (OSDictionary
*) inSubTree
->getObject (i
);
520 matchingDictionary
= (OSDictionary
*) entry
->getObject ("device");
521 providerDictionary
= (OSDictionary
*) entry
->getObject ("provider");
523 deviceMatch
= true; // if no matching dictionary, this is not a criteria and so must match
524 if ( matchingDictionary
) {
526 if ( NULL
!= (deviceDictionary
= theDevice
->dictionaryWithProperties ())) {
527 deviceMatch
= deviceDictionary
->isEqualTo ( matchingDictionary
, matchingDictionary
);
528 deviceDictionary
->release ();
532 providerMatch
= true; // we indicate a match if there is no nub or provider
533 if ( theNub
&& providerDictionary
) {
534 providerMatch
= false;
535 if ( NULL
!= (nubDictionary
= theNub
->dictionaryWithProperties ()) ) {
536 providerMatch
= nubDictionary
->isEqualTo ( providerDictionary
, providerDictionary
);
537 nubDictionary
->release ();
541 multiParentMatch
= true; // again we indicate a match if there is no multi-parent node
542 if (deviceMatch
&& providerMatch
) {
543 if (NULL
!= multipleParentKeyValue
) {
544 OSNumber
* aNumber
= (OSNumber
*) entry
->getObject ("multiple-parent");
545 multiParentMatch
= (NULL
!= aNumber
) ? multipleParentKeyValue
->isEqualTo (aNumber
) : false;
549 nodeFound
= (deviceMatch
&& providerMatch
&& multiParentMatch
);
551 // if the power tree specifies a provider dictionary but theNub is
552 // NULL then we cannot match with this entry.
554 if ( theNub
== NULL
&& providerDictionary
!= NULL
)
557 // if this node is THE ONE...then register the device
560 if (RegisterServiceInTree (theDevice
, entry
, theParent
, theNub
) ) {
562 if ( kIOLogPower
& gIOKitDebug
)
563 IOLog ("PMRegisterDevice/CheckSubTree - service registered!\n");
565 numInstancesRegistered
++;
567 // determine if we need to search for additional nodes for this item
568 multipleParentKeyValue
= (OSNumber
*) entry
->getObject ("multiple-parent");
574 continueSearch
= ( (false == nodeFound
) || (NULL
!= multipleParentKeyValue
) );
576 if ( continueSearch
&& (NULL
!= (children
= (OSArray
*) entry
->getObject ("children"))) ) {
577 nodeFound
= CheckSubTree ( children
, theNub
, theDevice
, entry
);
578 continueSearch
= ( (false == nodeFound
) || (NULL
!= multipleParentKeyValue
) );
581 if ( false == continueSearch
)
585 return ( nodeFound
);
588 //*********************************************************************************
589 // RegisterServiceInTree
591 // Register a device at the specified node of our power tree.
592 //*********************************************************************************
594 bool IOPlatformExpert::RegisterServiceInTree (IOService
* theService
, OSDictionary
* theTreeNode
, OSDictionary
* theTreeParentNode
, IOService
* theProvider
)
596 IOService
* aService
;
597 bool registered
= false;
599 unsigned int numChildren
;
600 OSDictionary
* child
;
602 // make sure someone is not already registered here
604 if ( NULL
== theTreeNode
->getObject ("service") ) {
606 if ( theTreeNode
->setObject ("service", OSDynamicCast ( OSObject
, theService
)) ) {
608 // 1. CHILDREN ------------------
610 // we registered the node in the tree...now if the node has children
611 // registered we must tell this service to add them.
613 if ( NULL
!= (children
= (OSArray
*) theTreeNode
->getObject ("children")) ) {
614 numChildren
= children
->getCount ();
615 for ( unsigned int i
= 0; i
< numChildren
; i
++ ) {
616 if ( NULL
!= (child
= (OSDictionary
*) children
->getObject (i
)) ) {
617 if ( NULL
!= (aService
= (IOService
*) child
->getObject ("service")) )
618 theService
->addPowerChild (aService
);
623 // 2. PARENT --------------------
625 // also we must notify the parent of this node (if a registered service
626 // exists there) of a new child.
628 if ( theTreeParentNode
) {
629 if ( NULL
!= (aService
= (IOService
*) theTreeParentNode
->getObject ("service")) )
630 if (aService
!= theProvider
)
631 aService
->addPowerChild (theService
);
641 //*********************************************************************************
642 // printDictionaryKeys
644 // Print the keys for the given dictionary and selected contents.
645 //*********************************************************************************
646 void printDictionaryKeys (OSDictionary
* inDictionary
, char * inMsg
)
648 OSCollectionIterator
* mcoll
= OSCollectionIterator::withCollection (inDictionary
);
655 mkey
= OSDynamicCast (OSSymbol
, mcoll
->getNextObject ());
659 // kprintf ("dictionary key #%d: %s\n", i, mkey->getCStringNoCopy () );
661 // if this is the IOClass key, print it's contents
663 if ( mkey
->isEqualTo ("IOClass") ) {
664 ioClass
= (OSString
*) inDictionary
->getObject ("IOClass");
665 if ( ioClass
) IOLog ("%s IOClass is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
668 // if this is an IOProviderClass key print it
670 if ( mkey
->isEqualTo ("IOProviderClass") ) {
671 ioClass
= (OSString
*) inDictionary
->getObject ("IOProviderClass");
672 if ( ioClass
) IOLog ("%s IOProviderClass is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
676 // also print IONameMatch keys
677 if ( mkey
->isEqualTo ("IONameMatch") ) {
678 ioClass
= (OSString
*) inDictionary
->getObject ("IONameMatch");
679 if ( ioClass
) IOLog ("%s IONameMatch is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
682 // also print IONameMatched keys
684 if ( mkey
->isEqualTo ("IONameMatched") ) {
685 ioClass
= (OSString
*) inDictionary
->getObject ("IONameMatched");
686 if ( ioClass
) IOLog ("%s IONameMatched is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
692 if ( mkey
->isEqualTo ("AAPL,clock-id") ) {
694 cstr
= getCStringForObject (inDictionary
->getObject ("AAPL,clock-id"));
696 kprintf (" ===> AAPL,clock-id is %s\n", cstr
);
702 if ( mkey
->isEqualTo ("name") ) {
705 getCStringForObject(inDictionary
->getObject("name"), nameStr
,
707 if (strlen(nameStr
) > 0)
708 IOLog ("%s name is %s\n", inMsg
, nameStr
);
711 mkey
= (OSSymbol
*) mcoll
->getNextObject ();
720 getCStringForObject(OSObject
*inObj
, char *outStr
, size_t outStrLen
)
725 if ( (NULL
== inObj
) || (NULL
== outStr
))
728 char * objString
= (char *) (inObj
->getMetaClass())->getClassName();
730 if ((0 == strncmp(objString
, "OSString", sizeof("OSString"))) ||
731 (0 == strncmp(objString
, "OSSymbol", sizeof("OSSymbol"))))
732 strlcpy(outStr
, ((OSString
*)inObj
)->getCStringNoCopy(), outStrLen
);
734 else if (0 == strncmp(objString
, "OSData", sizeof("OSData"))) {
735 len
= ((OSData
*)inObj
)->getLength();
736 buffer
= (char *)((OSData
*)inObj
)->getBytesNoCopy();
737 if (buffer
&& (len
> 0)) {
738 for (i
=0; i
< len
; i
++) {
739 outStr
[i
] = buffer
[i
];
746 /* IOShutdownNotificationsTimedOut
747 * - Called from a timer installed by PEHaltRestart
749 static void IOShutdownNotificationsTimedOut(
750 thread_call_param_t p0
,
751 thread_call_param_t p1
)
755 /* 30 seconds has elapsed - resume shutdown */
756 if(gIOPlatform
) gIOPlatform
->haltRestart(type
);
763 * Callouts from BSD for machine name & model
766 boolean_t
PEGetMachineName( char * name
, int maxLength
)
769 return( gIOPlatform
->getMachineName( name
, maxLength
));
774 boolean_t
PEGetModelName( char * name
, int maxLength
)
777 return( gIOPlatform
->getModelName( name
, maxLength
));
782 int PEGetPlatformEpoch(void)
785 return( gIOPlatform
->getBootROMType());
790 int PEHaltRestart(unsigned int type
)
792 IOPMrootDomain
*pmRootDomain
= IOService::getPMRootDomain();
793 AbsoluteTime deadline
;
794 thread_call_t shutdown_hang
;
795 unsigned int tell_type
;
797 if(type
== kPEHaltCPU
|| type
== kPERestartCPU
|| type
== kPEUPSDelayHaltCPU
)
799 /* Notify IOKit PM clients of shutdown/restart
800 Clients subscribe to this message with a call to
801 IOService::registerInterest()
804 /* Spawn a thread that will panic in 30 seconds.
805 If all goes well the machine will be off by the time
808 shutdown_hang
= thread_call_allocate( &IOShutdownNotificationsTimedOut
,
809 (thread_call_param_t
) type
);
810 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
811 thread_call_enter1_delayed( shutdown_hang
, 0, deadline
);
814 if( kPEUPSDelayHaltCPU
== type
) {
815 tell_type
= kPEHaltCPU
;
820 pmRootDomain
->handlePlatformHaltRestart(tell_type
);
821 /* This notification should have few clients who all do
822 their work synchronously.
824 In this "shutdown notification" context we don't give
825 drivers the option of working asynchronously and responding
826 later. PM internals make it very hard to wait for asynchronous
831 if (gIOPlatform
) return gIOPlatform
->haltRestart(type
);
835 UInt32
PESavePanicInfo(UInt8
*buffer
, UInt32 length
)
837 if (gIOPlatform
!= 0) return gIOPlatform
->savePanicInfo(buffer
, length
);
841 long PEGetGMTTimeOfDay(void)
846 result
= gIOPlatform
->getGMTTimeOfDay();
851 void PESetGMTTimeOfDay(long secs
)
854 gIOPlatform
->setGMTTimeOfDay(secs
);
859 void IOPlatformExpert::registerNVRAMController(IONVRAMController
* caller
)
862 IORegistryEntry
* entry
;
863 OSString
* string
= 0;
866 entry
= IORegistryEntry::fromPath( "/efi/platform", gIODTPlane
);
869 data
= OSDynamicCast( OSData
, entry
->getProperty( "system-id" ) );
870 if ( data
&& data
->getLength( ) == 16 )
873 uint8_t digest
[ SHA_DIGEST_LENGTH
];
874 const uuid_t space
= { 0x2A, 0x06, 0x19, 0x90, 0xD3, 0x8D, 0x44, 0x40, 0xA1, 0x39, 0xC4, 0x97, 0x70, 0x37, 0x65, 0xAC };
876 SHA1Init( &context
);
877 SHA1Update( &context
, space
, sizeof( space
) );
878 SHA1Update( &context
, data
->getBytesNoCopy( ), data
->getLength( ) );
879 SHA1Final( digest
, &context
);
881 digest
[ 6 ] = ( digest
[ 6 ] & 0x0F ) | 0x50;
882 digest
[ 8 ] = ( digest
[ 8 ] & 0x3F ) | 0x80;
884 uuid_unparse( digest
, uuid
);
885 string
= OSString::withCString( uuid
);
893 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
896 data
= OSDynamicCast( OSData
, entry
->getProperty( "platform-uuid" ) );
897 if ( data
&& data
->getLength( ) == sizeof( uuid_t
) )
899 uuid_unparse( ( uint8_t * ) data
->getBytesNoCopy( ), uuid
);
900 string
= OSString::withCString( uuid
);
909 getProvider( )->setProperty( kIOPlatformUUIDKey
, string
);
910 publishResource( kIOPlatformUUIDKey
, string
);
915 publishResource("IONVRAM");
918 IOReturn
IOPlatformExpert::callPlatformFunction(const OSSymbol
*functionName
,
919 bool waitForFunction
,
920 void *param1
, void *param2
,
921 void *param3
, void *param4
)
923 IOService
*service
, *_resources
;
925 if (waitForFunction
) {
926 _resources
= waitForService(resourceMatching(functionName
));
928 _resources
= resources();
930 if (_resources
== 0) return kIOReturnUnsupported
;
932 service
= OSDynamicCast(IOService
, _resources
->getProperty(functionName
));
933 if (service
== 0) return kIOReturnUnsupported
;
935 return service
->callPlatformFunction(functionName
, waitForFunction
,
936 param1
, param2
, param3
, param4
);
939 IOByteCount
IOPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
944 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
947 #define super IOPlatformExpert
949 OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert
, IOPlatformExpert
)
951 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 0);
952 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 1);
953 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 2);
954 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 3);
955 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 4);
956 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 5);
957 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 6);
958 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 7);
960 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
962 IOService
* IODTPlatformExpert::probe( IOService
* provider
,
965 if( !super::probe( provider
, score
))
968 // check machine types
969 if( !provider
->compareNames( getProperty( gIONameMatchKey
) ))
975 bool IODTPlatformExpert::configure( IOService
* provider
)
977 if( !super::configure( provider
))
980 processTopLevel( provider
);
985 IOService
* IODTPlatformExpert::createNub( IORegistryEntry
* from
)
989 nub
= new IOPlatformDevice
;
991 if( !nub
->init( from
, gIODTPlane
)) {
999 bool IODTPlatformExpert::createNubs( IOService
* parent
, OSIterator
* iter
)
1001 IORegistryEntry
* next
;
1006 while( (next
= (IORegistryEntry
*) iter
->getNextObject())) {
1008 if( 0 == (nub
= createNub( next
)))
1011 nub
->attach( parent
);
1012 nub
->registerService();
1020 void IODTPlatformExpert::processTopLevel( IORegistryEntry
* rootEntry
)
1023 IORegistryEntry
* next
;
1024 IORegistryEntry
* cpus
;
1025 IORegistryEntry
* options
;
1028 kids
= IODTFindMatchingEntries( rootEntry
, 0, deleteList() );
1030 while( (next
= (IORegistryEntry
*)kids
->getNextObject())) {
1031 next
->detachAll( gIODTPlane
);
1036 // Publish an IODTNVRAM class on /options.
1037 options
= rootEntry
->childFromPath("options", gIODTPlane
);
1039 dtNVRAM
= new IODTNVRAM
;
1041 if (!dtNVRAM
->init(options
, gIODTPlane
)) {
1045 dtNVRAM
->attach(this);
1046 dtNVRAM
->registerService();
1051 // Publish the cpus.
1052 cpus
= rootEntry
->childFromPath( "cpus", gIODTPlane
);
1054 createNubs( this, IODTFindMatchingEntries( cpus
, kIODTExclusive
, 0));
1056 // publish top level, minus excludeList
1057 createNubs( this, IODTFindMatchingEntries( rootEntry
, kIODTExclusive
, excludeList()));
1060 IOReturn
IODTPlatformExpert::getNubResources( IOService
* nub
)
1062 if( nub
->getDeviceMemory())
1063 return( kIOReturnSuccess
);
1065 IODTResolveAddressing( nub
, "reg", 0);
1067 return( kIOReturnSuccess
);
1070 bool IODTPlatformExpert::compareNubName( const IOService
* nub
,
1071 OSString
* name
, OSString
** matched
) const
1073 return( IODTCompareNubName( nub
, name
, matched
)
1074 || super::compareNubName( nub
, name
, matched
) );
1077 bool IODTPlatformExpert::getModelName( char * name
, int maxLength
)
1087 prop
= (OSData
*) getProvider()->getProperty( gIODTCompatibleKey
);
1089 str
= (const char *) prop
->getBytesNoCopy();
1091 if( 0 == strncmp( str
, "AAPL,", strlen( "AAPL," ) ))
1092 str
+= strlen( "AAPL," );
1095 while( (c
= *str
++)) {
1096 if( (c
== '/') || (c
== ' '))
1100 if( len
>= maxLength
)
1110 bool IODTPlatformExpert::getMachineName( char * name
, int maxLength
)
1116 prop
= (OSData
*) getProvider()->getProperty( gIODTModelKey
);
1120 strlcpy( name
, (const char *) prop
->getBytesNoCopy(), maxLength
);
1125 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1127 void IODTPlatformExpert::registerNVRAMController( IONVRAMController
* nvram
)
1129 if (dtNVRAM
) dtNVRAM
->registerNVRAMController(nvram
);
1131 super::registerNVRAMController(nvram
);
1134 int IODTPlatformExpert::haltRestart(unsigned int type
)
1136 if (dtNVRAM
) dtNVRAM
->sync();
1138 return super::haltRestart(type
);
1141 IOReturn
IODTPlatformExpert::readXPRAM(IOByteCount offset
, UInt8
* buffer
,
1144 if (dtNVRAM
) return dtNVRAM
->readXPRAM(offset
, buffer
, length
);
1145 else return kIOReturnNotReady
;
1148 IOReturn
IODTPlatformExpert::writeXPRAM(IOByteCount offset
, UInt8
* buffer
,
1151 if (dtNVRAM
) return dtNVRAM
->writeXPRAM(offset
, buffer
, length
);
1152 else return kIOReturnNotReady
;
1155 IOReturn
IODTPlatformExpert::readNVRAMProperty(
1156 IORegistryEntry
* entry
,
1157 const OSSymbol
** name
, OSData
** value
)
1159 if (dtNVRAM
) return dtNVRAM
->readNVRAMProperty(entry
, name
, value
);
1160 else return kIOReturnNotReady
;
1163 IOReturn
IODTPlatformExpert::writeNVRAMProperty(
1164 IORegistryEntry
* entry
,
1165 const OSSymbol
* name
, OSData
* value
)
1167 if (dtNVRAM
) return dtNVRAM
->writeNVRAMProperty(entry
, name
, value
);
1168 else return kIOReturnNotReady
;
1171 OSDictionary
*IODTPlatformExpert::getNVRAMPartitions(void)
1173 if (dtNVRAM
) return dtNVRAM
->getNVRAMPartitions();
1177 IOReturn
IODTPlatformExpert::readNVRAMPartition(const OSSymbol
* partitionID
,
1178 IOByteCount offset
, UInt8
* buffer
,
1181 if (dtNVRAM
) return dtNVRAM
->readNVRAMPartition(partitionID
, offset
,
1183 else return kIOReturnNotReady
;
1186 IOReturn
IODTPlatformExpert::writeNVRAMPartition(const OSSymbol
* partitionID
,
1187 IOByteCount offset
, UInt8
* buffer
,
1190 if (dtNVRAM
) return dtNVRAM
->writeNVRAMPartition(partitionID
, offset
,
1192 else return kIOReturnNotReady
;
1195 IOByteCount
IODTPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1197 IOByteCount lengthSaved
= 0;
1199 if (dtNVRAM
) lengthSaved
= dtNVRAM
->savePanicInfo(buffer
, length
);
1201 if (lengthSaved
== 0) lengthSaved
= super::savePanicInfo(buffer
, length
);
1206 OSString
* IODTPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
) {
1207 UInt8
* serialNumber
;
1208 unsigned int serialNumberSize
;
1209 unsigned short pos
= 0;
1213 if (myProperty
!= NULL
) {
1214 serialNumberSize
= myProperty
->getLength();
1215 serialNumber
= (UInt8
*)(myProperty
->getBytesNoCopy());
1216 temp
= (char*)serialNumber
;
1217 if (serialNumberSize
> 0) {
1218 // check to see if this is a CTO serial number...
1219 while (pos
< serialNumberSize
&& temp
[pos
] != '-') pos
++;
1221 if (pos
< serialNumberSize
) { // there was a hyphen, so it's a CTO serial number
1222 memcpy(SerialNo
, serialNumber
+ 12, 8);
1223 memcpy(&SerialNo
[8], serialNumber
, 3);
1225 memcpy(&SerialNo
[12], serialNumber
+ 3, 8);
1227 } else { // just a normal serial number
1228 memcpy(SerialNo
, serialNumber
+ 13, 8);
1229 memcpy(&SerialNo
[8], serialNumber
, 3);
1232 return OSString::withCString(SerialNo
);
1239 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1242 #define super IOService
1244 OSDefineMetaClassAndStructors(IOPlatformExpertDevice
, IOService
)
1246 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 0);
1247 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 1);
1248 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 2);
1249 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 3);
1251 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1253 bool IOPlatformExpertDevice::compareName( OSString
* name
,
1254 OSString
** matched
) const
1256 return( IODTCompareNubName( this, name
, matched
));
1260 IOPlatformExpertDevice::initWithArgs(
1261 void * dtTop
, void * p2
, void * p3
, void * p4
)
1263 IORegistryEntry
* dt
= 0;
1264 void * argsData
[ 4 ];
1267 // dtTop may be zero on non- device tree systems
1268 if( dtTop
&& (dt
= IODeviceTreeAlloc( dtTop
)))
1269 ok
= super::init( dt
, gIODTPlane
);
1276 workLoop
= IOWorkLoop::workLoop();
1280 argsData
[ 0 ] = dtTop
;
1285 setProperty("IOPlatformArgs", (void *)argsData
, sizeof(argsData
));
1290 IOWorkLoop
*IOPlatformExpertDevice::getWorkLoop() const
1295 IOReturn
IOPlatformExpertDevice::setProperties( OSObject
* properties
)
1297 OSDictionary
* dictionary
;
1301 status
= super::setProperties( properties
);
1302 if ( status
!= kIOReturnUnsupported
) return status
;
1304 status
= IOUserClient::clientHasPrivilege( current_task( ), kIOClientPrivilegeAdministrator
);
1305 if ( status
!= kIOReturnSuccess
) return status
;
1307 dictionary
= OSDynamicCast( OSDictionary
, properties
);
1308 if ( dictionary
== 0 ) return kIOReturnBadArgument
;
1310 object
= dictionary
->getObject( kIOPlatformUUIDKey
);
1313 IORegistryEntry
* entry
;
1317 string
= ( OSString
* ) getProperty( kIOPlatformUUIDKey
);
1318 if ( string
) return kIOReturnNotPermitted
;
1320 string
= OSDynamicCast( OSString
, object
);
1321 if ( string
== 0 ) return kIOReturnBadArgument
;
1323 status
= uuid_parse( string
->getCStringNoCopy( ), uuid
);
1324 if ( status
!= 0 ) return kIOReturnBadArgument
;
1326 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
1329 entry
->setProperty( "platform-uuid", uuid
, sizeof( uuid_t
) );
1333 setProperty( kIOPlatformUUIDKey
, string
);
1334 publishResource( kIOPlatformUUIDKey
, string
);
1336 return kIOReturnSuccess
;
1339 return kIOReturnUnsupported
;
1342 void IOPlatformExpertDevice::free()
1345 workLoop
->release();
1348 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1351 #define super IOService
1353 OSDefineMetaClassAndStructors(IOPlatformDevice
, IOService
)
1355 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 0);
1356 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 1);
1357 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 2);
1358 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 3);
1360 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1362 bool IOPlatformDevice::compareName( OSString
* name
,
1363 OSString
** matched
) const
1365 return( ((IOPlatformExpert
*)getProvider())->
1366 compareNubName( this, name
, matched
));
1369 IOService
* IOPlatformDevice::matchLocation( IOService
* /* client */ )
1374 IOReturn
IOPlatformDevice::getResources( void )
1376 return( ((IOPlatformExpert
*)getProvider())->getNubResources( this ));
1379 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1381 /*********************************************************************
1382 * IOPanicPlatform class
1384 * If no legitimate IOPlatformDevice matches, this one does and panics
1385 * the kernel with a suitable message.
1386 *********************************************************************/
1388 class IOPanicPlatform
: IOPlatformExpert
{
1389 OSDeclareDefaultStructors(IOPanicPlatform
);
1392 bool start(IOService
* provider
);
1396 OSDefineMetaClassAndStructors(IOPanicPlatform
, IOPlatformExpert
);
1399 bool IOPanicPlatform::start(IOService
* provider
) {
1400 const char * platform_name
= "(unknown platform name)";
1402 if (provider
) platform_name
= provider
->getName();
1404 panic("Unable to find driver for this platform: \"%s\".\n",