]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOPlatformExpert.cpp
xnu-1504.9.37.tar.gz
[apple/xnu.git] / iokit / Kernel / IOPlatformExpert.cpp
1 /*
2 * Copyright (c) 1998-2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * HISTORY
30 */
31
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>
45
46 #include <IOKit/system.h>
47
48 #include <libkern/c++/OSContainers.h>
49 #include <libkern/crypto/sha1.h>
50
51 extern "C" {
52 #include <machine/machine_routines.h>
53 #include <pexpert/pexpert.h>
54 #include <uuid/uuid.h>
55 }
56
57 void printDictionaryKeys (OSDictionary * inDictionary, char * inMsg);
58 static void getCStringForObject(OSObject *inObj, char *outStr, size_t outStrLen);
59
60 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
61
62 #define super IOService
63
64 OSDefineMetaClassAndStructors(IOPlatformExpert, IOService)
65
66 OSMetaClassDefineReservedUsed(IOPlatformExpert, 0);
67
68 OSMetaClassDefineReservedUsed(IOPlatformExpert, 1);
69 OSMetaClassDefineReservedUnused(IOPlatformExpert, 2);
70 OSMetaClassDefineReservedUnused(IOPlatformExpert, 3);
71 OSMetaClassDefineReservedUnused(IOPlatformExpert, 4);
72 OSMetaClassDefineReservedUnused(IOPlatformExpert, 5);
73 OSMetaClassDefineReservedUnused(IOPlatformExpert, 6);
74 OSMetaClassDefineReservedUnused(IOPlatformExpert, 7);
75 OSMetaClassDefineReservedUnused(IOPlatformExpert, 8);
76 OSMetaClassDefineReservedUnused(IOPlatformExpert, 9);
77 OSMetaClassDefineReservedUnused(IOPlatformExpert, 10);
78 OSMetaClassDefineReservedUnused(IOPlatformExpert, 11);
79
80 static IOPlatformExpert * gIOPlatform;
81 static OSDictionary * gIOInterruptControllers;
82 static IOLock * gIOInterruptControllersLock;
83
84 OSSymbol * gPlatformInterruptControllerName;
85
86 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
87
88 bool IOPlatformExpert::attach( IOService * provider )
89 {
90
91 if( !super::attach( provider ))
92 return( false);
93
94 return( true);
95 }
96
97 bool IOPlatformExpert::start( IOService * provider )
98 {
99 IORangeAllocator * physicalRanges;
100 OSData * busFrequency;
101 uint32_t debugFlags;
102
103 if (!super::start(provider))
104 return false;
105
106 // Override the mapper present flag is requested by boot arguments.
107 if (PE_parse_boot_argn("dart", &debugFlags, sizeof (debugFlags)) && (debugFlags == 0))
108 removeProperty(kIOPlatformMapperPresentKey);
109
110 // Register the presence or lack thereof a system
111 // PCI address mapper with the IOMapper class
112 IOMapper::setMapperRequired(0 != getProperty(kIOPlatformMapperPresentKey));
113
114 gIOInterruptControllers = OSDictionary::withCapacity(1);
115 gIOInterruptControllersLock = IOLockAlloc();
116
117 // Correct the bus frequency in the device tree.
118 busFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.bus_clock_rate_hz, 4);
119 provider->setProperty("clock-frequency", busFrequency);
120 busFrequency->release();
121
122 gPlatformInterruptControllerName = (OSSymbol *)OSSymbol::withCStringNoCopy("IOPlatformInterruptController");
123
124 physicalRanges = IORangeAllocator::withRange(0xffffffff, 1, 16,
125 IORangeAllocator::kLocking);
126 assert(physicalRanges);
127 setProperty("Platform Memory Ranges", physicalRanges);
128
129 setPlatform( this );
130 gIOPlatform = this;
131
132 PMInstantiatePowerDomains();
133
134 // Parse the serial-number data and publish a user-readable string
135 OSData* mydata = (OSData*) (provider->getProperty("serial-number"));
136 if (mydata != NULL) {
137 OSString *serNoString = createSystemSerialNumberString(mydata);
138 if (serNoString != NULL) {
139 provider->setProperty(kIOPlatformSerialNumberKey, serNoString);
140 serNoString->release();
141 }
142 }
143
144 return( configure(provider) );
145 }
146
147 bool IOPlatformExpert::configure( IOService * provider )
148 {
149 OSSet * topLevel;
150 OSDictionary * dict;
151 IOService * nub;
152
153 topLevel = OSDynamicCast( OSSet, getProperty("top-level"));
154
155 if( topLevel) {
156 while( (dict = OSDynamicCast( OSDictionary,
157 topLevel->getAnyObject()))) {
158 dict->retain();
159 topLevel->removeObject( dict );
160 nub = createNub( dict );
161 if( 0 == nub)
162 continue;
163 dict->release();
164 nub->attach( this );
165 nub->registerService();
166 }
167 }
168
169 return( true );
170 }
171
172 IOService * IOPlatformExpert::createNub( OSDictionary * from )
173 {
174 IOService * nub;
175
176 nub = new IOPlatformDevice;
177 if(nub) {
178 if( !nub->init( from )) {
179 nub->release();
180 nub = 0;
181 }
182 }
183 return( nub);
184 }
185
186 bool IOPlatformExpert::compareNubName( const IOService * nub,
187 OSString * name, OSString ** matched ) const
188 {
189 return( nub->IORegistryEntry::compareName( name, matched ));
190 }
191
192 IOReturn IOPlatformExpert::getNubResources( IOService * nub )
193 {
194 return( kIOReturnSuccess );
195 }
196
197 long IOPlatformExpert::getBootROMType(void)
198 {
199 return _peBootROMType;
200 }
201
202 long IOPlatformExpert::getChipSetType(void)
203 {
204 return _peChipSetType;
205 }
206
207 long IOPlatformExpert::getMachineType(void)
208 {
209 return _peMachineType;
210 }
211
212 void IOPlatformExpert::setBootROMType(long peBootROMType)
213 {
214 _peBootROMType = peBootROMType;
215 }
216
217 void IOPlatformExpert::setChipSetType(long peChipSetType)
218 {
219 _peChipSetType = peChipSetType;
220 }
221
222 void IOPlatformExpert::setMachineType(long peMachineType)
223 {
224 _peMachineType = peMachineType;
225 }
226
227 bool IOPlatformExpert::getMachineName( char * /*name*/, int /*maxLength*/)
228 {
229 return( false );
230 }
231
232 bool IOPlatformExpert::getModelName( char * /*name*/, int /*maxLength*/)
233 {
234 return( false );
235 }
236
237 OSString* IOPlatformExpert::createSystemSerialNumberString(OSData* myProperty)
238 {
239 return NULL;
240 }
241
242 IORangeAllocator * IOPlatformExpert::getPhysicalRangeAllocator(void)
243 {
244 return(OSDynamicCast(IORangeAllocator,
245 getProperty("Platform Memory Ranges")));
246 }
247
248 int (*PE_halt_restart)(unsigned int type) = 0;
249
250 int IOPlatformExpert::haltRestart(unsigned int type)
251 {
252 if (type == kPEPanicSync) return 0;
253
254 if (type == kPEHangCPU) while (true) {}
255
256 if (type == kPEUPSDelayHaltCPU) {
257 // RestartOnPowerLoss feature was turned on, proceed with shutdown.
258 type = kPEHaltCPU;
259 }
260
261 // On ARM kPEPanicRestartCPU is supported in the drivers
262 if (type == kPEPanicRestartCPU)
263 type = kPERestartCPU;
264
265 if (PE_halt_restart) return (*PE_halt_restart)(type);
266 else return -1;
267 }
268
269 void IOPlatformExpert::sleepKernel(void)
270 {
271 #if 0
272 long cnt;
273 boolean_t intState;
274
275 intState = ml_set_interrupts_enabled(false);
276
277 for (cnt = 0; cnt < 10000; cnt++) {
278 IODelay(1000);
279 }
280
281 ml_set_interrupts_enabled(intState);
282 #else
283 // PE_initialize_console(0, kPEDisableScreen);
284
285 IOCPUSleepKernel();
286
287 // PE_initialize_console(0, kPEEnableScreen);
288 #endif
289 }
290
291 long IOPlatformExpert::getGMTTimeOfDay(void)
292 {
293 return(0);
294 }
295
296 void IOPlatformExpert::setGMTTimeOfDay(long secs)
297 {
298 }
299
300
301 IOReturn IOPlatformExpert::getConsoleInfo( PE_Video * consoleInfo )
302 {
303 return( PE_current_console( consoleInfo));
304 }
305
306 IOReturn IOPlatformExpert::setConsoleInfo( PE_Video * consoleInfo,
307 unsigned int op)
308 {
309 return( PE_initialize_console( consoleInfo, op ));
310 }
311
312 IOReturn IOPlatformExpert::registerInterruptController(OSSymbol *name, IOInterruptController *interruptController)
313 {
314 IOLockLock(gIOInterruptControllersLock);
315
316 gIOInterruptControllers->setObject(name, interruptController);
317
318 IOLockWakeup(gIOInterruptControllersLock,
319 gIOInterruptControllers, /* one-thread */ false);
320
321 IOLockUnlock(gIOInterruptControllersLock);
322
323 return kIOReturnSuccess;
324 }
325
326 IOInterruptController *IOPlatformExpert::lookUpInterruptController(OSSymbol *name)
327 {
328 OSObject *object;
329
330 IOLockLock(gIOInterruptControllersLock);
331 while (1) {
332
333 object = gIOInterruptControllers->getObject(name);
334
335 if (object != 0)
336 break;
337
338 IOLockSleep(gIOInterruptControllersLock,
339 gIOInterruptControllers, THREAD_UNINT);
340 }
341
342 IOLockUnlock(gIOInterruptControllersLock);
343 return OSDynamicCast(IOInterruptController, object);
344 }
345
346
347 void IOPlatformExpert::setCPUInterruptProperties(IOService *service)
348 {
349 IOCPUInterruptController *controller;
350
351 controller = OSDynamicCast(IOCPUInterruptController, waitForService(serviceMatching("IOCPUInterruptController")));
352 if (controller) controller->setCPUInterruptProperties(service);
353 }
354
355 bool IOPlatformExpert::atInterruptLevel(void)
356 {
357 return ml_at_interrupt_context();
358 }
359
360 bool IOPlatformExpert::platformAdjustService(IOService */*service*/)
361 {
362 return true;
363 }
364
365
366 //*********************************************************************************
367 // PMLog
368 //
369 //*********************************************************************************
370
371 void IOPlatformExpert::
372 PMLog(const char *who, unsigned long event,
373 unsigned long param1, unsigned long param2)
374 {
375 UInt32 debugFlags = gIOKitDebug;
376
377 if (debugFlags & kIOLogPower) {
378
379 clock_sec_t nows;
380 clock_usec_t nowus;
381 clock_get_system_microtime(&nows, &nowus);
382 nowus += (nows % 1000) * 1000000;
383
384 kprintf("pm%u %p %.30s %d %lx %lx\n",
385 nowus, current_thread(), who, // Identity
386 (int) event, (long) param1, (long) param2); // Args
387
388 if (debugFlags & kIOLogTracePower) {
389 static const UInt32 sStartStopBitField[] =
390 { 0x00000000, 0x00000040 }; // Only Program Hardware so far
391
392 // Arcane formula from Hacker's Delight by Warren
393 // abs(x) = ((int) x >> 31) ^ (x + ((int) x >> 31))
394 UInt32 sgnevent = ((long) event >> 31);
395 UInt32 absevent = sgnevent ^ (event + sgnevent);
396 UInt32 code = IODBG_POWER(absevent);
397
398 UInt32 bit = 1 << (absevent & 0x1f);
399 if (absevent < sizeof(sStartStopBitField) * 8
400 && (sStartStopBitField[absevent >> 5] & bit) ) {
401 // Or in the START or END bits, Start = 1 & END = 2
402 // If sgnevent == 0 then START - 0 => START
403 // else if sgnevent == -1 then START - -1 => END
404 code |= DBG_FUNC_START - sgnevent;
405 }
406
407 // Record the timestamp, wish I had a this pointer
408 IOTimeStampConstant(code, (uintptr_t) who, event, param1, param2);
409 }
410 }
411 }
412
413
414 //*********************************************************************************
415 // PMInstantiatePowerDomains
416 //
417 // In this vanilla implementation, a Root Power Domain is instantiated.
418 // All other objects which register will be children of this Root.
419 // Where this is inappropriate, PMInstantiatePowerDomains is overridden
420 // in a platform-specific subclass.
421 //*********************************************************************************
422
423 void IOPlatformExpert::PMInstantiatePowerDomains ( void )
424 {
425 root = new IOPMrootDomain;
426 root->init();
427 root->attach(this);
428 root->start(this);
429 }
430
431
432 //*********************************************************************************
433 // PMRegisterDevice
434 //
435 // In this vanilla implementation, all callers are made children of the root power domain.
436 // Where this is inappropriate, PMRegisterDevice is overridden in a platform-specific subclass.
437 //*********************************************************************************
438
439 void IOPlatformExpert::PMRegisterDevice(IOService * theNub, IOService * theDevice)
440 {
441 root->addPowerChild ( theDevice );
442 }
443
444 //*********************************************************************************
445 // hasPMFeature
446 //
447 //*********************************************************************************
448
449 bool IOPlatformExpert::hasPMFeature (unsigned long featureMask)
450 {
451 return ((_pePMFeatures & featureMask) != 0);
452 }
453
454 //*********************************************************************************
455 // hasPrivPMFeature
456 //
457 //*********************************************************************************
458
459 bool IOPlatformExpert::hasPrivPMFeature (unsigned long privFeatureMask)
460 {
461 return ((_pePrivPMFeatures & privFeatureMask) != 0);
462 }
463
464 //*********************************************************************************
465 // numBatteriesSupported
466 //
467 //*********************************************************************************
468
469 int IOPlatformExpert::numBatteriesSupported (void)
470 {
471 return (_peNumBatteriesSupported);
472 }
473
474 //*********************************************************************************
475 // CheckSubTree
476 //
477 // This method is called by the instantiated sublass of the platform expert to
478 // determine how a device should be inserted into the Power Domain. The subclass
479 // provides an XML power tree description against which a device is matched based
480 // on class and provider. If a match is found this routine returns true in addition
481 // to flagging the description tree at the appropriate node that a device has been
482 // registered for the given service.
483 //*********************************************************************************
484
485 bool IOPlatformExpert::CheckSubTree (OSArray * inSubTree, IOService * theNub, IOService * theDevice, OSDictionary * theParent)
486 {
487 unsigned int i;
488 unsigned int numPowerTreeNodes;
489 OSDictionary * entry;
490 OSDictionary * matchingDictionary;
491 OSDictionary * providerDictionary;
492 OSDictionary * deviceDictionary;
493 OSDictionary * nubDictionary;
494 OSArray * children;
495 bool nodeFound = false;
496 bool continueSearch = false;
497 bool deviceMatch = false;
498 bool providerMatch = false;
499 bool multiParentMatch = false;
500
501 if ( (NULL == theDevice) || (NULL == inSubTree) )
502 return false;
503
504 numPowerTreeNodes = inSubTree->getCount ();
505
506 // iterate through the power tree to find a home for this device
507
508 for ( i = 0; i < numPowerTreeNodes; i++ ) {
509
510 entry = (OSDictionary *) inSubTree->getObject (i);
511
512 matchingDictionary = (OSDictionary *) entry->getObject ("device");
513 providerDictionary = (OSDictionary *) entry->getObject ("provider");
514
515 deviceMatch = true; // if no matching dictionary, this is not a criteria and so must match
516 if ( matchingDictionary ) {
517 deviceMatch = false;
518 if ( NULL != (deviceDictionary = theDevice->dictionaryWithProperties ())) {
519 deviceMatch = deviceDictionary->isEqualTo ( matchingDictionary, matchingDictionary );
520 deviceDictionary->release ();
521 }
522 }
523
524 providerMatch = true; // we indicate a match if there is no nub or provider
525 if ( theNub && providerDictionary ) {
526 providerMatch = false;
527 if ( NULL != (nubDictionary = theNub->dictionaryWithProperties ()) ) {
528 providerMatch = nubDictionary->isEqualTo ( providerDictionary, providerDictionary );
529 nubDictionary->release ();
530 }
531 }
532
533 multiParentMatch = true; // again we indicate a match if there is no multi-parent node
534 if (deviceMatch && providerMatch) {
535 if (NULL != multipleParentKeyValue) {
536 OSNumber * aNumber = (OSNumber *) entry->getObject ("multiple-parent");
537 multiParentMatch = (NULL != aNumber) ? multipleParentKeyValue->isEqualTo (aNumber) : false;
538 }
539 }
540
541 nodeFound = (deviceMatch && providerMatch && multiParentMatch);
542
543 // if the power tree specifies a provider dictionary but theNub is
544 // NULL then we cannot match with this entry.
545
546 if ( theNub == NULL && providerDictionary != NULL )
547 nodeFound = false;
548
549 // if this node is THE ONE...then register the device
550
551 if ( nodeFound ) {
552 if (RegisterServiceInTree (theDevice, entry, theParent, theNub) ) {
553
554 if ( kIOLogPower & gIOKitDebug)
555 IOLog ("PMRegisterDevice/CheckSubTree - service registered!\n");
556
557 numInstancesRegistered++;
558
559 // determine if we need to search for additional nodes for this item
560 multipleParentKeyValue = (OSNumber *) entry->getObject ("multiple-parent");
561 }
562 else
563 nodeFound = false;
564 }
565
566 continueSearch = ( (false == nodeFound) || (NULL != multipleParentKeyValue) );
567
568 if ( continueSearch && (NULL != (children = (OSArray *) entry->getObject ("children"))) ) {
569 nodeFound = CheckSubTree ( children, theNub, theDevice, entry );
570 continueSearch = ( (false == nodeFound) || (NULL != multipleParentKeyValue) );
571 }
572
573 if ( false == continueSearch )
574 break;
575 }
576
577 return ( nodeFound );
578 }
579
580 //*********************************************************************************
581 // RegisterServiceInTree
582 //
583 // Register a device at the specified node of our power tree.
584 //*********************************************************************************
585
586 bool IOPlatformExpert::RegisterServiceInTree (IOService * theService, OSDictionary * theTreeNode, OSDictionary * theTreeParentNode, IOService * theProvider)
587 {
588 IOService * aService;
589 bool registered = false;
590 OSArray * children;
591 unsigned int numChildren;
592 OSDictionary * child;
593
594 // make sure someone is not already registered here
595
596 if ( NULL == theTreeNode->getObject ("service") ) {
597
598 if ( theTreeNode->setObject ("service", OSDynamicCast ( OSObject, theService)) ) {
599
600 // 1. CHILDREN ------------------
601
602 // we registered the node in the tree...now if the node has children
603 // registered we must tell this service to add them.
604
605 if ( NULL != (children = (OSArray *) theTreeNode->getObject ("children")) ) {
606 numChildren = children->getCount ();
607 for ( unsigned int i = 0; i < numChildren; i++ ) {
608 if ( NULL != (child = (OSDictionary *) children->getObject (i)) ) {
609 if ( NULL != (aService = (IOService *) child->getObject ("service")) )
610 theService->addPowerChild (aService);
611 }
612 }
613 }
614
615 // 2. PARENT --------------------
616
617 // also we must notify the parent of this node (if a registered service
618 // exists there) of a new child.
619
620 if ( theTreeParentNode ) {
621 if ( NULL != (aService = (IOService *) theTreeParentNode->getObject ("service")) )
622 if (aService != theProvider)
623 aService->addPowerChild (theService);
624 }
625
626 registered = true;
627 }
628 }
629
630 return registered;
631 }
632
633 //*********************************************************************************
634 // printDictionaryKeys
635 //
636 // Print the keys for the given dictionary and selected contents.
637 //*********************************************************************************
638 void printDictionaryKeys (OSDictionary * inDictionary, char * inMsg)
639 {
640 OSCollectionIterator * mcoll = OSCollectionIterator::withCollection (inDictionary);
641 OSSymbol * mkey;
642 OSString * ioClass;
643 unsigned int i = 0;
644
645 mcoll->reset ();
646
647 mkey = OSDynamicCast (OSSymbol, mcoll->getNextObject ());
648
649 while (mkey) {
650
651 // kprintf ("dictionary key #%d: %s\n", i, mkey->getCStringNoCopy () );
652
653 // if this is the IOClass key, print it's contents
654
655 if ( mkey->isEqualTo ("IOClass") ) {
656 ioClass = (OSString *) inDictionary->getObject ("IOClass");
657 if ( ioClass ) IOLog ("%s IOClass is %s\n", inMsg, ioClass->getCStringNoCopy () );
658 }
659
660 // if this is an IOProviderClass key print it
661
662 if ( mkey->isEqualTo ("IOProviderClass") ) {
663 ioClass = (OSString *) inDictionary->getObject ("IOProviderClass");
664 if ( ioClass ) IOLog ("%s IOProviderClass is %s\n", inMsg, ioClass->getCStringNoCopy () );
665
666 }
667
668 // also print IONameMatch keys
669 if ( mkey->isEqualTo ("IONameMatch") ) {
670 ioClass = (OSString *) inDictionary->getObject ("IONameMatch");
671 if ( ioClass ) IOLog ("%s IONameMatch is %s\n", inMsg, ioClass->getCStringNoCopy () );
672 }
673
674 // also print IONameMatched keys
675
676 if ( mkey->isEqualTo ("IONameMatched") ) {
677 ioClass = (OSString *) inDictionary->getObject ("IONameMatched");
678 if ( ioClass ) IOLog ("%s IONameMatched is %s\n", inMsg, ioClass->getCStringNoCopy () );
679 }
680
681 #if 0
682 // print clock-id
683
684 if ( mkey->isEqualTo ("AAPL,clock-id") ) {
685 char * cstr;
686 cstr = getCStringForObject (inDictionary->getObject ("AAPL,clock-id"));
687 if (cstr)
688 kprintf (" ===> AAPL,clock-id is %s\n", cstr );
689 }
690 #endif
691
692 // print name
693
694 if ( mkey->isEqualTo ("name") ) {
695 char nameStr[64];
696 nameStr[0] = 0;
697 getCStringForObject(inDictionary->getObject("name"), nameStr,
698 sizeof(nameStr));
699 if (strlen(nameStr) > 0)
700 IOLog ("%s name is %s\n", inMsg, nameStr);
701 }
702
703 mkey = (OSSymbol *) mcoll->getNextObject ();
704
705 i++;
706 }
707
708 mcoll->release ();
709 }
710
711 static void
712 getCStringForObject(OSObject *inObj, char *outStr, size_t outStrLen)
713 {
714 char * buffer;
715 unsigned int len, i;
716
717 if ( (NULL == inObj) || (NULL == outStr))
718 return;
719
720 char * objString = (char *) (inObj->getMetaClass())->getClassName();
721
722 if ((0 == strncmp(objString, "OSString", sizeof("OSString"))) ||
723 (0 == strncmp(objString, "OSSymbol", sizeof("OSSymbol"))))
724 strlcpy(outStr, ((OSString *)inObj)->getCStringNoCopy(), outStrLen);
725
726 else if (0 == strncmp(objString, "OSData", sizeof("OSData"))) {
727 len = ((OSData *)inObj)->getLength();
728 buffer = (char *)((OSData *)inObj)->getBytesNoCopy();
729 if (buffer && (len > 0)) {
730 for (i=0; i < len; i++) {
731 outStr[i] = buffer[i];
732 }
733 outStr[len] = 0;
734 }
735 }
736 }
737
738 /* IOShutdownNotificationsTimedOut
739 * - Called from a timer installed by PEHaltRestart
740 */
741 static void IOShutdownNotificationsTimedOut(
742 thread_call_param_t p0,
743 thread_call_param_t p1)
744 {
745 int type = (int)(long)p0;
746
747 /* 30 seconds has elapsed - resume shutdown */
748 if(gIOPlatform) gIOPlatform->haltRestart(type);
749 }
750
751
752 extern "C" {
753
754 /*
755 * Callouts from BSD for machine name & model
756 */
757
758 boolean_t PEGetMachineName( char * name, int maxLength )
759 {
760 if( gIOPlatform)
761 return( gIOPlatform->getMachineName( name, maxLength ));
762 else
763 return( false );
764 }
765
766 boolean_t PEGetModelName( char * name, int maxLength )
767 {
768 if( gIOPlatform)
769 return( gIOPlatform->getModelName( name, maxLength ));
770 else
771 return( false );
772 }
773
774 int PEGetPlatformEpoch(void)
775 {
776 if( gIOPlatform)
777 return( gIOPlatform->getBootROMType());
778 else
779 return( -1 );
780 }
781
782 int PEHaltRestart(unsigned int type)
783 {
784 IOPMrootDomain *pmRootDomain = IOService::getPMRootDomain();
785 AbsoluteTime deadline;
786 thread_call_t shutdown_hang;
787
788 if(type == kPEHaltCPU || type == kPERestartCPU || type == kPEUPSDelayHaltCPU)
789 {
790 /* Notify IOKit PM clients of shutdown/restart
791 Clients subscribe to this message with a call to
792 IOService::registerInterest()
793 */
794
795 /* Spawn a thread that will panic in 30 seconds.
796 If all goes well the machine will be off by the time
797 the timer expires.
798 */
799 shutdown_hang = thread_call_allocate( &IOShutdownNotificationsTimedOut,
800 (thread_call_param_t) type);
801 clock_interval_to_deadline( 30, kSecondScale, &deadline );
802 thread_call_enter1_delayed( shutdown_hang, 0, deadline );
803
804 pmRootDomain->handlePlatformHaltRestart(type);
805 /* This notification should have few clients who all do
806 their work synchronously.
807
808 In this "shutdown notification" context we don't give
809 drivers the option of working asynchronously and responding
810 later. PM internals make it very hard to wait for asynchronous
811 replies.
812 */
813 }
814
815 if (gIOPlatform) return gIOPlatform->haltRestart(type);
816 else return -1;
817 }
818
819 UInt32 PESavePanicInfo(UInt8 *buffer, UInt32 length)
820 {
821 if (gIOPlatform != 0) return gIOPlatform->savePanicInfo(buffer, length);
822 else return 0;
823 }
824
825 long PEGetGMTTimeOfDay(void)
826 {
827 long result = 0;
828
829 if( gIOPlatform) result = gIOPlatform->getGMTTimeOfDay();
830
831 return (result);
832 }
833
834 void PESetGMTTimeOfDay(long secs)
835 {
836 if( gIOPlatform) gIOPlatform->setGMTTimeOfDay(secs);
837 }
838
839 } /* extern "C" */
840
841 void IOPlatformExpert::registerNVRAMController(IONVRAMController * caller)
842 {
843 OSData * data;
844 IORegistryEntry * entry;
845 OSString * string = 0;
846 uuid_string_t uuid;
847
848 entry = IORegistryEntry::fromPath( "/efi/platform", gIODTPlane );
849 if ( entry )
850 {
851 data = OSDynamicCast( OSData, entry->getProperty( "system-id" ) );
852 if ( data && data->getLength( ) == 16 )
853 {
854 SHA1_CTX context;
855 uint8_t digest[ SHA_DIGEST_LENGTH ];
856 const uuid_t space = { 0x2A, 0x06, 0x19, 0x90, 0xD3, 0x8D, 0x44, 0x40, 0xA1, 0x39, 0xC4, 0x97, 0x70, 0x37, 0x65, 0xAC };
857
858 SHA1Init( &context );
859 SHA1Update( &context, space, sizeof( space ) );
860 SHA1Update( &context, data->getBytesNoCopy( ), data->getLength( ) );
861 SHA1Final( digest, &context );
862
863 digest[ 6 ] = ( digest[ 6 ] & 0x0F ) | 0x50;
864 digest[ 8 ] = ( digest[ 8 ] & 0x3F ) | 0x80;
865
866 uuid_unparse( digest, uuid );
867 string = OSString::withCString( uuid );
868 }
869
870 entry->release( );
871 }
872
873 if ( string == 0 )
874 {
875 entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
876 if ( entry )
877 {
878 data = OSDynamicCast( OSData, entry->getProperty( "platform-uuid" ) );
879 if ( data && data->getLength( ) == sizeof( uuid_t ) )
880 {
881 uuid_unparse( ( uint8_t * ) data->getBytesNoCopy( ), uuid );
882 string = OSString::withCString( uuid );
883 }
884
885 entry->release( );
886 }
887 }
888
889 if ( string )
890 {
891 getProvider( )->setProperty( kIOPlatformUUIDKey, string );
892 publishResource( kIOPlatformUUIDKey, string );
893
894 string->release( );
895 }
896
897 publishResource("IONVRAM");
898 }
899
900 IOReturn IOPlatformExpert::callPlatformFunction(const OSSymbol *functionName,
901 bool waitForFunction,
902 void *param1, void *param2,
903 void *param3, void *param4)
904 {
905 IOService *service, *_resources;
906
907 if (waitForFunction) {
908 _resources = waitForService(resourceMatching(functionName));
909 } else {
910 _resources = getResourceService();
911 }
912 if (_resources == 0) return kIOReturnUnsupported;
913
914 service = OSDynamicCast(IOService, _resources->getProperty(functionName));
915 if (service == 0) return kIOReturnUnsupported;
916
917 return service->callPlatformFunction(functionName, waitForFunction,
918 param1, param2, param3, param4);
919 }
920
921 IOByteCount IOPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length)
922 {
923 return 0;
924 }
925
926 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
927
928 #undef super
929 #define super IOPlatformExpert
930
931 OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert, IOPlatformExpert )
932
933 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 0);
934 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 1);
935 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 2);
936 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 3);
937 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 4);
938 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 5);
939 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 6);
940 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 7);
941
942 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
943
944 IOService * IODTPlatformExpert::probe( IOService * provider,
945 SInt32 * score )
946 {
947 if( !super::probe( provider, score))
948 return( 0 );
949
950 // check machine types
951 if( !provider->compareNames( getProperty( gIONameMatchKey ) ))
952 return( 0 );
953
954 return( this);
955 }
956
957 bool IODTPlatformExpert::configure( IOService * provider )
958 {
959 if( !super::configure( provider))
960 return( false);
961
962 processTopLevel( provider );
963
964 return( true );
965 }
966
967 IOService * IODTPlatformExpert::createNub( IORegistryEntry * from )
968 {
969 IOService * nub;
970
971 nub = new IOPlatformDevice;
972 if( nub) {
973 if( !nub->init( from, gIODTPlane )) {
974 nub->free();
975 nub = 0;
976 }
977 }
978 return( nub);
979 }
980
981 bool IODTPlatformExpert::createNubs( IOService * parent, OSIterator * iter )
982 {
983 IORegistryEntry * next;
984 IOService * nub;
985 bool ok = true;
986
987 if( iter) {
988 while( (next = (IORegistryEntry *) iter->getNextObject())) {
989
990 if( 0 == (nub = createNub( next )))
991 continue;
992
993 nub->attach( parent );
994 nub->registerService();
995 }
996 iter->release();
997 }
998
999 return( ok );
1000 }
1001
1002 void IODTPlatformExpert::processTopLevel( IORegistryEntry * rootEntry )
1003 {
1004 OSIterator * kids;
1005 IORegistryEntry * next;
1006 IORegistryEntry * cpus;
1007 IORegistryEntry * options;
1008
1009 // infanticide
1010 kids = IODTFindMatchingEntries( rootEntry, 0, deleteList() );
1011 if( kids) {
1012 while( (next = (IORegistryEntry *)kids->getNextObject())) {
1013 next->detachAll( gIODTPlane);
1014 }
1015 kids->release();
1016 }
1017
1018 // Publish an IODTNVRAM class on /options.
1019 options = rootEntry->childFromPath("options", gIODTPlane);
1020 if (options) {
1021 dtNVRAM = new IODTNVRAM;
1022 if (dtNVRAM) {
1023 if (!dtNVRAM->init(options, gIODTPlane)) {
1024 dtNVRAM->release();
1025 dtNVRAM = 0;
1026 } else {
1027 dtNVRAM->attach(this);
1028 dtNVRAM->registerService();
1029 }
1030 }
1031 }
1032
1033 // Publish the cpus.
1034 cpus = rootEntry->childFromPath( "cpus", gIODTPlane);
1035 if ( cpus)
1036 createNubs( this, IODTFindMatchingEntries( cpus, kIODTExclusive, 0));
1037
1038 // publish top level, minus excludeList
1039 createNubs( this, IODTFindMatchingEntries( rootEntry, kIODTExclusive, excludeList()));
1040 }
1041
1042 IOReturn IODTPlatformExpert::getNubResources( IOService * nub )
1043 {
1044 if( nub->getDeviceMemory())
1045 return( kIOReturnSuccess );
1046
1047 IODTResolveAddressing( nub, "reg", 0);
1048
1049 return( kIOReturnSuccess);
1050 }
1051
1052 bool IODTPlatformExpert::compareNubName( const IOService * nub,
1053 OSString * name, OSString ** matched ) const
1054 {
1055 return( IODTCompareNubName( nub, name, matched )
1056 || super::compareNubName( nub, name, matched) );
1057 }
1058
1059 bool IODTPlatformExpert::getModelName( char * name, int maxLength )
1060 {
1061 OSData * prop;
1062 const char * str;
1063 int len;
1064 char c;
1065 bool ok = false;
1066
1067 maxLength--;
1068
1069 prop = (OSData *) getProvider()->getProperty( gIODTCompatibleKey );
1070 if( prop ) {
1071 str = (const char *) prop->getBytesNoCopy();
1072
1073 if( 0 == strncmp( str, "AAPL,", strlen( "AAPL," ) ))
1074 str += strlen( "AAPL," );
1075
1076 len = 0;
1077 while( (c = *str++)) {
1078 if( (c == '/') || (c == ' '))
1079 c = '-';
1080
1081 name[ len++ ] = c;
1082 if( len >= maxLength)
1083 break;
1084 }
1085
1086 name[ len ] = 0;
1087 ok = true;
1088 }
1089 return( ok );
1090 }
1091
1092 bool IODTPlatformExpert::getMachineName( char * name, int maxLength )
1093 {
1094 OSData * prop;
1095 bool ok = false;
1096
1097 maxLength--;
1098 prop = (OSData *) getProvider()->getProperty( gIODTModelKey );
1099 ok = (0 != prop);
1100
1101 if( ok )
1102 strlcpy( name, (const char *) prop->getBytesNoCopy(), maxLength );
1103
1104 return( ok );
1105 }
1106
1107 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1108
1109 void IODTPlatformExpert::registerNVRAMController( IONVRAMController * nvram )
1110 {
1111 if (dtNVRAM) dtNVRAM->registerNVRAMController(nvram);
1112
1113 super::registerNVRAMController(nvram);
1114 }
1115
1116 int IODTPlatformExpert::haltRestart(unsigned int type)
1117 {
1118 if (dtNVRAM) dtNVRAM->sync();
1119
1120 return super::haltRestart(type);
1121 }
1122
1123 IOReturn IODTPlatformExpert::readXPRAM(IOByteCount offset, UInt8 * buffer,
1124 IOByteCount length)
1125 {
1126 if (dtNVRAM) return dtNVRAM->readXPRAM(offset, buffer, length);
1127 else return kIOReturnNotReady;
1128 }
1129
1130 IOReturn IODTPlatformExpert::writeXPRAM(IOByteCount offset, UInt8 * buffer,
1131 IOByteCount length)
1132 {
1133 if (dtNVRAM) return dtNVRAM->writeXPRAM(offset, buffer, length);
1134 else return kIOReturnNotReady;
1135 }
1136
1137 IOReturn IODTPlatformExpert::readNVRAMProperty(
1138 IORegistryEntry * entry,
1139 const OSSymbol ** name, OSData ** value )
1140 {
1141 if (dtNVRAM) return dtNVRAM->readNVRAMProperty(entry, name, value);
1142 else return kIOReturnNotReady;
1143 }
1144
1145 IOReturn IODTPlatformExpert::writeNVRAMProperty(
1146 IORegistryEntry * entry,
1147 const OSSymbol * name, OSData * value )
1148 {
1149 if (dtNVRAM) return dtNVRAM->writeNVRAMProperty(entry, name, value);
1150 else return kIOReturnNotReady;
1151 }
1152
1153 OSDictionary *IODTPlatformExpert::getNVRAMPartitions(void)
1154 {
1155 if (dtNVRAM) return dtNVRAM->getNVRAMPartitions();
1156 else return 0;
1157 }
1158
1159 IOReturn IODTPlatformExpert::readNVRAMPartition(const OSSymbol * partitionID,
1160 IOByteCount offset, UInt8 * buffer,
1161 IOByteCount length)
1162 {
1163 if (dtNVRAM) return dtNVRAM->readNVRAMPartition(partitionID, offset,
1164 buffer, length);
1165 else return kIOReturnNotReady;
1166 }
1167
1168 IOReturn IODTPlatformExpert::writeNVRAMPartition(const OSSymbol * partitionID,
1169 IOByteCount offset, UInt8 * buffer,
1170 IOByteCount length)
1171 {
1172 if (dtNVRAM) return dtNVRAM->writeNVRAMPartition(partitionID, offset,
1173 buffer, length);
1174 else return kIOReturnNotReady;
1175 }
1176
1177 IOByteCount IODTPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length)
1178 {
1179 IOByteCount lengthSaved = 0;
1180
1181 if (dtNVRAM) lengthSaved = dtNVRAM->savePanicInfo(buffer, length);
1182
1183 if (lengthSaved == 0) lengthSaved = super::savePanicInfo(buffer, length);
1184
1185 return lengthSaved;
1186 }
1187
1188 OSString* IODTPlatformExpert::createSystemSerialNumberString(OSData* myProperty) {
1189 UInt8* serialNumber;
1190 unsigned int serialNumberSize;
1191 unsigned short pos = 0;
1192 char* temp;
1193 char SerialNo[30];
1194
1195 if (myProperty != NULL) {
1196 serialNumberSize = myProperty->getLength();
1197 serialNumber = (UInt8*)(myProperty->getBytesNoCopy());
1198 temp = (char*)serialNumber;
1199 if (serialNumberSize > 0) {
1200 // check to see if this is a CTO serial number...
1201 while (pos < serialNumberSize && temp[pos] != '-') pos++;
1202
1203 if (pos < serialNumberSize) { // there was a hyphen, so it's a CTO serial number
1204 memcpy(SerialNo, serialNumber + 12, 8);
1205 memcpy(&SerialNo[8], serialNumber, 3);
1206 SerialNo[11] = '-';
1207 memcpy(&SerialNo[12], serialNumber + 3, 8);
1208 SerialNo[20] = 0;
1209 } else { // just a normal serial number
1210 memcpy(SerialNo, serialNumber + 13, 8);
1211 memcpy(&SerialNo[8], serialNumber, 3);
1212 SerialNo[11] = 0;
1213 }
1214 return OSString::withCString(SerialNo);
1215 }
1216 }
1217 return NULL;
1218 }
1219
1220
1221 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1222
1223 #undef super
1224 #define super IOService
1225
1226 OSDefineMetaClassAndStructors(IOPlatformExpertDevice, IOService)
1227
1228 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 0);
1229 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 1);
1230 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 2);
1231 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 3);
1232
1233 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1234
1235 bool IOPlatformExpertDevice::compareName( OSString * name,
1236 OSString ** matched ) const
1237 {
1238 return( IODTCompareNubName( this, name, matched ));
1239 }
1240
1241 bool
1242 IOPlatformExpertDevice::initWithArgs(
1243 void * dtTop, void * p2, void * p3, void * p4 )
1244 {
1245 IORegistryEntry * dt = 0;
1246 void * argsData[ 4 ];
1247 bool ok;
1248
1249 // dtTop may be zero on non- device tree systems
1250 if( dtTop && (dt = IODeviceTreeAlloc( dtTop )))
1251 ok = super::init( dt, gIODTPlane );
1252 else
1253 ok = super::init();
1254
1255 if( !ok)
1256 return( false);
1257
1258 workLoop = IOWorkLoop::workLoop();
1259 if (!workLoop)
1260 return false;
1261
1262 argsData[ 0 ] = dtTop;
1263 argsData[ 1 ] = p2;
1264 argsData[ 2 ] = p3;
1265 argsData[ 3 ] = p4;
1266
1267 setProperty("IOPlatformArgs", (void *)argsData, sizeof(argsData));
1268
1269 return( true);
1270 }
1271
1272 IOWorkLoop *IOPlatformExpertDevice::getWorkLoop() const
1273 {
1274 return workLoop;
1275 }
1276
1277 IOReturn IOPlatformExpertDevice::setProperties( OSObject * properties )
1278 {
1279 OSDictionary * dictionary;
1280 OSObject * object;
1281 IOReturn status;
1282
1283 status = super::setProperties( properties );
1284 if ( status != kIOReturnUnsupported ) return status;
1285
1286 status = IOUserClient::clientHasPrivilege( current_task( ), kIOClientPrivilegeAdministrator );
1287 if ( status != kIOReturnSuccess ) return status;
1288
1289 dictionary = OSDynamicCast( OSDictionary, properties );
1290 if ( dictionary == 0 ) return kIOReturnBadArgument;
1291
1292 object = dictionary->getObject( kIOPlatformUUIDKey );
1293 if ( object )
1294 {
1295 IORegistryEntry * entry;
1296 OSString * string;
1297 uuid_t uuid;
1298
1299 string = ( OSString * ) getProperty( kIOPlatformUUIDKey );
1300 if ( string ) return kIOReturnNotPermitted;
1301
1302 string = OSDynamicCast( OSString, object );
1303 if ( string == 0 ) return kIOReturnBadArgument;
1304
1305 status = uuid_parse( string->getCStringNoCopy( ), uuid );
1306 if ( status != 0 ) return kIOReturnBadArgument;
1307
1308 entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
1309 if ( entry )
1310 {
1311 entry->setProperty( "platform-uuid", uuid, sizeof( uuid_t ) );
1312 entry->release( );
1313 }
1314
1315 setProperty( kIOPlatformUUIDKey, string );
1316 publishResource( kIOPlatformUUIDKey, string );
1317
1318 return kIOReturnSuccess;
1319 }
1320
1321 return kIOReturnUnsupported;
1322 }
1323
1324 void IOPlatformExpertDevice::free()
1325 {
1326 if (workLoop)
1327 workLoop->release();
1328 }
1329
1330 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1331
1332 #undef super
1333 #define super IOService
1334
1335 OSDefineMetaClassAndStructors(IOPlatformDevice, IOService)
1336
1337 OSMetaClassDefineReservedUnused(IOPlatformDevice, 0);
1338 OSMetaClassDefineReservedUnused(IOPlatformDevice, 1);
1339 OSMetaClassDefineReservedUnused(IOPlatformDevice, 2);
1340 OSMetaClassDefineReservedUnused(IOPlatformDevice, 3);
1341
1342 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1343
1344 bool IOPlatformDevice::compareName( OSString * name,
1345 OSString ** matched ) const
1346 {
1347 return( ((IOPlatformExpert *)getProvider())->
1348 compareNubName( this, name, matched ));
1349 }
1350
1351 IOService * IOPlatformDevice::matchLocation( IOService * /* client */ )
1352 {
1353 return( this );
1354 }
1355
1356 IOReturn IOPlatformDevice::getResources( void )
1357 {
1358 return( ((IOPlatformExpert *)getProvider())->getNubResources( this ));
1359 }
1360
1361 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1362
1363 /*********************************************************************
1364 * IOPanicPlatform class
1365 *
1366 * If no legitimate IOPlatformDevice matches, this one does and panics
1367 * the kernel with a suitable message.
1368 *********************************************************************/
1369
1370 class IOPanicPlatform : IOPlatformExpert {
1371 OSDeclareDefaultStructors(IOPanicPlatform);
1372
1373 public:
1374 bool start(IOService * provider);
1375 };
1376
1377
1378 OSDefineMetaClassAndStructors(IOPanicPlatform, IOPlatformExpert);
1379
1380
1381 bool IOPanicPlatform::start(IOService * provider) {
1382 const char * platform_name = "(unknown platform name)";
1383
1384 if (provider) platform_name = provider->getName();
1385
1386 panic("Unable to find driver for this platform: \"%s\".\n",
1387 platform_name);
1388
1389 return false;
1390 }
1391