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>
51 #include <machine/machine_routines.h>
52 #include <pexpert/pexpert.h>
53 #include <uuid/uuid.h>
56 /* Delay period for UPS halt */
57 #define kUPSDelayHaltCPU_msec (1000*60*5)
59 void printDictionaryKeys (OSDictionary
* inDictionary
, char * inMsg
);
60 static void getCStringForObject(OSObject
*inObj
, char *outStr
, size_t outStrLen
);
62 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
64 #define super IOService
66 OSDefineMetaClassAndStructors(IOPlatformExpert
, IOService
)
68 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 0);
70 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 1);
71 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 2);
72 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 3);
73 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 4);
74 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 5);
75 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 6);
76 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 7);
77 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 8);
78 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 9);
79 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 10);
80 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 11);
82 static IOPlatformExpert
* gIOPlatform
;
83 static OSDictionary
* gIOInterruptControllers
;
84 static IOLock
* gIOInterruptControllersLock
;
86 OSSymbol
* gPlatformInterruptControllerName
;
88 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
90 bool IOPlatformExpert::attach( IOService
* provider
)
93 if( !super::attach( provider
))
99 bool IOPlatformExpert::start( IOService
* provider
)
101 IORangeAllocator
* physicalRanges
;
102 OSData
* busFrequency
;
105 if (!super::start(provider
))
108 // Override the mapper present flag is requested by boot arguments.
109 if (PE_parse_boot_arg("dart", &debugFlags
) && (debugFlags
== 0))
110 removeProperty(kIOPlatformMapperPresentKey
);
112 // Register the presence or lack thereof a system
113 // PCI address mapper with the IOMapper class
114 IOMapper::setMapperRequired(0 != getProperty(kIOPlatformMapperPresentKey
));
116 gIOInterruptControllers
= OSDictionary::withCapacity(1);
117 gIOInterruptControllersLock
= IOLockAlloc();
119 // Correct the bus frequency in the device tree.
120 busFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.bus_clock_rate_hz
, 4);
121 provider
->setProperty("clock-frequency", busFrequency
);
122 busFrequency
->release();
124 gPlatformInterruptControllerName
= (OSSymbol
*)OSSymbol::withCStringNoCopy("IOPlatformInterruptController");
126 physicalRanges
= IORangeAllocator::withRange(0xffffffff, 1, 16,
127 IORangeAllocator::kLocking
);
128 assert(physicalRanges
);
129 setProperty("Platform Memory Ranges", physicalRanges
);
134 PMInstantiatePowerDomains();
136 // Parse the serial-number data and publish a user-readable string
137 OSData
* mydata
= (OSData
*) (provider
->getProperty("serial-number"));
138 if (mydata
!= NULL
) {
139 OSString
*serNoString
= createSystemSerialNumberString(mydata
);
140 if (serNoString
!= NULL
) {
141 provider
->setProperty(kIOPlatformSerialNumberKey
, serNoString
);
142 serNoString
->release();
146 return( configure(provider
) );
149 bool IOPlatformExpert::configure( IOService
* provider
)
155 topLevel
= OSDynamicCast( OSSet
, getProperty("top-level"));
158 while( (dict
= OSDynamicCast( OSDictionary
,
159 topLevel
->getAnyObject()))) {
161 topLevel
->removeObject( dict
);
162 nub
= createNub( dict
);
167 nub
->registerService();
174 IOService
* IOPlatformExpert::createNub( OSDictionary
* from
)
178 nub
= new IOPlatformDevice
;
180 if( !nub
->init( from
)) {
188 bool IOPlatformExpert::compareNubName( const IOService
* nub
,
189 OSString
* name
, OSString
** matched
) const
191 return( nub
->IORegistryEntry::compareName( name
, matched
));
194 IOReturn
IOPlatformExpert::getNubResources( IOService
* nub
)
196 return( kIOReturnSuccess
);
199 long IOPlatformExpert::getBootROMType(void)
201 return _peBootROMType
;
204 long IOPlatformExpert::getChipSetType(void)
206 return _peChipSetType
;
209 long IOPlatformExpert::getMachineType(void)
211 return _peMachineType
;
214 void IOPlatformExpert::setBootROMType(long peBootROMType
)
216 _peBootROMType
= peBootROMType
;
219 void IOPlatformExpert::setChipSetType(long peChipSetType
)
221 _peChipSetType
= peChipSetType
;
224 void IOPlatformExpert::setMachineType(long peMachineType
)
226 _peMachineType
= peMachineType
;
229 bool IOPlatformExpert::getMachineName( char * /*name*/, int /*maxLength*/)
234 bool IOPlatformExpert::getModelName( char * /*name*/, int /*maxLength*/)
239 OSString
* IOPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
)
244 IORangeAllocator
* IOPlatformExpert::getPhysicalRangeAllocator(void)
246 return(OSDynamicCast(IORangeAllocator
,
247 getProperty("Platform Memory Ranges")));
250 int (*PE_halt_restart
)(unsigned int type
) = 0;
252 int IOPlatformExpert::haltRestart(unsigned int type
)
254 if (type
== kPEPanicSync
) return 0;
256 if (type
== kPEHangCPU
) while (1);
258 if (type
== kPEUPSDelayHaltCPU
) {
259 // Stall shutdown for 5 minutes, and if no outside force has
260 // removed our power at that point, proceed with a reboot.
261 IOSleep( kUPSDelayHaltCPU_msec
);
263 // Ideally we never reach this point.
265 type
= kPERestartCPU
;
268 // On ARM kPEPanicRestartCPU is supported in the drivers
269 if (type
== kPEPanicRestartCPU
)
270 type
= kPERestartCPU
;
272 if (PE_halt_restart
) return (*PE_halt_restart
)(type
);
276 void IOPlatformExpert::sleepKernel(void)
282 intState
= ml_set_interrupts_enabled(false);
284 for (cnt
= 0; cnt
< 10000; cnt
++) {
288 ml_set_interrupts_enabled(intState
);
290 // PE_initialize_console(0, kPEDisableScreen);
294 // PE_initialize_console(0, kPEEnableScreen);
298 long IOPlatformExpert::getGMTTimeOfDay(void)
303 void IOPlatformExpert::setGMTTimeOfDay(long secs
)
308 IOReturn
IOPlatformExpert::getConsoleInfo( PE_Video
* consoleInfo
)
310 return( PE_current_console( consoleInfo
));
313 IOReturn
IOPlatformExpert::setConsoleInfo( PE_Video
* consoleInfo
,
316 return( PE_initialize_console( consoleInfo
, op
));
319 IOReturn
IOPlatformExpert::registerInterruptController(OSSymbol
*name
, IOInterruptController
*interruptController
)
321 IOLockLock(gIOInterruptControllersLock
);
323 gIOInterruptControllers
->setObject(name
, interruptController
);
325 IOLockWakeup(gIOInterruptControllersLock
,
326 gIOInterruptControllers
, /* one-thread */ false);
328 IOLockUnlock(gIOInterruptControllersLock
);
330 return kIOReturnSuccess
;
333 IOInterruptController
*IOPlatformExpert::lookUpInterruptController(OSSymbol
*name
)
337 IOLockLock(gIOInterruptControllersLock
);
340 object
= gIOInterruptControllers
->getObject(name
);
345 IOLockSleep(gIOInterruptControllersLock
,
346 gIOInterruptControllers
, THREAD_UNINT
);
349 IOLockUnlock(gIOInterruptControllersLock
);
350 return OSDynamicCast(IOInterruptController
, object
);
354 void IOPlatformExpert::setCPUInterruptProperties(IOService
*service
)
356 IOCPUInterruptController
*controller
;
358 controller
= OSDynamicCast(IOCPUInterruptController
, waitForService(serviceMatching("IOCPUInterruptController")));
359 if (controller
) controller
->setCPUInterruptProperties(service
);
362 bool IOPlatformExpert::atInterruptLevel(void)
364 return ml_at_interrupt_context();
367 bool IOPlatformExpert::platformAdjustService(IOService */
*service*/
)
373 //*********************************************************************************
376 //*********************************************************************************
378 void IOPlatformExpert::
379 PMLog(const char *who
, unsigned long event
,
380 unsigned long param1
, unsigned long param2
)
382 UInt32 debugFlags
= gIOKitDebug
;
384 if (debugFlags
& kIOLogPower
) {
386 uint32_t nows
, nowus
;
387 clock_get_system_microtime(&nows
, &nowus
);
388 nowus
+= (nows
% 1000) * 1000000;
390 kprintf("pm%u %x %.30s %d %x %x\n",
391 nowus
, (unsigned) current_thread(), who
, // Identity
392 (int) event
, param1
, param2
); // Args
394 if (debugFlags
& kIOLogTracePower
) {
395 static const UInt32 sStartStopBitField
[] =
396 { 0x00000000, 0x00000040 }; // Only Program Hardware so far
398 // Arcane formula from Hacker's Delight by Warren
399 // abs(x) = ((int) x >> 31) ^ (x + ((int) x >> 31))
400 UInt32 sgnevent
= ((long) event
>> 31);
401 UInt32 absevent
= sgnevent
^ (event
+ sgnevent
);
402 UInt32 code
= IODBG_POWER(absevent
);
404 UInt32 bit
= 1 << (absevent
& 0x1f);
405 if (absevent
< sizeof(sStartStopBitField
) * 8
406 && (sStartStopBitField
[absevent
>> 5] & bit
) ) {
407 // Or in the START or END bits, Start = 1 & END = 2
408 // If sgnevent == 0 then START - 0 => START
409 // else if sgnevent == -1 then START - -1 => END
410 code
|= DBG_FUNC_START
- sgnevent
;
413 // Record the timestamp, wish I had a this pointer
414 IOTimeStampConstant(code
, (UInt32
) who
, event
, param1
, param2
);
420 //*********************************************************************************
421 // PMInstantiatePowerDomains
423 // In this vanilla implementation, a Root Power Domain is instantiated.
424 // All other objects which register will be children of this Root.
425 // Where this is inappropriate, PMInstantiatePowerDomains is overridden
426 // in a platform-specific subclass.
427 //*********************************************************************************
429 void IOPlatformExpert::PMInstantiatePowerDomains ( void )
431 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
)
754 /* 30 seconds has elapsed - resume shutdown */
755 if(gIOPlatform
) gIOPlatform
->haltRestart(type
);
762 * Callouts from BSD for machine name & model
765 boolean_t
PEGetMachineName( char * name
, int maxLength
)
768 return( gIOPlatform
->getMachineName( name
, maxLength
));
773 boolean_t
PEGetModelName( char * name
, int maxLength
)
776 return( gIOPlatform
->getModelName( name
, maxLength
));
781 int PEGetPlatformEpoch(void)
784 return( gIOPlatform
->getBootROMType());
789 int PEHaltRestart(unsigned int type
)
791 IOPMrootDomain
*pmRootDomain
= IOService::getPMRootDomain();
792 AbsoluteTime deadline
;
793 thread_call_t shutdown_hang
;
794 unsigned int tell_type
;
796 if(type
== kPEHaltCPU
|| type
== kPERestartCPU
|| type
== kPEUPSDelayHaltCPU
)
798 /* Notify IOKit PM clients of shutdown/restart
799 Clients subscribe to this message with a call to
800 IOService::registerInterest()
803 /* Spawn a thread that will panic in 30 seconds.
804 If all goes well the machine will be off by the time
807 shutdown_hang
= thread_call_allocate( &IOShutdownNotificationsTimedOut
,
808 (thread_call_param_t
) type
);
809 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
810 thread_call_enter1_delayed( shutdown_hang
, 0, deadline
);
813 if( kPEUPSDelayHaltCPU
== type
) {
814 tell_type
= kPEHaltCPU
;
819 pmRootDomain
->handlePlatformHaltRestart(tell_type
);
820 /* This notification should have few clients who all do
821 their work synchronously.
823 In this "shutdown notification" context we don't give
824 drivers the option of working asynchronously and responding
825 later. PM internals make it very hard to wait for asynchronous
830 if (gIOPlatform
) return gIOPlatform
->haltRestart(type
);
834 UInt32
PESavePanicInfo(UInt8
*buffer
, UInt32 length
)
836 if (gIOPlatform
!= 0) return gIOPlatform
->savePanicInfo(buffer
, length
);
840 long PEGetGMTTimeOfDay(void)
845 result
= gIOPlatform
->getGMTTimeOfDay();
850 void PESetGMTTimeOfDay(long secs
)
853 gIOPlatform
->setGMTTimeOfDay(secs
);
858 void IOPlatformExpert::registerNVRAMController(IONVRAMController
* caller
)
861 IORegistryEntry
* nvram
;
864 nvram
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
867 data
= OSDynamicCast( OSData
, nvram
->getProperty( "platform-uuid" ) );
868 if ( data
&& data
->getLength( ) == sizeof( uuid_t
) )
871 uuid_unparse( ( UInt8
* ) data
->getBytesNoCopy( ), uuid
);
873 string
= OSString::withCString( uuid
);
876 getProvider( )->setProperty( kIOPlatformUUIDKey
, string
);
877 publishResource( kIOPlatformUUIDKey
, string
);
886 publishResource("IONVRAM");
889 IOReturn
IOPlatformExpert::callPlatformFunction(const OSSymbol
*functionName
,
890 bool waitForFunction
,
891 void *param1
, void *param2
,
892 void *param3
, void *param4
)
894 IOService
*service
, *_resources
;
896 if (waitForFunction
) {
897 _resources
= waitForService(resourceMatching(functionName
));
899 _resources
= resources();
901 if (_resources
== 0) return kIOReturnUnsupported
;
903 service
= OSDynamicCast(IOService
, _resources
->getProperty(functionName
));
904 if (service
== 0) return kIOReturnUnsupported
;
906 return service
->callPlatformFunction(functionName
, waitForFunction
,
907 param1
, param2
, param3
, param4
);
910 IOByteCount
IOPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
915 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
918 #define super IOPlatformExpert
920 OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert
, IOPlatformExpert
)
922 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 0);
923 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 1);
924 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 2);
925 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 3);
926 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 4);
927 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 5);
928 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 6);
929 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 7);
931 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
933 IOService
* IODTPlatformExpert::probe( IOService
* provider
,
936 if( !super::probe( provider
, score
))
939 // check machine types
940 if( !provider
->compareNames( getProperty( gIONameMatchKey
) ))
946 bool IODTPlatformExpert::configure( IOService
* provider
)
948 if( !super::configure( provider
))
951 processTopLevel( provider
);
956 IOService
* IODTPlatformExpert::createNub( IORegistryEntry
* from
)
960 nub
= new IOPlatformDevice
;
962 if( !nub
->init( from
, gIODTPlane
)) {
970 bool IODTPlatformExpert::createNubs( IOService
* parent
, OSIterator
* iter
)
972 IORegistryEntry
* next
;
977 while( (next
= (IORegistryEntry
*) iter
->getNextObject())) {
979 if( 0 == (nub
= createNub( next
)))
982 nub
->attach( parent
);
983 nub
->registerService();
991 void IODTPlatformExpert::processTopLevel( IORegistryEntry
* rootEntry
)
994 IORegistryEntry
* next
;
995 IORegistryEntry
* cpus
;
996 IORegistryEntry
* options
;
999 kids
= IODTFindMatchingEntries( rootEntry
, 0, deleteList() );
1001 while( (next
= (IORegistryEntry
*)kids
->getNextObject())) {
1002 next
->detachAll( gIODTPlane
);
1007 // Publish an IODTNVRAM class on /options.
1008 options
= rootEntry
->childFromPath("options", gIODTPlane
);
1010 dtNVRAM
= new IODTNVRAM
;
1012 if (!dtNVRAM
->init(options
, gIODTPlane
)) {
1016 dtNVRAM
->attach(this);
1017 dtNVRAM
->registerService();
1022 // Publish the cpus.
1023 cpus
= rootEntry
->childFromPath( "cpus", gIODTPlane
);
1025 createNubs( this, IODTFindMatchingEntries( cpus
, kIODTExclusive
, 0));
1027 // publish top level, minus excludeList
1028 createNubs( this, IODTFindMatchingEntries( rootEntry
, kIODTExclusive
, excludeList()));
1031 IOReturn
IODTPlatformExpert::getNubResources( IOService
* nub
)
1033 if( nub
->getDeviceMemory())
1034 return( kIOReturnSuccess
);
1036 IODTResolveAddressing( nub
, "reg", 0);
1038 return( kIOReturnSuccess
);
1041 bool IODTPlatformExpert::compareNubName( const IOService
* nub
,
1042 OSString
* name
, OSString
** matched
) const
1044 return( IODTCompareNubName( nub
, name
, matched
)
1045 || super::compareNubName( nub
, name
, matched
) );
1048 bool IODTPlatformExpert::getModelName( char * name
, int maxLength
)
1058 prop
= (OSData
*) getProvider()->getProperty( gIODTCompatibleKey
);
1060 str
= (const char *) prop
->getBytesNoCopy();
1062 if( 0 == strncmp( str
, "AAPL,", strlen( "AAPL," ) ))
1063 str
+= strlen( "AAPL," );
1066 while( (c
= *str
++)) {
1067 if( (c
== '/') || (c
== ' '))
1071 if( len
>= maxLength
)
1081 bool IODTPlatformExpert::getMachineName( char * name
, int maxLength
)
1087 prop
= (OSData
*) getProvider()->getProperty( gIODTModelKey
);
1091 strlcpy( name
, (const char *) prop
->getBytesNoCopy(), maxLength
);
1096 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1098 void IODTPlatformExpert::registerNVRAMController( IONVRAMController
* nvram
)
1100 if (dtNVRAM
) dtNVRAM
->registerNVRAMController(nvram
);
1102 super::registerNVRAMController(nvram
);
1105 int IODTPlatformExpert::haltRestart(unsigned int type
)
1107 if (dtNVRAM
) dtNVRAM
->sync();
1109 return super::haltRestart(type
);
1112 IOReturn
IODTPlatformExpert::readXPRAM(IOByteCount offset
, UInt8
* buffer
,
1115 if (dtNVRAM
) return dtNVRAM
->readXPRAM(offset
, buffer
, length
);
1116 else return kIOReturnNotReady
;
1119 IOReturn
IODTPlatformExpert::writeXPRAM(IOByteCount offset
, UInt8
* buffer
,
1122 if (dtNVRAM
) return dtNVRAM
->writeXPRAM(offset
, buffer
, length
);
1123 else return kIOReturnNotReady
;
1126 IOReturn
IODTPlatformExpert::readNVRAMProperty(
1127 IORegistryEntry
* entry
,
1128 const OSSymbol
** name
, OSData
** value
)
1130 if (dtNVRAM
) return dtNVRAM
->readNVRAMProperty(entry
, name
, value
);
1131 else return kIOReturnNotReady
;
1134 IOReturn
IODTPlatformExpert::writeNVRAMProperty(
1135 IORegistryEntry
* entry
,
1136 const OSSymbol
* name
, OSData
* value
)
1138 if (dtNVRAM
) return dtNVRAM
->writeNVRAMProperty(entry
, name
, value
);
1139 else return kIOReturnNotReady
;
1142 OSDictionary
*IODTPlatformExpert::getNVRAMPartitions(void)
1144 if (dtNVRAM
) return dtNVRAM
->getNVRAMPartitions();
1148 IOReturn
IODTPlatformExpert::readNVRAMPartition(const OSSymbol
* partitionID
,
1149 IOByteCount offset
, UInt8
* buffer
,
1152 if (dtNVRAM
) return dtNVRAM
->readNVRAMPartition(partitionID
, offset
,
1154 else return kIOReturnNotReady
;
1157 IOReturn
IODTPlatformExpert::writeNVRAMPartition(const OSSymbol
* partitionID
,
1158 IOByteCount offset
, UInt8
* buffer
,
1161 if (dtNVRAM
) return dtNVRAM
->writeNVRAMPartition(partitionID
, offset
,
1163 else return kIOReturnNotReady
;
1166 IOByteCount
IODTPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1168 IOByteCount lengthSaved
= 0;
1170 if (dtNVRAM
) lengthSaved
= dtNVRAM
->savePanicInfo(buffer
, length
);
1172 if (lengthSaved
== 0) lengthSaved
= super::savePanicInfo(buffer
, length
);
1177 OSString
* IODTPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
) {
1178 UInt8
* serialNumber
;
1179 unsigned int serialNumberSize
;
1180 unsigned short pos
= 0;
1184 if (myProperty
!= NULL
) {
1185 serialNumberSize
= myProperty
->getLength();
1186 serialNumber
= (UInt8
*)(myProperty
->getBytesNoCopy());
1187 temp
= (char*)serialNumber
;
1188 if (serialNumberSize
> 0) {
1189 // check to see if this is a CTO serial number...
1190 while (pos
< serialNumberSize
&& temp
[pos
] != '-') pos
++;
1192 if (pos
< serialNumberSize
) { // there was a hyphen, so it's a CTO serial number
1193 memcpy(SerialNo
, serialNumber
+ 12, 8);
1194 memcpy(&SerialNo
[8], serialNumber
, 3);
1196 memcpy(&SerialNo
[12], serialNumber
+ 3, 8);
1198 } else { // just a normal serial number
1199 memcpy(SerialNo
, serialNumber
+ 13, 8);
1200 memcpy(&SerialNo
[8], serialNumber
, 3);
1203 return OSString::withCString(SerialNo
);
1210 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1213 #define super IOService
1215 OSDefineMetaClassAndStructors(IOPlatformExpertDevice
, IOService
)
1217 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 0);
1218 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 1);
1219 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 2);
1220 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 3);
1222 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1224 bool IOPlatformExpertDevice::compareName( OSString
* name
,
1225 OSString
** matched
) const
1227 return( IODTCompareNubName( this, name
, matched
));
1231 IOPlatformExpertDevice::initWithArgs(
1232 void * dtTop
, void * p2
, void * p3
, void * p4
)
1234 IORegistryEntry
* dt
= 0;
1235 void * argsData
[ 4 ];
1238 // dtTop may be zero on non- device tree systems
1239 if( dtTop
&& (dt
= IODeviceTreeAlloc( dtTop
)))
1240 ok
= super::init( dt
, gIODTPlane
);
1247 workLoop
= IOWorkLoop::workLoop();
1251 argsData
[ 0 ] = dtTop
;
1256 setProperty("IOPlatformArgs", (void *)argsData
, sizeof(argsData
));
1261 IOWorkLoop
*IOPlatformExpertDevice::getWorkLoop() const
1266 IOReturn
IOPlatformExpertDevice::setProperties( OSObject
* properties
)
1268 OSDictionary
* dictionary
;
1272 status
= super::setProperties( properties
);
1273 if ( status
!= kIOReturnUnsupported
) return status
;
1275 status
= IOUserClient::clientHasPrivilege( current_task( ), kIOClientPrivilegeAdministrator
);
1276 if ( status
!= kIOReturnSuccess
) return status
;
1278 dictionary
= OSDynamicCast( OSDictionary
, properties
);
1279 if ( dictionary
== 0 ) return kIOReturnBadArgument
;
1281 object
= dictionary
->getObject( kIOPlatformUUIDKey
);
1284 IORegistryEntry
* nvram
;
1288 string
= ( OSString
* ) getProperty( kIOPlatformUUIDKey
);
1289 if ( string
) return kIOReturnNotPermitted
;
1291 string
= OSDynamicCast( OSString
, object
);
1292 if ( string
== 0 ) return kIOReturnBadArgument
;
1294 status
= uuid_parse( string
->getCStringNoCopy( ), uuid
);
1295 if ( status
!= 0 ) return kIOReturnBadArgument
;
1297 nvram
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
1300 nvram
->setProperty( "platform-uuid", uuid
, sizeof( uuid_t
) );
1304 setProperty( kIOPlatformUUIDKey
, string
);
1305 publishResource( kIOPlatformUUIDKey
, string
);
1307 return kIOReturnSuccess
;
1310 return kIOReturnUnsupported
;
1313 void IOPlatformExpertDevice::free()
1316 workLoop
->release();
1319 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1322 #define super IOService
1324 OSDefineMetaClassAndStructors(IOPlatformDevice
, IOService
)
1326 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 0);
1327 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 1);
1328 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 2);
1329 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 3);
1331 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1333 bool IOPlatformDevice::compareName( OSString
* name
,
1334 OSString
** matched
) const
1336 return( ((IOPlatformExpert
*)getProvider())->
1337 compareNubName( this, name
, matched
));
1340 IOService
* IOPlatformDevice::matchLocation( IOService
* /* client */ )
1345 IOReturn
IOPlatformDevice::getResources( void )
1347 return( ((IOPlatformExpert
*)getProvider())->getNubResources( this ));
1350 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1352 /*********************************************************************
1353 * IOPanicPlatform class
1355 * If no legitimate IOPlatformDevice matches, this one does and panics
1356 * the kernel with a suitable message.
1357 *********************************************************************/
1359 class IOPanicPlatform
: IOPlatformExpert
{
1360 OSDeclareDefaultStructors(IOPanicPlatform
);
1363 bool start(IOService
* provider
);
1367 OSDefineMetaClassAndStructors(IOPanicPlatform
, IOPlatformExpert
);
1370 bool IOPanicPlatform::start(IOService
* provider
) {
1371 const char * platform_name
= "(unknown platform name)";
1373 if (provider
) platform_name
= provider
->getName();
1375 panic("Unable to find driver for this platform: \"%s\".\n",