2 * Copyright (c) 1998-2010 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <IOKit/IOCPU.h>
30 #include <IOKit/IODeviceTreeSupport.h>
31 #include <IOKit/IOKitDebug.h>
32 #include <IOKit/IOMapper.h>
33 #include <IOKit/IOMessage.h>
34 #include <IOKit/IONVRAM.h>
35 #include <IOKit/IOPlatformExpert.h>
36 #include <IOKit/IORangeAllocator.h>
37 #include <IOKit/IOWorkLoop.h>
38 #include <IOKit/pwr_mgt/RootDomain.h>
39 #include <IOKit/IOKitKeys.h>
40 #include <IOKit/IOTimeStamp.h>
41 #include <IOKit/IOUserClient.h>
43 #include <IOKit/system.h>
45 #include <libkern/c++/OSContainers.h>
46 #include <libkern/crypto/sha1.h>
47 #include <libkern/OSAtomic.h>
50 #include <machine/machine_routines.h>
51 #include <pexpert/pexpert.h>
52 #include <uuid/uuid.h>
55 void printDictionaryKeys (OSDictionary
* inDictionary
, char * inMsg
);
56 static void getCStringForObject(OSObject
*inObj
, char *outStr
, size_t outStrLen
);
58 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
60 #define super IOService
62 OSDefineMetaClassAndStructors(IOPlatformExpert
, IOService
)
64 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 0);
66 OSMetaClassDefineReservedUsed(IOPlatformExpert
, 1);
67 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 2);
68 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 3);
69 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 4);
70 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 5);
71 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 6);
72 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 7);
73 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 8);
74 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 9);
75 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 10);
76 OSMetaClassDefineReservedUnused(IOPlatformExpert
, 11);
78 static IOPlatformExpert
* gIOPlatform
;
79 static OSDictionary
* gIOInterruptControllers
;
80 static IOLock
* gIOInterruptControllersLock
;
81 static IODTNVRAM
*gIOOptionsEntry
;
83 OSSymbol
* gPlatformInterruptControllerName
;
85 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
87 bool IOPlatformExpert::attach( IOService
* provider
)
90 if( !super::attach( provider
))
96 bool IOPlatformExpert::start( IOService
* provider
)
98 IORangeAllocator
* physicalRanges
;
99 OSData
* busFrequency
;
102 if (!super::start(provider
))
105 // Override the mapper present flag is requested by boot arguments.
106 if (PE_parse_boot_argn("dart", &debugFlags
, sizeof (debugFlags
)) && (debugFlags
== 0))
107 removeProperty(kIOPlatformMapperPresentKey
);
108 if (PE_parse_boot_argn("-x", &debugFlags
, sizeof (debugFlags
)))
109 removeProperty(kIOPlatformMapperPresentKey
);
111 // Register the presence or lack thereof a system
112 // PCI address mapper with the IOMapper class
113 IOMapper::setMapperRequired(0 != getProperty(kIOPlatformMapperPresentKey
));
115 gIOInterruptControllers
= OSDictionary::withCapacity(1);
116 gIOInterruptControllersLock
= IOLockAlloc();
118 // Correct the bus frequency in the device tree.
119 busFrequency
= OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo
.bus_clock_rate_hz
, 4);
120 provider
->setProperty("clock-frequency", busFrequency
);
121 busFrequency
->release();
123 gPlatformInterruptControllerName
= (OSSymbol
*)OSSymbol::withCStringNoCopy("IOPlatformInterruptController");
125 physicalRanges
= IORangeAllocator::withRange(0xffffffff, 1, 16,
126 IORangeAllocator::kLocking
);
127 assert(physicalRanges
);
128 setProperty("Platform Memory Ranges", physicalRanges
);
133 PMInstantiatePowerDomains();
135 // Parse the serial-number data and publish a user-readable string
136 OSData
* mydata
= (OSData
*) (provider
->getProperty("serial-number"));
137 if (mydata
!= NULL
) {
138 OSString
*serNoString
= createSystemSerialNumberString(mydata
);
139 if (serNoString
!= NULL
) {
140 provider
->setProperty(kIOPlatformSerialNumberKey
, serNoString
);
141 serNoString
->release();
145 return( configure(provider
) );
148 bool IOPlatformExpert::configure( IOService
* provider
)
154 topLevel
= OSDynamicCast( OSSet
, getProperty("top-level"));
157 while( (dict
= OSDynamicCast( OSDictionary
,
158 topLevel
->getAnyObject()))) {
160 topLevel
->removeObject( dict
);
161 nub
= createNub( dict
);
166 nub
->registerService();
173 IOService
* IOPlatformExpert::createNub( OSDictionary
* from
)
177 nub
= new IOPlatformDevice
;
179 if( !nub
->init( from
)) {
187 bool IOPlatformExpert::compareNubName( const IOService
* nub
,
188 OSString
* name
, OSString
** matched
) const
190 return( nub
->IORegistryEntry::compareName( name
, matched
));
193 IOReturn
IOPlatformExpert::getNubResources( IOService
* nub
)
195 return( kIOReturnSuccess
);
198 long IOPlatformExpert::getBootROMType(void)
200 return _peBootROMType
;
203 long IOPlatformExpert::getChipSetType(void)
205 return _peChipSetType
;
208 long IOPlatformExpert::getMachineType(void)
210 return _peMachineType
;
213 void IOPlatformExpert::setBootROMType(long peBootROMType
)
215 _peBootROMType
= peBootROMType
;
218 void IOPlatformExpert::setChipSetType(long peChipSetType
)
220 _peChipSetType
= peChipSetType
;
223 void IOPlatformExpert::setMachineType(long peMachineType
)
225 _peMachineType
= peMachineType
;
228 bool IOPlatformExpert::getMachineName( char * /*name*/, int /*maxLength*/)
233 bool IOPlatformExpert::getModelName( char * /*name*/, int /*maxLength*/)
238 OSString
* IOPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
)
243 IORangeAllocator
* IOPlatformExpert::getPhysicalRangeAllocator(void)
245 return(OSDynamicCast(IORangeAllocator
,
246 getProperty("Platform Memory Ranges")));
249 int (*PE_halt_restart
)(unsigned int type
) = 0;
251 int IOPlatformExpert::haltRestart(unsigned int type
)
253 if (type
== kPEPanicSync
) return 0;
255 if (type
== kPEHangCPU
) while (true) {}
257 if (type
== kPEUPSDelayHaltCPU
) {
258 // RestartOnPowerLoss feature was turned on, proceed with shutdown.
262 // On ARM kPEPanicRestartCPU is supported in the drivers
263 if (type
== kPEPanicRestartCPU
)
264 type
= kPERestartCPU
;
266 if (PE_halt_restart
) return (*PE_halt_restart
)(type
);
270 void IOPlatformExpert::sleepKernel(void)
276 intState
= ml_set_interrupts_enabled(false);
278 for (cnt
= 0; cnt
< 10000; cnt
++) {
282 ml_set_interrupts_enabled(intState
);
284 // PE_initialize_console(0, kPEDisableScreen);
288 // PE_initialize_console(0, kPEEnableScreen);
292 long IOPlatformExpert::getGMTTimeOfDay(void)
297 void IOPlatformExpert::setGMTTimeOfDay(long secs
)
302 IOReturn
IOPlatformExpert::getConsoleInfo( PE_Video
* consoleInfo
)
304 return( PE_current_console( consoleInfo
));
307 IOReturn
IOPlatformExpert::setConsoleInfo( PE_Video
* consoleInfo
,
310 return( PE_initialize_console( consoleInfo
, op
));
313 IOReturn
IOPlatformExpert::registerInterruptController(OSSymbol
*name
, IOInterruptController
*interruptController
)
315 IOLockLock(gIOInterruptControllersLock
);
317 gIOInterruptControllers
->setObject(name
, interruptController
);
319 IOLockWakeup(gIOInterruptControllersLock
,
320 gIOInterruptControllers
, /* one-thread */ false);
322 IOLockUnlock(gIOInterruptControllersLock
);
324 return kIOReturnSuccess
;
327 IOInterruptController
*IOPlatformExpert::lookUpInterruptController(OSSymbol
*name
)
331 IOLockLock(gIOInterruptControllersLock
);
334 object
= gIOInterruptControllers
->getObject(name
);
339 IOLockSleep(gIOInterruptControllersLock
,
340 gIOInterruptControllers
, THREAD_UNINT
);
343 IOLockUnlock(gIOInterruptControllersLock
);
344 return OSDynamicCast(IOInterruptController
, object
);
348 void IOPlatformExpert::setCPUInterruptProperties(IOService
*service
)
350 IOCPUInterruptController
*controller
;
352 controller
= OSDynamicCast(IOCPUInterruptController
, waitForService(serviceMatching("IOCPUInterruptController")));
353 if (controller
) controller
->setCPUInterruptProperties(service
);
356 bool IOPlatformExpert::atInterruptLevel(void)
358 return ml_at_interrupt_context();
361 bool IOPlatformExpert::platformAdjustService(IOService */
*service*/
)
367 //*********************************************************************************
370 //*********************************************************************************
372 void IOPlatformExpert::
373 PMLog(const char *who
, unsigned long event
,
374 unsigned long param1
, unsigned long param2
)
378 clock_get_system_microtime(&nows
, &nowus
);
379 nowus
+= (nows
% 1000) * 1000000;
381 kprintf("pm%u %p %.30s %d %lx %lx\n",
382 nowus
, current_thread(), who
, // Identity
383 (int) event
, (long) param1
, (long) param2
); // Args
387 //*********************************************************************************
388 // PMInstantiatePowerDomains
390 // In this vanilla implementation, a Root Power Domain is instantiated.
391 // All other objects which register will be children of this Root.
392 // Where this is inappropriate, PMInstantiatePowerDomains is overridden
393 // in a platform-specific subclass.
394 //*********************************************************************************
396 void IOPlatformExpert::PMInstantiatePowerDomains ( void )
398 root
= new IOPMrootDomain
;
405 //*********************************************************************************
408 // In this vanilla implementation, all callers are made children of the root power domain.
409 // Where this is inappropriate, PMRegisterDevice is overridden in a platform-specific subclass.
410 //*********************************************************************************
412 void IOPlatformExpert::PMRegisterDevice(IOService
* theNub
, IOService
* theDevice
)
414 root
->addPowerChild ( theDevice
);
417 //*********************************************************************************
420 //*********************************************************************************
422 bool IOPlatformExpert::hasPMFeature (unsigned long featureMask
)
424 return ((_pePMFeatures
& featureMask
) != 0);
427 //*********************************************************************************
430 //*********************************************************************************
432 bool IOPlatformExpert::hasPrivPMFeature (unsigned long privFeatureMask
)
434 return ((_pePrivPMFeatures
& privFeatureMask
) != 0);
437 //*********************************************************************************
438 // numBatteriesSupported
440 //*********************************************************************************
442 int IOPlatformExpert::numBatteriesSupported (void)
444 return (_peNumBatteriesSupported
);
447 //*********************************************************************************
450 // This method is called by the instantiated sublass of the platform expert to
451 // determine how a device should be inserted into the Power Domain. The subclass
452 // provides an XML power tree description against which a device is matched based
453 // on class and provider. If a match is found this routine returns true in addition
454 // to flagging the description tree at the appropriate node that a device has been
455 // registered for the given service.
456 //*********************************************************************************
458 bool IOPlatformExpert::CheckSubTree (OSArray
* inSubTree
, IOService
* theNub
, IOService
* theDevice
, OSDictionary
* theParent
)
461 unsigned int numPowerTreeNodes
;
462 OSDictionary
* entry
;
463 OSDictionary
* matchingDictionary
;
464 OSDictionary
* providerDictionary
;
465 OSDictionary
* deviceDictionary
;
466 OSDictionary
* nubDictionary
;
468 bool nodeFound
= false;
469 bool continueSearch
= false;
470 bool deviceMatch
= false;
471 bool providerMatch
= false;
472 bool multiParentMatch
= false;
474 if ( (NULL
== theDevice
) || (NULL
== inSubTree
) )
477 numPowerTreeNodes
= inSubTree
->getCount ();
479 // iterate through the power tree to find a home for this device
481 for ( i
= 0; i
< numPowerTreeNodes
; i
++ ) {
483 entry
= (OSDictionary
*) inSubTree
->getObject (i
);
485 matchingDictionary
= (OSDictionary
*) entry
->getObject ("device");
486 providerDictionary
= (OSDictionary
*) entry
->getObject ("provider");
488 deviceMatch
= true; // if no matching dictionary, this is not a criteria and so must match
489 if ( matchingDictionary
) {
491 if ( NULL
!= (deviceDictionary
= theDevice
->dictionaryWithProperties ())) {
492 deviceMatch
= deviceDictionary
->isEqualTo ( matchingDictionary
, matchingDictionary
);
493 deviceDictionary
->release ();
497 providerMatch
= true; // we indicate a match if there is no nub or provider
498 if ( theNub
&& providerDictionary
) {
499 providerMatch
= false;
500 if ( NULL
!= (nubDictionary
= theNub
->dictionaryWithProperties ()) ) {
501 providerMatch
= nubDictionary
->isEqualTo ( providerDictionary
, providerDictionary
);
502 nubDictionary
->release ();
506 multiParentMatch
= true; // again we indicate a match if there is no multi-parent node
507 if (deviceMatch
&& providerMatch
) {
508 if (NULL
!= multipleParentKeyValue
) {
509 OSNumber
* aNumber
= (OSNumber
*) entry
->getObject ("multiple-parent");
510 multiParentMatch
= (NULL
!= aNumber
) ? multipleParentKeyValue
->isEqualTo (aNumber
) : false;
514 nodeFound
= (deviceMatch
&& providerMatch
&& multiParentMatch
);
516 // if the power tree specifies a provider dictionary but theNub is
517 // NULL then we cannot match with this entry.
519 if ( theNub
== NULL
&& providerDictionary
!= NULL
)
522 // if this node is THE ONE...then register the device
525 if (RegisterServiceInTree (theDevice
, entry
, theParent
, theNub
) ) {
527 if ( kIOLogPower
& gIOKitDebug
)
528 IOLog ("PMRegisterDevice/CheckSubTree - service registered!\n");
530 numInstancesRegistered
++;
532 // determine if we need to search for additional nodes for this item
533 multipleParentKeyValue
= (OSNumber
*) entry
->getObject ("multiple-parent");
539 continueSearch
= ( (false == nodeFound
) || (NULL
!= multipleParentKeyValue
) );
541 if ( continueSearch
&& (NULL
!= (children
= (OSArray
*) entry
->getObject ("children"))) ) {
542 nodeFound
= CheckSubTree ( children
, theNub
, theDevice
, entry
);
543 continueSearch
= ( (false == nodeFound
) || (NULL
!= multipleParentKeyValue
) );
546 if ( false == continueSearch
)
550 return ( nodeFound
);
553 //*********************************************************************************
554 // RegisterServiceInTree
556 // Register a device at the specified node of our power tree.
557 //*********************************************************************************
559 bool IOPlatformExpert::RegisterServiceInTree (IOService
* theService
, OSDictionary
* theTreeNode
, OSDictionary
* theTreeParentNode
, IOService
* theProvider
)
561 IOService
* aService
;
562 bool registered
= false;
564 unsigned int numChildren
;
565 OSDictionary
* child
;
567 // make sure someone is not already registered here
569 if ( NULL
== theTreeNode
->getObject ("service") ) {
571 if ( theTreeNode
->setObject ("service", OSDynamicCast ( OSObject
, theService
)) ) {
573 // 1. CHILDREN ------------------
575 // we registered the node in the tree...now if the node has children
576 // registered we must tell this service to add them.
578 if ( NULL
!= (children
= (OSArray
*) theTreeNode
->getObject ("children")) ) {
579 numChildren
= children
->getCount ();
580 for ( unsigned int i
= 0; i
< numChildren
; i
++ ) {
581 if ( NULL
!= (child
= (OSDictionary
*) children
->getObject (i
)) ) {
582 if ( NULL
!= (aService
= (IOService
*) child
->getObject ("service")) )
583 theService
->addPowerChild (aService
);
588 // 2. PARENT --------------------
590 // also we must notify the parent of this node (if a registered service
591 // exists there) of a new child.
593 if ( theTreeParentNode
) {
594 if ( NULL
!= (aService
= (IOService
*) theTreeParentNode
->getObject ("service")) )
595 if (aService
!= theProvider
)
596 aService
->addPowerChild (theService
);
606 //*********************************************************************************
607 // printDictionaryKeys
609 // Print the keys for the given dictionary and selected contents.
610 //*********************************************************************************
611 void printDictionaryKeys (OSDictionary
* inDictionary
, char * inMsg
)
613 OSCollectionIterator
* mcoll
= OSCollectionIterator::withCollection (inDictionary
);
620 mkey
= OSDynamicCast (OSSymbol
, mcoll
->getNextObject ());
624 // kprintf ("dictionary key #%d: %s\n", i, mkey->getCStringNoCopy () );
626 // if this is the IOClass key, print it's contents
628 if ( mkey
->isEqualTo ("IOClass") ) {
629 ioClass
= (OSString
*) inDictionary
->getObject ("IOClass");
630 if ( ioClass
) IOLog ("%s IOClass is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
633 // if this is an IOProviderClass key print it
635 if ( mkey
->isEqualTo ("IOProviderClass") ) {
636 ioClass
= (OSString
*) inDictionary
->getObject ("IOProviderClass");
637 if ( ioClass
) IOLog ("%s IOProviderClass is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
641 // also print IONameMatch keys
642 if ( mkey
->isEqualTo ("IONameMatch") ) {
643 ioClass
= (OSString
*) inDictionary
->getObject ("IONameMatch");
644 if ( ioClass
) IOLog ("%s IONameMatch is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
647 // also print IONameMatched keys
649 if ( mkey
->isEqualTo ("IONameMatched") ) {
650 ioClass
= (OSString
*) inDictionary
->getObject ("IONameMatched");
651 if ( ioClass
) IOLog ("%s IONameMatched is %s\n", inMsg
, ioClass
->getCStringNoCopy () );
657 if ( mkey
->isEqualTo ("AAPL,clock-id") ) {
659 cstr
= getCStringForObject (inDictionary
->getObject ("AAPL,clock-id"));
661 kprintf (" ===> AAPL,clock-id is %s\n", cstr
);
667 if ( mkey
->isEqualTo ("name") ) {
670 getCStringForObject(inDictionary
->getObject("name"), nameStr
,
672 if (strlen(nameStr
) > 0)
673 IOLog ("%s name is %s\n", inMsg
, nameStr
);
676 mkey
= (OSSymbol
*) mcoll
->getNextObject ();
685 getCStringForObject(OSObject
*inObj
, char *outStr
, size_t outStrLen
)
690 if ( (NULL
== inObj
) || (NULL
== outStr
))
693 char * objString
= (char *) (inObj
->getMetaClass())->getClassName();
695 if ((0 == strncmp(objString
, "OSString", sizeof("OSString"))) ||
696 (0 == strncmp(objString
, "OSSymbol", sizeof("OSSymbol"))))
697 strlcpy(outStr
, ((OSString
*)inObj
)->getCStringNoCopy(), outStrLen
);
699 else if (0 == strncmp(objString
, "OSData", sizeof("OSData"))) {
700 len
= ((OSData
*)inObj
)->getLength();
701 buffer
= (char *)((OSData
*)inObj
)->getBytesNoCopy();
702 if (buffer
&& (len
> 0)) {
703 for (i
=0; i
< len
; i
++) {
704 outStr
[i
] = buffer
[i
];
711 /* IOShutdownNotificationsTimedOut
712 * - Called from a timer installed by PEHaltRestart
714 static void IOShutdownNotificationsTimedOut(
715 thread_call_param_t p0
,
716 thread_call_param_t p1
)
718 int type
= (int)(long)p0
;
720 /* 30 seconds has elapsed - resume shutdown */
721 if(gIOPlatform
) gIOPlatform
->haltRestart(type
);
728 * Callouts from BSD for machine name & model
731 boolean_t
PEGetMachineName( char * name
, int maxLength
)
734 return( gIOPlatform
->getMachineName( name
, maxLength
));
739 boolean_t
PEGetModelName( char * name
, int maxLength
)
742 return( gIOPlatform
->getModelName( name
, maxLength
));
747 int PEGetPlatformEpoch(void)
750 return( gIOPlatform
->getBootROMType());
755 int PEHaltRestart(unsigned int type
)
757 IOPMrootDomain
*pmRootDomain
;
758 AbsoluteTime deadline
;
759 thread_call_t shutdown_hang
;
761 if(type
== kPEHaltCPU
|| type
== kPERestartCPU
|| type
== kPEUPSDelayHaltCPU
)
763 pmRootDomain
= IOService::getPMRootDomain();
764 /* Notify IOKit PM clients of shutdown/restart
765 Clients subscribe to this message with a call to
766 IOService::registerInterest()
769 /* Spawn a thread that will panic in 30 seconds.
770 If all goes well the machine will be off by the time
773 shutdown_hang
= thread_call_allocate( &IOShutdownNotificationsTimedOut
,
774 (thread_call_param_t
)(uintptr_t) type
);
775 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
776 thread_call_enter1_delayed( shutdown_hang
, 0, deadline
);
778 pmRootDomain
->handlePlatformHaltRestart(type
);
779 /* This notification should have few clients who all do
780 their work synchronously.
782 In this "shutdown notification" context we don't give
783 drivers the option of working asynchronously and responding
784 later. PM internals make it very hard to wait for asynchronous
789 if (gIOPlatform
) return gIOPlatform
->haltRestart(type
);
793 UInt32
PESavePanicInfo(UInt8
*buffer
, UInt32 length
)
795 if (gIOPlatform
!= 0) return gIOPlatform
->savePanicInfo(buffer
, length
);
801 inline static int init_gIOOptionsEntry(void)
803 IORegistryEntry
*entry
;
805 volatile void **options
;
811 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
815 nvram_entry
= (void *) OSDynamicCast(IODTNVRAM
, entry
);
819 options
= (volatile void **) &gIOOptionsEntry
;
820 if (!OSCompareAndSwapPtr(NULL
, nvram_entry
, options
)) {
833 /* pass in a NULL value if you just want to figure out the len */
834 boolean_t
PEReadNVRAMProperty(const char *symbol
, void *value
,
844 if (init_gIOOptionsEntry() < 0)
850 obj
= gIOOptionsEntry
->getProperty(symbol
);
854 /* convert to data */
855 data
= OSDynamicCast(OSData
, obj
);
859 *len
= data
->getLength();
860 vlen
= min(vlen
, *len
);
862 memcpy((void *) value
, data
->getBytesNoCopy(), vlen
);
871 boolean_t
PEWriteNVRAMProperty(const char *symbol
, const void *value
,
872 const unsigned int len
)
878 if (!symbol
|| !value
|| !len
)
881 if (init_gIOOptionsEntry() < 0)
884 sym
= OSSymbol::withCStringNoCopy(symbol
);
888 data
= OSData::withBytes((void *) value
, len
);
892 ret
= gIOOptionsEntry
->setProperty(sym
, data
);
899 gIOOptionsEntry
->sync();
908 boolean_t
PERemoveNVRAMProperty(const char *symbol
)
915 if (init_gIOOptionsEntry() < 0)
918 sym
= OSSymbol::withCStringNoCopy(symbol
);
922 gIOOptionsEntry
->removeProperty(sym
);
926 gIOOptionsEntry
->sync();
934 long PEGetGMTTimeOfDay(void)
938 if( gIOPlatform
) result
= gIOPlatform
->getGMTTimeOfDay();
943 void PESetGMTTimeOfDay(long secs
)
945 if( gIOPlatform
) gIOPlatform
->setGMTTimeOfDay(secs
);
950 void IOPlatformExpert::registerNVRAMController(IONVRAMController
* caller
)
953 IORegistryEntry
* entry
;
954 OSString
* string
= 0;
957 entry
= IORegistryEntry::fromPath( "/efi/platform", gIODTPlane
);
960 data
= OSDynamicCast( OSData
, entry
->getProperty( "system-id" ) );
961 if ( data
&& data
->getLength( ) == 16 )
964 uint8_t digest
[ SHA_DIGEST_LENGTH
];
965 const uuid_t space
= { 0x2A, 0x06, 0x19, 0x90, 0xD3, 0x8D, 0x44, 0x40, 0xA1, 0x39, 0xC4, 0x97, 0x70, 0x37, 0x65, 0xAC };
967 SHA1Init( &context
);
968 SHA1Update( &context
, space
, sizeof( space
) );
969 SHA1Update( &context
, data
->getBytesNoCopy( ), data
->getLength( ) );
970 SHA1Final( digest
, &context
);
972 digest
[ 6 ] = ( digest
[ 6 ] & 0x0F ) | 0x50;
973 digest
[ 8 ] = ( digest
[ 8 ] & 0x3F ) | 0x80;
975 uuid_unparse( digest
, uuid
);
976 string
= OSString::withCString( uuid
);
984 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
987 data
= OSDynamicCast( OSData
, entry
->getProperty( "platform-uuid" ) );
988 if ( data
&& data
->getLength( ) == sizeof( uuid_t
) )
990 uuid_unparse( ( uint8_t * ) data
->getBytesNoCopy( ), uuid
);
991 string
= OSString::withCString( uuid
);
1000 getProvider( )->setProperty( kIOPlatformUUIDKey
, string
);
1001 publishResource( kIOPlatformUUIDKey
, string
);
1006 publishResource("IONVRAM");
1009 IOReturn
IOPlatformExpert::callPlatformFunction(const OSSymbol
*functionName
,
1010 bool waitForFunction
,
1011 void *param1
, void *param2
,
1012 void *param3
, void *param4
)
1014 IOService
*service
, *_resources
;
1016 if (waitForFunction
) {
1017 _resources
= waitForService(resourceMatching(functionName
));
1019 _resources
= getResourceService();
1021 if (_resources
== 0) return kIOReturnUnsupported
;
1023 service
= OSDynamicCast(IOService
, _resources
->getProperty(functionName
));
1024 if (service
== 0) return kIOReturnUnsupported
;
1026 return service
->callPlatformFunction(functionName
, waitForFunction
,
1027 param1
, param2
, param3
, param4
);
1030 IOByteCount
IOPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1035 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1038 #define super IOPlatformExpert
1040 OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert
, IOPlatformExpert
)
1042 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 0);
1043 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 1);
1044 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 2);
1045 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 3);
1046 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 4);
1047 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 5);
1048 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 6);
1049 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 7);
1051 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1053 IOService
* IODTPlatformExpert::probe( IOService
* provider
,
1056 if( !super::probe( provider
, score
))
1059 // check machine types
1060 if( !provider
->compareNames( getProperty( gIONameMatchKey
) ))
1066 bool IODTPlatformExpert::configure( IOService
* provider
)
1068 if( !super::configure( provider
))
1071 processTopLevel( provider
);
1076 IOService
* IODTPlatformExpert::createNub( IORegistryEntry
* from
)
1080 nub
= new IOPlatformDevice
;
1082 if( !nub
->init( from
, gIODTPlane
)) {
1090 bool IODTPlatformExpert::createNubs( IOService
* parent
, OSIterator
* iter
)
1092 IORegistryEntry
* next
;
1097 while( (next
= (IORegistryEntry
*) iter
->getNextObject())) {
1099 if( 0 == (nub
= createNub( next
)))
1102 nub
->attach( parent
);
1103 nub
->registerService();
1111 void IODTPlatformExpert::processTopLevel( IORegistryEntry
* rootEntry
)
1114 IORegistryEntry
* next
;
1115 IORegistryEntry
* cpus
;
1116 IORegistryEntry
* options
;
1119 kids
= IODTFindMatchingEntries( rootEntry
, 0, deleteList() );
1121 while( (next
= (IORegistryEntry
*)kids
->getNextObject())) {
1122 next
->detachAll( gIODTPlane
);
1127 // Publish an IODTNVRAM class on /options.
1128 options
= rootEntry
->childFromPath("options", gIODTPlane
);
1130 dtNVRAM
= new IODTNVRAM
;
1132 if (!dtNVRAM
->init(options
, gIODTPlane
)) {
1136 dtNVRAM
->attach(this);
1137 dtNVRAM
->registerService();
1142 // Publish the cpus.
1143 cpus
= rootEntry
->childFromPath( "cpus", gIODTPlane
);
1145 createNubs( this, IODTFindMatchingEntries( cpus
, kIODTExclusive
, 0));
1147 // publish top level, minus excludeList
1148 createNubs( this, IODTFindMatchingEntries( rootEntry
, kIODTExclusive
, excludeList()));
1151 IOReturn
IODTPlatformExpert::getNubResources( IOService
* nub
)
1153 if( nub
->getDeviceMemory())
1154 return( kIOReturnSuccess
);
1156 IODTResolveAddressing( nub
, "reg", 0);
1158 return( kIOReturnSuccess
);
1161 bool IODTPlatformExpert::compareNubName( const IOService
* nub
,
1162 OSString
* name
, OSString
** matched
) const
1164 return( IODTCompareNubName( nub
, name
, matched
)
1165 || super::compareNubName( nub
, name
, matched
) );
1168 bool IODTPlatformExpert::getModelName( char * name
, int maxLength
)
1178 prop
= (OSData
*) getProvider()->getProperty( gIODTCompatibleKey
);
1180 str
= (const char *) prop
->getBytesNoCopy();
1182 if( 0 == strncmp( str
, "AAPL,", strlen( "AAPL," ) ))
1183 str
+= strlen( "AAPL," );
1186 while( (c
= *str
++)) {
1187 if( (c
== '/') || (c
== ' '))
1191 if( len
>= maxLength
)
1201 bool IODTPlatformExpert::getMachineName( char * name
, int maxLength
)
1207 prop
= (OSData
*) getProvider()->getProperty( gIODTModelKey
);
1211 strlcpy( name
, (const char *) prop
->getBytesNoCopy(), maxLength
);
1216 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1218 void IODTPlatformExpert::registerNVRAMController( IONVRAMController
* nvram
)
1220 if (dtNVRAM
) dtNVRAM
->registerNVRAMController(nvram
);
1222 super::registerNVRAMController(nvram
);
1225 int IODTPlatformExpert::haltRestart(unsigned int type
)
1227 if (dtNVRAM
) dtNVRAM
->sync();
1229 return super::haltRestart(type
);
1232 IOReturn
IODTPlatformExpert::readXPRAM(IOByteCount offset
, UInt8
* buffer
,
1235 if (dtNVRAM
) return dtNVRAM
->readXPRAM(offset
, buffer
, length
);
1236 else return kIOReturnNotReady
;
1239 IOReturn
IODTPlatformExpert::writeXPRAM(IOByteCount offset
, UInt8
* buffer
,
1242 if (dtNVRAM
) return dtNVRAM
->writeXPRAM(offset
, buffer
, length
);
1243 else return kIOReturnNotReady
;
1246 IOReturn
IODTPlatformExpert::readNVRAMProperty(
1247 IORegistryEntry
* entry
,
1248 const OSSymbol
** name
, OSData
** value
)
1250 if (dtNVRAM
) return dtNVRAM
->readNVRAMProperty(entry
, name
, value
);
1251 else return kIOReturnNotReady
;
1254 IOReturn
IODTPlatformExpert::writeNVRAMProperty(
1255 IORegistryEntry
* entry
,
1256 const OSSymbol
* name
, OSData
* value
)
1258 if (dtNVRAM
) return dtNVRAM
->writeNVRAMProperty(entry
, name
, value
);
1259 else return kIOReturnNotReady
;
1262 OSDictionary
*IODTPlatformExpert::getNVRAMPartitions(void)
1264 if (dtNVRAM
) return dtNVRAM
->getNVRAMPartitions();
1268 IOReturn
IODTPlatformExpert::readNVRAMPartition(const OSSymbol
* partitionID
,
1269 IOByteCount offset
, UInt8
* buffer
,
1272 if (dtNVRAM
) return dtNVRAM
->readNVRAMPartition(partitionID
, offset
,
1274 else return kIOReturnNotReady
;
1277 IOReturn
IODTPlatformExpert::writeNVRAMPartition(const OSSymbol
* partitionID
,
1278 IOByteCount offset
, UInt8
* buffer
,
1281 if (dtNVRAM
) return dtNVRAM
->writeNVRAMPartition(partitionID
, offset
,
1283 else return kIOReturnNotReady
;
1286 IOByteCount
IODTPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1288 IOByteCount lengthSaved
= 0;
1290 if (dtNVRAM
) lengthSaved
= dtNVRAM
->savePanicInfo(buffer
, length
);
1292 if (lengthSaved
== 0) lengthSaved
= super::savePanicInfo(buffer
, length
);
1297 OSString
* IODTPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
) {
1298 UInt8
* serialNumber
;
1299 unsigned int serialNumberSize
;
1300 unsigned short pos
= 0;
1304 if (myProperty
!= NULL
) {
1305 serialNumberSize
= myProperty
->getLength();
1306 serialNumber
= (UInt8
*)(myProperty
->getBytesNoCopy());
1307 temp
= (char*)serialNumber
;
1308 if (serialNumberSize
> 0) {
1309 // check to see if this is a CTO serial number...
1310 while (pos
< serialNumberSize
&& temp
[pos
] != '-') pos
++;
1312 if (pos
< serialNumberSize
) { // there was a hyphen, so it's a CTO serial number
1313 memcpy(SerialNo
, serialNumber
+ 12, 8);
1314 memcpy(&SerialNo
[8], serialNumber
, 3);
1316 memcpy(&SerialNo
[12], serialNumber
+ 3, 8);
1318 } else { // just a normal serial number
1319 memcpy(SerialNo
, serialNumber
+ 13, 8);
1320 memcpy(&SerialNo
[8], serialNumber
, 3);
1323 return OSString::withCString(SerialNo
);
1330 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1333 #define super IOService
1335 OSDefineMetaClassAndStructors(IOPlatformExpertDevice
, IOService
)
1337 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 0);
1338 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 1);
1339 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 2);
1340 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 3);
1342 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1344 bool IOPlatformExpertDevice::compareName( OSString
* name
,
1345 OSString
** matched
) const
1347 return( IODTCompareNubName( this, name
, matched
));
1351 IOPlatformExpertDevice::initWithArgs(
1352 void * dtTop
, void * p2
, void * p3
, void * p4
)
1354 IORegistryEntry
* dt
= 0;
1355 void * argsData
[ 4 ];
1358 // dtTop may be zero on non- device tree systems
1359 if( dtTop
&& (dt
= IODeviceTreeAlloc( dtTop
)))
1360 ok
= super::init( dt
, gIODTPlane
);
1368 workLoop
= IOWorkLoop::workLoop();
1372 argsData
[ 0 ] = dtTop
;
1377 setProperty("IOPlatformArgs", (void *)argsData
, sizeof(argsData
));
1382 IOWorkLoop
*IOPlatformExpertDevice::getWorkLoop() const
1387 IOReturn
IOPlatformExpertDevice::setProperties( OSObject
* properties
)
1389 OSDictionary
* dictionary
;
1393 status
= super::setProperties( properties
);
1394 if ( status
!= kIOReturnUnsupported
) return status
;
1396 status
= IOUserClient::clientHasPrivilege( current_task( ), kIOClientPrivilegeAdministrator
);
1397 if ( status
!= kIOReturnSuccess
) return status
;
1399 dictionary
= OSDynamicCast( OSDictionary
, properties
);
1400 if ( dictionary
== 0 ) return kIOReturnBadArgument
;
1402 object
= dictionary
->getObject( kIOPlatformUUIDKey
);
1405 IORegistryEntry
* entry
;
1409 string
= ( OSString
* ) getProperty( kIOPlatformUUIDKey
);
1410 if ( string
) return kIOReturnNotPermitted
;
1412 string
= OSDynamicCast( OSString
, object
);
1413 if ( string
== 0 ) return kIOReturnBadArgument
;
1415 status
= uuid_parse( string
->getCStringNoCopy( ), uuid
);
1416 if ( status
!= 0 ) return kIOReturnBadArgument
;
1418 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
1421 entry
->setProperty( "platform-uuid", uuid
, sizeof( uuid_t
) );
1425 setProperty( kIOPlatformUUIDKey
, string
);
1426 publishResource( kIOPlatformUUIDKey
, string
);
1428 return kIOReturnSuccess
;
1431 return kIOReturnUnsupported
;
1434 void IOPlatformExpertDevice::free()
1437 workLoop
->release();
1440 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1443 #define super IOService
1445 OSDefineMetaClassAndStructors(IOPlatformDevice
, IOService
)
1447 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 0);
1448 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 1);
1449 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 2);
1450 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 3);
1452 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1454 bool IOPlatformDevice::compareName( OSString
* name
,
1455 OSString
** matched
) const
1457 return( ((IOPlatformExpert
*)getProvider())->
1458 compareNubName( this, name
, matched
));
1461 IOService
* IOPlatformDevice::matchLocation( IOService
* /* client */ )
1466 IOReturn
IOPlatformDevice::getResources( void )
1468 return( ((IOPlatformExpert
*)getProvider())->getNubResources( this ));
1471 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1473 /*********************************************************************
1474 * IOPanicPlatform class
1476 * If no legitimate IOPlatformDevice matches, this one does and panics
1477 * the kernel with a suitable message.
1478 *********************************************************************/
1480 class IOPanicPlatform
: IOPlatformExpert
{
1481 OSDeclareDefaultStructors(IOPanicPlatform
);
1484 bool start(IOService
* provider
);
1488 OSDefineMetaClassAndStructors(IOPanicPlatform
, IOPlatformExpert
);
1491 bool IOPanicPlatform::start(IOService
* provider
) {
1492 const char * platform_name
= "(unknown platform name)";
1494 if (provider
) platform_name
= provider
->getName();
1496 panic("Unable to find driver for this platform: \"%s\".\n",