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 #ifdef CONFIG_EMBEDDED
719 /* 30 seconds has elapsed - panic */
720 panic("Halt/Restart Timed Out");
722 #else /* ! CONFIG_EMBEDDED */
723 int type
= (int)(long)p0
;
725 /* 30 seconds has elapsed - resume shutdown */
726 if(gIOPlatform
) gIOPlatform
->haltRestart(type
);
727 #endif /* CONFIG_EMBEDDED */
734 * Callouts from BSD for machine name & model
737 boolean_t
PEGetMachineName( char * name
, int maxLength
)
740 return( gIOPlatform
->getMachineName( name
, maxLength
));
745 boolean_t
PEGetModelName( char * name
, int maxLength
)
748 return( gIOPlatform
->getModelName( name
, maxLength
));
753 int PEGetPlatformEpoch(void)
756 return( gIOPlatform
->getBootROMType());
761 int PEHaltRestart(unsigned int type
)
763 IOPMrootDomain
*pmRootDomain
;
764 AbsoluteTime deadline
;
765 thread_call_t shutdown_hang
;
767 if(type
== kPEHaltCPU
|| type
== kPERestartCPU
|| type
== kPEUPSDelayHaltCPU
)
769 pmRootDomain
= IOService::getPMRootDomain();
770 /* Notify IOKit PM clients of shutdown/restart
771 Clients subscribe to this message with a call to
772 IOService::registerInterest()
775 /* Spawn a thread that will panic in 30 seconds.
776 If all goes well the machine will be off by the time
779 shutdown_hang
= thread_call_allocate( &IOShutdownNotificationsTimedOut
,
780 (thread_call_param_t
) type
);
781 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
782 thread_call_enter1_delayed( shutdown_hang
, 0, deadline
);
784 pmRootDomain
->handlePlatformHaltRestart(type
);
785 /* This notification should have few clients who all do
786 their work synchronously.
788 In this "shutdown notification" context we don't give
789 drivers the option of working asynchronously and responding
790 later. PM internals make it very hard to wait for asynchronous
795 if (gIOPlatform
) return gIOPlatform
->haltRestart(type
);
799 UInt32
PESavePanicInfo(UInt8
*buffer
, UInt32 length
)
801 if (gIOPlatform
!= 0) return gIOPlatform
->savePanicInfo(buffer
, length
);
807 inline static int init_gIOOptionsEntry(void)
809 IORegistryEntry
*entry
;
811 volatile void **options
;
817 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
821 nvram_entry
= (void *) OSDynamicCast(IODTNVRAM
, entry
);
825 options
= (volatile void **) &gIOOptionsEntry
;
826 if (!OSCompareAndSwapPtr(NULL
, nvram_entry
, options
)) {
839 /* pass in a NULL value if you just want to figure out the len */
840 boolean_t
PEReadNVRAMProperty(const char *symbol
, void *value
,
850 if (init_gIOOptionsEntry() < 0)
856 obj
= gIOOptionsEntry
->getProperty(symbol
);
860 /* convert to data */
861 data
= OSDynamicCast(OSData
, obj
);
865 *len
= data
->getLength();
866 vlen
= min(vlen
, *len
);
868 memcpy((void *) value
, data
->getBytesNoCopy(), vlen
);
877 boolean_t
PEWriteNVRAMProperty(const char *symbol
, const void *value
,
878 const unsigned int len
)
884 if (!symbol
|| !value
|| !len
)
887 if (init_gIOOptionsEntry() < 0)
890 sym
= OSSymbol::withCStringNoCopy(symbol
);
894 data
= OSData::withBytes((void *) value
, len
);
898 ret
= gIOOptionsEntry
->setProperty(sym
, data
);
905 gIOOptionsEntry
->sync();
914 long PEGetGMTTimeOfDay(void)
918 if( gIOPlatform
) result
= gIOPlatform
->getGMTTimeOfDay();
923 void PESetGMTTimeOfDay(long secs
)
925 if( gIOPlatform
) gIOPlatform
->setGMTTimeOfDay(secs
);
930 void IOPlatformExpert::registerNVRAMController(IONVRAMController
* caller
)
933 IORegistryEntry
* entry
;
934 OSString
* string
= 0;
938 entry
= IORegistryEntry::fromPath( "/chosen", gIODTPlane
);
943 data1
= OSDynamicCast( OSData
, entry
->getProperty( "unique-chip-id" ) );
944 if ( data1
&& data1
->getLength( ) == 8 )
948 data2
= OSDynamicCast( OSData
, entry
->getProperty( "chip-id" ) );
949 if ( data2
&& data2
->getLength( ) == 4 )
952 uint8_t digest
[ SHA_DIGEST_LENGTH
];
953 const uuid_t space
= { 0xA6, 0xDD, 0x4C, 0xCB, 0xB5, 0xE8, 0x4A, 0xF5, 0xAC, 0xDD, 0xB6, 0xDC, 0x6A, 0x05, 0x42, 0xB8 };
955 SHA1Init( &context
);
956 SHA1Update( &context
, space
, sizeof( space
) );
957 SHA1Update( &context
, data1
->getBytesNoCopy( ), data1
->getLength( ) );
958 SHA1Update( &context
, data2
->getBytesNoCopy( ), data2
->getLength( ) );
959 SHA1Final( digest
, &context
);
961 digest
[ 6 ] = ( digest
[ 6 ] & 0x0F ) | 0x50;
962 digest
[ 8 ] = ( digest
[ 8 ] & 0x3F ) | 0x80;
964 uuid_unparse( digest
, uuid
);
965 string
= OSString::withCString( uuid
);
971 #else /* !CONFIG_EMBEDDED */
972 entry
= IORegistryEntry::fromPath( "/efi/platform", gIODTPlane
);
975 data
= OSDynamicCast( OSData
, entry
->getProperty( "system-id" ) );
976 if ( data
&& data
->getLength( ) == 16 )
979 uint8_t digest
[ SHA_DIGEST_LENGTH
];
980 const uuid_t space
= { 0x2A, 0x06, 0x19, 0x90, 0xD3, 0x8D, 0x44, 0x40, 0xA1, 0x39, 0xC4, 0x97, 0x70, 0x37, 0x65, 0xAC };
982 SHA1Init( &context
);
983 SHA1Update( &context
, space
, sizeof( space
) );
984 SHA1Update( &context
, data
->getBytesNoCopy( ), data
->getLength( ) );
985 SHA1Final( digest
, &context
);
987 digest
[ 6 ] = ( digest
[ 6 ] & 0x0F ) | 0x50;
988 digest
[ 8 ] = ( digest
[ 8 ] & 0x3F ) | 0x80;
990 uuid_unparse( digest
, uuid
);
991 string
= OSString::withCString( uuid
);
996 #endif /* !CONFIG_EMBEDDED */
1000 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
1003 data
= OSDynamicCast( OSData
, entry
->getProperty( "platform-uuid" ) );
1004 if ( data
&& data
->getLength( ) == sizeof( uuid_t
) )
1006 uuid_unparse( ( uint8_t * ) data
->getBytesNoCopy( ), uuid
);
1007 string
= OSString::withCString( uuid
);
1016 getProvider( )->setProperty( kIOPlatformUUIDKey
, string
);
1017 publishResource( kIOPlatformUUIDKey
, string
);
1022 publishResource("IONVRAM");
1025 IOReturn
IOPlatformExpert::callPlatformFunction(const OSSymbol
*functionName
,
1026 bool waitForFunction
,
1027 void *param1
, void *param2
,
1028 void *param3
, void *param4
)
1030 IOService
*service
, *_resources
;
1032 if (waitForFunction
) {
1033 _resources
= waitForService(resourceMatching(functionName
));
1035 _resources
= getResourceService();
1037 if (_resources
== 0) return kIOReturnUnsupported
;
1039 service
= OSDynamicCast(IOService
, _resources
->getProperty(functionName
));
1040 if (service
== 0) return kIOReturnUnsupported
;
1042 return service
->callPlatformFunction(functionName
, waitForFunction
,
1043 param1
, param2
, param3
, param4
);
1046 IOByteCount
IOPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1051 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1054 #define super IOPlatformExpert
1056 OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert
, IOPlatformExpert
)
1058 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 0);
1059 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 1);
1060 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 2);
1061 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 3);
1062 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 4);
1063 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 5);
1064 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 6);
1065 OSMetaClassDefineReservedUnused(IODTPlatformExpert
, 7);
1067 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1069 IOService
* IODTPlatformExpert::probe( IOService
* provider
,
1072 if( !super::probe( provider
, score
))
1075 // check machine types
1076 if( !provider
->compareNames( getProperty( gIONameMatchKey
) ))
1082 bool IODTPlatformExpert::configure( IOService
* provider
)
1084 if( !super::configure( provider
))
1087 processTopLevel( provider
);
1092 IOService
* IODTPlatformExpert::createNub( IORegistryEntry
* from
)
1096 nub
= new IOPlatformDevice
;
1098 if( !nub
->init( from
, gIODTPlane
)) {
1106 bool IODTPlatformExpert::createNubs( IOService
* parent
, OSIterator
* iter
)
1108 IORegistryEntry
* next
;
1113 while( (next
= (IORegistryEntry
*) iter
->getNextObject())) {
1115 if( 0 == (nub
= createNub( next
)))
1118 nub
->attach( parent
);
1119 nub
->registerService();
1127 void IODTPlatformExpert::processTopLevel( IORegistryEntry
* rootEntry
)
1130 IORegistryEntry
* next
;
1131 IORegistryEntry
* cpus
;
1132 IORegistryEntry
* options
;
1135 kids
= IODTFindMatchingEntries( rootEntry
, 0, deleteList() );
1137 while( (next
= (IORegistryEntry
*)kids
->getNextObject())) {
1138 next
->detachAll( gIODTPlane
);
1143 // Publish an IODTNVRAM class on /options.
1144 options
= rootEntry
->childFromPath("options", gIODTPlane
);
1146 dtNVRAM
= new IODTNVRAM
;
1148 if (!dtNVRAM
->init(options
, gIODTPlane
)) {
1152 dtNVRAM
->attach(this);
1153 dtNVRAM
->registerService();
1158 // Publish the cpus.
1159 cpus
= rootEntry
->childFromPath( "cpus", gIODTPlane
);
1161 createNubs( this, IODTFindMatchingEntries( cpus
, kIODTExclusive
, 0));
1163 // publish top level, minus excludeList
1164 createNubs( this, IODTFindMatchingEntries( rootEntry
, kIODTExclusive
, excludeList()));
1167 IOReturn
IODTPlatformExpert::getNubResources( IOService
* nub
)
1169 if( nub
->getDeviceMemory())
1170 return( kIOReturnSuccess
);
1172 IODTResolveAddressing( nub
, "reg", 0);
1174 return( kIOReturnSuccess
);
1177 bool IODTPlatformExpert::compareNubName( const IOService
* nub
,
1178 OSString
* name
, OSString
** matched
) const
1180 return( IODTCompareNubName( nub
, name
, matched
)
1181 || super::compareNubName( nub
, name
, matched
) );
1184 bool IODTPlatformExpert::getModelName( char * name
, int maxLength
)
1194 prop
= (OSData
*) getProvider()->getProperty( gIODTCompatibleKey
);
1196 str
= (const char *) prop
->getBytesNoCopy();
1198 if( 0 == strncmp( str
, "AAPL,", strlen( "AAPL," ) ))
1199 str
+= strlen( "AAPL," );
1202 while( (c
= *str
++)) {
1203 if( (c
== '/') || (c
== ' '))
1207 if( len
>= maxLength
)
1217 bool IODTPlatformExpert::getMachineName( char * name
, int maxLength
)
1223 prop
= (OSData
*) getProvider()->getProperty( gIODTModelKey
);
1227 strlcpy( name
, (const char *) prop
->getBytesNoCopy(), maxLength
);
1232 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1234 void IODTPlatformExpert::registerNVRAMController( IONVRAMController
* nvram
)
1236 if (dtNVRAM
) dtNVRAM
->registerNVRAMController(nvram
);
1238 super::registerNVRAMController(nvram
);
1241 int IODTPlatformExpert::haltRestart(unsigned int type
)
1243 if (dtNVRAM
) dtNVRAM
->sync();
1245 return super::haltRestart(type
);
1248 IOReturn
IODTPlatformExpert::readXPRAM(IOByteCount offset
, UInt8
* buffer
,
1251 if (dtNVRAM
) return dtNVRAM
->readXPRAM(offset
, buffer
, length
);
1252 else return kIOReturnNotReady
;
1255 IOReturn
IODTPlatformExpert::writeXPRAM(IOByteCount offset
, UInt8
* buffer
,
1258 if (dtNVRAM
) return dtNVRAM
->writeXPRAM(offset
, buffer
, length
);
1259 else return kIOReturnNotReady
;
1262 IOReturn
IODTPlatformExpert::readNVRAMProperty(
1263 IORegistryEntry
* entry
,
1264 const OSSymbol
** name
, OSData
** value
)
1266 if (dtNVRAM
) return dtNVRAM
->readNVRAMProperty(entry
, name
, value
);
1267 else return kIOReturnNotReady
;
1270 IOReturn
IODTPlatformExpert::writeNVRAMProperty(
1271 IORegistryEntry
* entry
,
1272 const OSSymbol
* name
, OSData
* value
)
1274 if (dtNVRAM
) return dtNVRAM
->writeNVRAMProperty(entry
, name
, value
);
1275 else return kIOReturnNotReady
;
1278 OSDictionary
*IODTPlatformExpert::getNVRAMPartitions(void)
1280 if (dtNVRAM
) return dtNVRAM
->getNVRAMPartitions();
1284 IOReturn
IODTPlatformExpert::readNVRAMPartition(const OSSymbol
* partitionID
,
1285 IOByteCount offset
, UInt8
* buffer
,
1288 if (dtNVRAM
) return dtNVRAM
->readNVRAMPartition(partitionID
, offset
,
1290 else return kIOReturnNotReady
;
1293 IOReturn
IODTPlatformExpert::writeNVRAMPartition(const OSSymbol
* partitionID
,
1294 IOByteCount offset
, UInt8
* buffer
,
1297 if (dtNVRAM
) return dtNVRAM
->writeNVRAMPartition(partitionID
, offset
,
1299 else return kIOReturnNotReady
;
1302 IOByteCount
IODTPlatformExpert::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
1304 IOByteCount lengthSaved
= 0;
1306 if (dtNVRAM
) lengthSaved
= dtNVRAM
->savePanicInfo(buffer
, length
);
1308 if (lengthSaved
== 0) lengthSaved
= super::savePanicInfo(buffer
, length
);
1313 OSString
* IODTPlatformExpert::createSystemSerialNumberString(OSData
* myProperty
) {
1314 UInt8
* serialNumber
;
1315 unsigned int serialNumberSize
;
1316 unsigned short pos
= 0;
1320 if (myProperty
!= NULL
) {
1321 serialNumberSize
= myProperty
->getLength();
1322 serialNumber
= (UInt8
*)(myProperty
->getBytesNoCopy());
1323 temp
= (char*)serialNumber
;
1324 if (serialNumberSize
> 0) {
1325 // check to see if this is a CTO serial number...
1326 while (pos
< serialNumberSize
&& temp
[pos
] != '-') pos
++;
1328 if (pos
< serialNumberSize
) { // there was a hyphen, so it's a CTO serial number
1329 memcpy(SerialNo
, serialNumber
+ 12, 8);
1330 memcpy(&SerialNo
[8], serialNumber
, 3);
1332 memcpy(&SerialNo
[12], serialNumber
+ 3, 8);
1334 } else { // just a normal serial number
1335 memcpy(SerialNo
, serialNumber
+ 13, 8);
1336 memcpy(&SerialNo
[8], serialNumber
, 3);
1339 return OSString::withCString(SerialNo
);
1346 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1349 #define super IOService
1351 OSDefineMetaClassAndStructors(IOPlatformExpertDevice
, IOService
)
1353 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 0);
1354 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 1);
1355 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 2);
1356 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice
, 3);
1358 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1360 bool IOPlatformExpertDevice::compareName( OSString
* name
,
1361 OSString
** matched
) const
1363 return( IODTCompareNubName( this, name
, matched
));
1367 IOPlatformExpertDevice::initWithArgs(
1368 void * dtTop
, void * p2
, void * p3
, void * p4
)
1370 IORegistryEntry
* dt
= 0;
1371 void * argsData
[ 4 ];
1374 // dtTop may be zero on non- device tree systems
1375 if( dtTop
&& (dt
= IODeviceTreeAlloc( dtTop
)))
1376 ok
= super::init( dt
, gIODTPlane
);
1383 workLoop
= IOWorkLoop::workLoop();
1387 argsData
[ 0 ] = dtTop
;
1392 setProperty("IOPlatformArgs", (void *)argsData
, sizeof(argsData
));
1397 IOWorkLoop
*IOPlatformExpertDevice::getWorkLoop() const
1402 IOReturn
IOPlatformExpertDevice::setProperties( OSObject
* properties
)
1404 OSDictionary
* dictionary
;
1408 status
= super::setProperties( properties
);
1409 if ( status
!= kIOReturnUnsupported
) return status
;
1411 status
= IOUserClient::clientHasPrivilege( current_task( ), kIOClientPrivilegeAdministrator
);
1412 if ( status
!= kIOReturnSuccess
) return status
;
1414 dictionary
= OSDynamicCast( OSDictionary
, properties
);
1415 if ( dictionary
== 0 ) return kIOReturnBadArgument
;
1417 object
= dictionary
->getObject( kIOPlatformUUIDKey
);
1420 IORegistryEntry
* entry
;
1424 string
= ( OSString
* ) getProperty( kIOPlatformUUIDKey
);
1425 if ( string
) return kIOReturnNotPermitted
;
1427 string
= OSDynamicCast( OSString
, object
);
1428 if ( string
== 0 ) return kIOReturnBadArgument
;
1430 status
= uuid_parse( string
->getCStringNoCopy( ), uuid
);
1431 if ( status
!= 0 ) return kIOReturnBadArgument
;
1433 entry
= IORegistryEntry::fromPath( "/options", gIODTPlane
);
1436 entry
->setProperty( "platform-uuid", uuid
, sizeof( uuid_t
) );
1440 setProperty( kIOPlatformUUIDKey
, string
);
1441 publishResource( kIOPlatformUUIDKey
, string
);
1443 return kIOReturnSuccess
;
1446 return kIOReturnUnsupported
;
1449 void IOPlatformExpertDevice::free()
1452 workLoop
->release();
1455 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1458 #define super IOService
1460 OSDefineMetaClassAndStructors(IOPlatformDevice
, IOService
)
1462 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 0);
1463 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 1);
1464 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 2);
1465 OSMetaClassDefineReservedUnused(IOPlatformDevice
, 3);
1467 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1469 bool IOPlatformDevice::compareName( OSString
* name
,
1470 OSString
** matched
) const
1472 return( ((IOPlatformExpert
*)getProvider())->
1473 compareNubName( this, name
, matched
));
1476 IOService
* IOPlatformDevice::matchLocation( IOService
* /* client */ )
1481 IOReturn
IOPlatformDevice::getResources( void )
1483 return( ((IOPlatformExpert
*)getProvider())->getNubResources( this ));
1486 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1488 /*********************************************************************
1489 * IOPanicPlatform class
1491 * If no legitimate IOPlatformDevice matches, this one does and panics
1492 * the kernel with a suitable message.
1493 *********************************************************************/
1495 class IOPanicPlatform
: IOPlatformExpert
{
1496 OSDeclareDefaultStructors(IOPanicPlatform
);
1499 bool start(IOService
* provider
);
1503 OSDefineMetaClassAndStructors(IOPanicPlatform
, IOPlatformExpert
);
1506 bool IOPanicPlatform::start(IOService
* provider
) {
1507 const char * platform_name
= "(unknown platform name)";
1509 if (provider
) platform_name
= provider
->getName();
1511 panic("Unable to find driver for this platform: \"%s\".\n",