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