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