]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOPlatformExpert.cpp
xnu-792.13.8.tar.gz
[apple/xnu.git] / iokit / Kernel / IOPlatformExpert.cpp
1 /*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30 /*
31 * HISTORY
32 */
33
34 #include <IOKit/IOCPU.h>
35 #include <IOKit/IODeviceTreeSupport.h>
36 #include <IOKit/IOKitDebug.h>
37 #include <IOKit/IOMapper.h>
38 #include <IOKit/IOMessage.h>
39 #include <IOKit/IONVRAM.h>
40 #include <IOKit/IOPlatformExpert.h>
41 #include <IOKit/IORangeAllocator.h>
42 #include <IOKit/IOWorkLoop.h>
43 #include <IOKit/pwr_mgt/RootDomain.h>
44 #include <IOKit/IOKitKeys.h>
45 #include <IOKit/IOTimeStamp.h>
46
47 #include <IOKit/system.h>
48
49 #include <libkern/c++/OSContainers.h>
50
51 extern "C" {
52 #include <machine/machine_routines.h>
53 #include <pexpert/pexpert.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);
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 == kPEHangCPU) while (1);
255
256 if (type == kPEUPSDelayHaltCPU) {
257 // Stall shutdown for 5 minutes, and if no outside force has
258 // removed our power at that point, proceed with a reboot.
259 IOSleep( kUPSDelayHaltCPU_msec );
260
261 // Ideally we never reach this point.
262
263 type = kPERestartCPU;
264 }
265
266 if (PE_halt_restart) return (*PE_halt_restart)(type);
267 else return -1;
268 }
269
270 void IOPlatformExpert::sleepKernel(void)
271 {
272 #if 0
273 long cnt;
274 boolean_t intState;
275
276 intState = ml_set_interrupts_enabled(false);
277
278 for (cnt = 0; cnt < 10000; cnt++) {
279 IODelay(1000);
280 }
281
282 ml_set_interrupts_enabled(intState);
283 #else
284 // PE_initialize_console(0, kPEDisableScreen);
285
286 IOCPUSleepKernel();
287
288 // PE_initialize_console(0, kPEEnableScreen);
289 #endif
290 }
291
292 long IOPlatformExpert::getGMTTimeOfDay(void)
293 {
294 return(0);
295 }
296
297 void IOPlatformExpert::setGMTTimeOfDay(long secs)
298 {
299 }
300
301
302 IOReturn IOPlatformExpert::getConsoleInfo( PE_Video * consoleInfo )
303 {
304 return( PE_current_console( consoleInfo));
305 }
306
307 IOReturn IOPlatformExpert::setConsoleInfo( PE_Video * consoleInfo,
308 unsigned int op)
309 {
310 return( PE_initialize_console( consoleInfo, op ));
311 }
312
313 IOReturn IOPlatformExpert::registerInterruptController(OSSymbol *name, IOInterruptController *interruptController)
314 {
315 IOLockLock(gIOInterruptControllersLock);
316
317 gIOInterruptControllers->setObject(name, interruptController);
318
319 IOLockWakeup(gIOInterruptControllersLock,
320 gIOInterruptControllers, /* one-thread */ false);
321
322 IOLockUnlock(gIOInterruptControllersLock);
323
324 return kIOReturnSuccess;
325 }
326
327 IOInterruptController *IOPlatformExpert::lookUpInterruptController(OSSymbol *name)
328 {
329 OSObject *object;
330
331 IOLockLock(gIOInterruptControllersLock);
332 while (1) {
333
334 object = gIOInterruptControllers->getObject(name);
335
336 if (object != 0)
337 break;
338
339 IOLockSleep(gIOInterruptControllersLock,
340 gIOInterruptControllers, THREAD_UNINT);
341 }
342
343 IOLockUnlock(gIOInterruptControllersLock);
344 return OSDynamicCast(IOInterruptController, object);
345 }
346
347
348 void IOPlatformExpert::setCPUInterruptProperties(IOService *service)
349 {
350 IOCPUInterruptController *controller;
351
352 controller = OSDynamicCast(IOCPUInterruptController, waitForService(serviceMatching("IOCPUInterruptController")));
353 if (controller) controller->setCPUInterruptProperties(service);
354 }
355
356 bool IOPlatformExpert::atInterruptLevel(void)
357 {
358 return ml_at_interrupt_context();
359 }
360
361 bool IOPlatformExpert::platformAdjustService(IOService */*service*/)
362 {
363 return true;
364 }
365
366
367 //*********************************************************************************
368 // PMLog
369 //
370 //*********************************************************************************
371
372 void IOPlatformExpert::
373 PMLog(const char *who, unsigned long event,
374 unsigned long param1, unsigned long param2)
375 {
376 UInt32 debugFlags = gIOKitDebug;
377
378 if (debugFlags & kIOLogPower) {
379
380 uint32_t nows, nowus;
381 clock_get_system_microtime(&nows, &nowus);
382 nowus += (nows % 1000) * 1000000;
383
384 kprintf("pm%u %x %.30s %d %x %x\n",
385 nowus, (unsigned) current_thread(), who, // Identity
386 (int) event, param1, 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, (UInt32) 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 root->youAreRoot();
430 }
431
432
433 //*********************************************************************************
434 // PMRegisterDevice
435 //
436 // In this vanilla implementation, all callers are made children of the root power domain.
437 // Where this is inappropriate, PMRegisterDevice is overridden in a platform-specific subclass.
438 //*********************************************************************************
439
440 void IOPlatformExpert::PMRegisterDevice(IOService * theNub, IOService * theDevice)
441 {
442 root->addPowerChild ( theDevice );
443 }
444
445 //*********************************************************************************
446 // hasPMFeature
447 //
448 //*********************************************************************************
449
450 bool IOPlatformExpert::hasPMFeature (unsigned long featureMask)
451 {
452 return ((_pePMFeatures & featureMask) != 0);
453 }
454
455 //*********************************************************************************
456 // hasPrivPMFeature
457 //
458 //*********************************************************************************
459
460 bool IOPlatformExpert::hasPrivPMFeature (unsigned long privFeatureMask)
461 {
462 return ((_pePrivPMFeatures & privFeatureMask) != 0);
463 }
464
465 //*********************************************************************************
466 // numBatteriesSupported
467 //
468 //*********************************************************************************
469
470 int IOPlatformExpert::numBatteriesSupported (void)
471 {
472 return (_peNumBatteriesSupported);
473 }
474
475 //*********************************************************************************
476 // CheckSubTree
477 //
478 // This method is called by the instantiated sublass of the platform expert to
479 // determine how a device should be inserted into the Power Domain. The subclass
480 // provides an XML power tree description against which a device is matched based
481 // on class and provider. If a match is found this routine returns true in addition
482 // to flagging the description tree at the appropriate node that a device has been
483 // registered for the given service.
484 //*********************************************************************************
485
486 bool IOPlatformExpert::CheckSubTree (OSArray * inSubTree, IOService * theNub, IOService * theDevice, OSDictionary * theParent)
487 {
488 unsigned int i;
489 unsigned int numPowerTreeNodes;
490 OSDictionary * entry;
491 OSDictionary * matchingDictionary;
492 OSDictionary * providerDictionary;
493 OSDictionary * deviceDictionary;
494 OSDictionary * nubDictionary;
495 OSArray * children;
496 bool nodeFound = false;
497 bool continueSearch = false;
498 bool deviceMatch = false;
499 bool providerMatch = false;
500 bool multiParentMatch = false;
501
502 if ( (NULL == theDevice) || (NULL == inSubTree) )
503 return false;
504
505 numPowerTreeNodes = inSubTree->getCount ();
506
507 // iterate through the power tree to find a home for this device
508
509 for ( i = 0; i < numPowerTreeNodes; i++ ) {
510
511 entry = (OSDictionary *) inSubTree->getObject (i);
512
513 matchingDictionary = (OSDictionary *) entry->getObject ("device");
514 providerDictionary = (OSDictionary *) entry->getObject ("provider");
515
516 deviceMatch = true; // if no matching dictionary, this is not a criteria and so must match
517 if ( matchingDictionary ) {
518 deviceMatch = false;
519 if ( NULL != (deviceDictionary = theDevice->dictionaryWithProperties ())) {
520 deviceMatch = deviceDictionary->isEqualTo ( matchingDictionary, matchingDictionary );
521 deviceDictionary->release ();
522 }
523 }
524
525 providerMatch = true; // we indicate a match if there is no nub or provider
526 if ( theNub && providerDictionary ) {
527 providerMatch = false;
528 if ( NULL != (nubDictionary = theNub->dictionaryWithProperties ()) ) {
529 providerMatch = nubDictionary->isEqualTo ( providerDictionary, providerDictionary );
530 nubDictionary->release ();
531 }
532 }
533
534 multiParentMatch = true; // again we indicate a match if there is no multi-parent node
535 if (deviceMatch && providerMatch) {
536 if (NULL != multipleParentKeyValue) {
537 OSNumber * aNumber = (OSNumber *) entry->getObject ("multiple-parent");
538 multiParentMatch = (NULL != aNumber) ? multipleParentKeyValue->isEqualTo (aNumber) : false;
539 }
540 }
541
542 nodeFound = (deviceMatch && providerMatch && multiParentMatch);
543
544 // if the power tree specifies a provider dictionary but theNub is
545 // NULL then we cannot match with this entry.
546
547 if ( theNub == NULL && providerDictionary != NULL )
548 nodeFound = false;
549
550 // if this node is THE ONE...then register the device
551
552 if ( nodeFound ) {
553 if (RegisterServiceInTree (theDevice, entry, theParent, theNub) ) {
554
555 if ( kIOLogPower & gIOKitDebug)
556 IOLog ("PMRegisterDevice/CheckSubTree - service registered!\n");
557
558 numInstancesRegistered++;
559
560 // determine if we need to search for additional nodes for this item
561 multipleParentKeyValue = (OSNumber *) entry->getObject ("multiple-parent");
562 }
563 else
564 nodeFound = false;
565 }
566
567 continueSearch = ( (false == nodeFound) || (NULL != multipleParentKeyValue) );
568
569 if ( continueSearch && (NULL != (children = (OSArray *) entry->getObject ("children"))) ) {
570 nodeFound = CheckSubTree ( children, theNub, theDevice, entry );
571 continueSearch = ( (false == nodeFound) || (NULL != multipleParentKeyValue) );
572 }
573
574 if ( false == continueSearch )
575 break;
576 }
577
578 return ( nodeFound );
579 }
580
581 //*********************************************************************************
582 // RegisterServiceInTree
583 //
584 // Register a device at the specified node of our power tree.
585 //*********************************************************************************
586
587 bool IOPlatformExpert::RegisterServiceInTree (IOService * theService, OSDictionary * theTreeNode, OSDictionary * theTreeParentNode, IOService * theProvider)
588 {
589 IOService * aService;
590 bool registered = false;
591 OSArray * children;
592 unsigned int numChildren;
593 OSDictionary * child;
594
595 // make sure someone is not already registered here
596
597 if ( NULL == theTreeNode->getObject ("service") ) {
598
599 if ( theTreeNode->setObject ("service", OSDynamicCast ( OSObject, theService)) ) {
600
601 // 1. CHILDREN ------------------
602
603 // we registered the node in the tree...now if the node has children
604 // registered we must tell this service to add them.
605
606 if ( NULL != (children = (OSArray *) theTreeNode->getObject ("children")) ) {
607 numChildren = children->getCount ();
608 for ( unsigned int i = 0; i < numChildren; i++ ) {
609 if ( NULL != (child = (OSDictionary *) children->getObject (i)) ) {
610 if ( NULL != (aService = (IOService *) child->getObject ("service")) )
611 theService->addPowerChild (aService);
612 }
613 }
614 }
615
616 // 2. PARENT --------------------
617
618 // also we must notify the parent of this node (if a registered service
619 // exists there) of a new child.
620
621 if ( theTreeParentNode ) {
622 if ( NULL != (aService = (IOService *) theTreeParentNode->getObject ("service")) )
623 if (aService != theProvider)
624 aService->addPowerChild (theService);
625 }
626
627 registered = true;
628 }
629 }
630
631 return registered;
632 }
633
634 //*********************************************************************************
635 // printDictionaryKeys
636 //
637 // Print the keys for the given dictionary and selected contents.
638 //*********************************************************************************
639 void printDictionaryKeys (OSDictionary * inDictionary, char * inMsg)
640 {
641 OSCollectionIterator * mcoll = OSCollectionIterator::withCollection (inDictionary);
642 OSSymbol * mkey;
643 OSString * ioClass;
644 unsigned int i = 0;
645
646 mcoll->reset ();
647
648 mkey = OSDynamicCast (OSSymbol, mcoll->getNextObject ());
649
650 while (mkey) {
651
652 // kprintf ("dictionary key #%d: %s\n", i, mkey->getCStringNoCopy () );
653
654 // if this is the IOClass key, print it's contents
655
656 if ( mkey->isEqualTo ("IOClass") ) {
657 ioClass = (OSString *) inDictionary->getObject ("IOClass");
658 if ( ioClass ) IOLog ("%s IOClass is %s\n", inMsg, ioClass->getCStringNoCopy () );
659 }
660
661 // if this is an IOProviderClass key print it
662
663 if ( mkey->isEqualTo ("IOProviderClass") ) {
664 ioClass = (OSString *) inDictionary->getObject ("IOProviderClass");
665 if ( ioClass ) IOLog ("%s IOProviderClass is %s\n", inMsg, ioClass->getCStringNoCopy () );
666
667 }
668
669 // also print IONameMatch keys
670 if ( mkey->isEqualTo ("IONameMatch") ) {
671 ioClass = (OSString *) inDictionary->getObject ("IONameMatch");
672 if ( ioClass ) IOLog ("%s IONameMatch is %s\n", inMsg, ioClass->getCStringNoCopy () );
673 }
674
675 // also print IONameMatched keys
676
677 if ( mkey->isEqualTo ("IONameMatched") ) {
678 ioClass = (OSString *) inDictionary->getObject ("IONameMatched");
679 if ( ioClass ) IOLog ("%s IONameMatched is %s\n", inMsg, ioClass->getCStringNoCopy () );
680 }
681
682 #if 0
683 // print clock-id
684
685 if ( mkey->isEqualTo ("AAPL,clock-id") ) {
686 char * cstr;
687 cstr = getCStringForObject (inDictionary->getObject ("AAPL,clock-id"));
688 if (cstr)
689 kprintf (" ===> AAPL,clock-id is %s\n", cstr );
690 }
691 #endif
692
693 // print name
694
695 if ( mkey->isEqualTo ("name") ) {
696 char nameStr[64];
697 nameStr[0] = 0;
698 getCStringForObject (inDictionary->getObject ("name"), 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 getCStringForObject (OSObject * inObj, char * outStr)
712 {
713 char * buffer;
714 unsigned int len, i;
715
716 if ( (NULL == inObj) || (NULL == outStr))
717 return;
718
719 char * objString = (char *) (inObj->getMetaClass())->getClassName();
720
721 if ((0 == strcmp(objString,"OSString")) || (0 == strcmp (objString, "OSSymbol")))
722 strcpy (outStr, ((OSString *)inObj)->getCStringNoCopy());
723
724 else if (0 == strcmp(objString,"OSData")) {
725 len = ((OSData *)inObj)->getLength();
726 buffer = (char *)((OSData *)inObj)->getBytesNoCopy();
727 if (buffer && (len > 0)) {
728 for (i=0; i < len; i++) {
729 outStr[i] = buffer[i];
730 }
731 outStr[len] = 0;
732 }
733 }
734 }
735
736 /* IOShutdownNotificationsTimedOut
737 * - Called from a timer installed by PEHaltRestart
738 */
739 static void IOShutdownNotificationsTimedOut(
740 thread_call_param_t p0,
741 thread_call_param_t p1)
742 {
743 int type = (int)p0;
744
745 /* 30 seconds has elapsed - resume shutdown */
746 if(gIOPlatform) gIOPlatform->haltRestart(type);
747 }
748
749
750 extern "C" {
751
752 /*
753 * Callouts from BSD for machine name & model
754 */
755
756 boolean_t PEGetMachineName( char * name, int maxLength )
757 {
758 if( gIOPlatform)
759 return( gIOPlatform->getMachineName( name, maxLength ));
760 else
761 return( false );
762 }
763
764 boolean_t PEGetModelName( char * name, int maxLength )
765 {
766 if( gIOPlatform)
767 return( gIOPlatform->getModelName( name, maxLength ));
768 else
769 return( false );
770 }
771
772 int PEGetPlatformEpoch(void)
773 {
774 if( gIOPlatform)
775 return( gIOPlatform->getBootROMType());
776 else
777 return( -1 );
778 }
779
780 int PEHaltRestart(unsigned int type)
781 {
782 IOPMrootDomain *pmRootDomain = IOService::getPMRootDomain();
783 bool noWaitForResponses;
784 AbsoluteTime deadline;
785 thread_call_t shutdown_hang;
786 unsigned int tell_type;
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
805 if( kPEUPSDelayHaltCPU == type ) {
806 tell_type = kPEHaltCPU;
807 } else {
808 tell_type = type;
809 }
810
811 noWaitForResponses = pmRootDomain->tellChangeDown2(tell_type);
812 /* This notification should have few clients who all do
813 their work synchronously.
814
815 In this "shutdown notification" context we don't give
816 drivers the option of working asynchronously and responding
817 later. PM internals make it very hard to wait for asynchronous
818 replies. In fact, it's a bad idea to even be calling
819 tellChangeDown2 from here at all.
820 */
821 }
822
823 if (gIOPlatform) return gIOPlatform->haltRestart(type);
824 else return -1;
825 }
826
827 UInt32 PESavePanicInfo(UInt8 *buffer, UInt32 length)
828 {
829 if (gIOPlatform != 0) return gIOPlatform->savePanicInfo(buffer, length);
830 else return 0;
831 }
832
833 long PEGetGMTTimeOfDay(void)
834 {
835 long result = 0;
836
837 if( gIOPlatform)
838 result = gIOPlatform->getGMTTimeOfDay();
839
840 return (result);
841 }
842
843 void PESetGMTTimeOfDay(long secs)
844 {
845 if( gIOPlatform)
846 gIOPlatform->setGMTTimeOfDay(secs);
847 }
848
849 } /* extern "C" */
850
851 void IOPlatformExpert::registerNVRAMController(IONVRAMController * caller)
852 {
853 publishResource("IONVRAM");
854 }
855
856 IOReturn IOPlatformExpert::callPlatformFunction(const OSSymbol *functionName,
857 bool waitForFunction,
858 void *param1, void *param2,
859 void *param3, void *param4)
860 {
861 IOService *service, *_resources;
862
863 if (waitForFunction) {
864 _resources = waitForService(resourceMatching(functionName));
865 } else {
866 _resources = resources();
867 }
868 if (_resources == 0) return kIOReturnUnsupported;
869
870 service = OSDynamicCast(IOService, _resources->getProperty(functionName));
871 if (service == 0) return kIOReturnUnsupported;
872
873 return service->callPlatformFunction(functionName, waitForFunction,
874 param1, param2, param3, param4);
875 }
876
877 IOByteCount IOPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length)
878 {
879 return 0;
880 }
881
882 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
883
884 #undef super
885 #define super IOPlatformExpert
886
887 OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert, IOPlatformExpert )
888
889 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 0);
890 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 1);
891 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 2);
892 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 3);
893 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 4);
894 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 5);
895 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 6);
896 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 7);
897
898 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
899
900 IOService * IODTPlatformExpert::probe( IOService * provider,
901 SInt32 * score )
902 {
903 if( !super::probe( provider, score))
904 return( 0 );
905
906 // check machine types
907 if( !provider->compareNames( getProperty( gIONameMatchKey ) ))
908 return( 0 );
909
910 return( this);
911 }
912
913 bool IODTPlatformExpert::configure( IOService * provider )
914 {
915 if( !super::configure( provider))
916 return( false);
917
918 processTopLevel( provider );
919
920 return( true );
921 }
922
923 IOService * IODTPlatformExpert::createNub( IORegistryEntry * from )
924 {
925 IOService * nub;
926
927 nub = new IOPlatformDevice;
928 if( nub) {
929 if( !nub->init( from, gIODTPlane )) {
930 nub->free();
931 nub = 0;
932 }
933 }
934 return( nub);
935 }
936
937 bool IODTPlatformExpert::createNubs( IOService * parent, OSIterator * iter )
938 {
939 IORegistryEntry * next;
940 IOService * nub;
941 bool ok = true;
942
943 if( iter) {
944 while( (next = (IORegistryEntry *) iter->getNextObject())) {
945
946 if( 0 == (nub = createNub( next )))
947 continue;
948
949 nub->attach( parent );
950 nub->registerService();
951 }
952 iter->release();
953 }
954
955 return( ok );
956 }
957
958 void IODTPlatformExpert::processTopLevel( IORegistryEntry * rootEntry )
959 {
960 OSIterator * kids;
961 IORegistryEntry * next;
962 IORegistryEntry * cpus;
963 IORegistryEntry * options;
964
965 // infanticide
966 kids = IODTFindMatchingEntries( rootEntry, 0, deleteList() );
967 if( kids) {
968 while( (next = (IORegistryEntry *)kids->getNextObject())) {
969 next->detachAll( gIODTPlane);
970 }
971 kids->release();
972 }
973
974 // Publish an IODTNVRAM class on /options.
975 options = rootEntry->childFromPath("options", gIODTPlane);
976 if (options) {
977 dtNVRAM = new IODTNVRAM;
978 if (dtNVRAM) {
979 if (!dtNVRAM->init(options, gIODTPlane)) {
980 dtNVRAM->release();
981 dtNVRAM = 0;
982 } else {
983 dtNVRAM->attach(this);
984 dtNVRAM->registerService();
985 }
986 }
987 }
988
989 // Publish the cpus.
990 cpus = rootEntry->childFromPath( "cpus", gIODTPlane);
991 if ( cpus)
992 createNubs( this, IODTFindMatchingEntries( cpus, kIODTExclusive, 0));
993
994 // publish top level, minus excludeList
995 createNubs( this, IODTFindMatchingEntries( rootEntry, kIODTExclusive, excludeList()));
996 }
997
998 IOReturn IODTPlatformExpert::getNubResources( IOService * nub )
999 {
1000 if( nub->getDeviceMemory())
1001 return( kIOReturnSuccess );
1002
1003 IODTResolveAddressing( nub, "reg", 0);
1004
1005 return( kIOReturnSuccess);
1006 }
1007
1008 bool IODTPlatformExpert::compareNubName( const IOService * nub,
1009 OSString * name, OSString ** matched ) const
1010 {
1011 return( IODTCompareNubName( nub, name, matched )
1012 || super::compareNubName( nub, name, matched) );
1013 }
1014
1015 bool IODTPlatformExpert::getModelName( char * name, int maxLength )
1016 {
1017 OSData * prop;
1018 const char * str;
1019 int len;
1020 char c;
1021 bool ok = false;
1022
1023 maxLength--;
1024
1025 prop = (OSData *) getProvider()->getProperty( gIODTCompatibleKey );
1026 if( prop ) {
1027 str = (const char *) prop->getBytesNoCopy();
1028
1029 if( 0 == strncmp( str, "AAPL,", strlen( "AAPL," ) ))
1030 str += strlen( "AAPL," );
1031
1032 len = 0;
1033 while( (c = *str++)) {
1034 if( (c == '/') || (c == ' '))
1035 c = '-';
1036
1037 name[ len++ ] = c;
1038 if( len >= maxLength)
1039 break;
1040 }
1041
1042 name[ len ] = 0;
1043 ok = true;
1044 }
1045 return( ok );
1046 }
1047
1048 bool IODTPlatformExpert::getMachineName( char * name, int maxLength )
1049 {
1050 OSData * prop;
1051 bool ok = false;
1052
1053 maxLength--;
1054 prop = (OSData *) getProvider()->getProperty( gIODTModelKey );
1055 ok = (0 != prop);
1056
1057 if( ok )
1058 strncpy( name, (const char *) prop->getBytesNoCopy(), maxLength );
1059
1060 return( ok );
1061 }
1062
1063 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1064
1065 void IODTPlatformExpert::registerNVRAMController( IONVRAMController * nvram )
1066 {
1067 if (dtNVRAM) dtNVRAM->registerNVRAMController(nvram);
1068
1069 super::registerNVRAMController(nvram);
1070 }
1071
1072 int IODTPlatformExpert::haltRestart(unsigned int type)
1073 {
1074 if (dtNVRAM) dtNVRAM->sync();
1075
1076 return super::haltRestart(type);
1077 }
1078
1079 IOReturn IODTPlatformExpert::readXPRAM(IOByteCount offset, UInt8 * buffer,
1080 IOByteCount length)
1081 {
1082 if (dtNVRAM) return dtNVRAM->readXPRAM(offset, buffer, length);
1083 else return kIOReturnNotReady;
1084 }
1085
1086 IOReturn IODTPlatformExpert::writeXPRAM(IOByteCount offset, UInt8 * buffer,
1087 IOByteCount length)
1088 {
1089 if (dtNVRAM) return dtNVRAM->writeXPRAM(offset, buffer, length);
1090 else return kIOReturnNotReady;
1091 }
1092
1093 IOReturn IODTPlatformExpert::readNVRAMProperty(
1094 IORegistryEntry * entry,
1095 const OSSymbol ** name, OSData ** value )
1096 {
1097 if (dtNVRAM) return dtNVRAM->readNVRAMProperty(entry, name, value);
1098 else return kIOReturnNotReady;
1099 }
1100
1101 IOReturn IODTPlatformExpert::writeNVRAMProperty(
1102 IORegistryEntry * entry,
1103 const OSSymbol * name, OSData * value )
1104 {
1105 if (dtNVRAM) return dtNVRAM->writeNVRAMProperty(entry, name, value);
1106 else return kIOReturnNotReady;
1107 }
1108
1109 OSDictionary *IODTPlatformExpert::getNVRAMPartitions(void)
1110 {
1111 if (dtNVRAM) return dtNVRAM->getNVRAMPartitions();
1112 else return 0;
1113 }
1114
1115 IOReturn IODTPlatformExpert::readNVRAMPartition(const OSSymbol * partitionID,
1116 IOByteCount offset, UInt8 * buffer,
1117 IOByteCount length)
1118 {
1119 if (dtNVRAM) return dtNVRAM->readNVRAMPartition(partitionID, offset,
1120 buffer, length);
1121 else return kIOReturnNotReady;
1122 }
1123
1124 IOReturn IODTPlatformExpert::writeNVRAMPartition(const OSSymbol * partitionID,
1125 IOByteCount offset, UInt8 * buffer,
1126 IOByteCount length)
1127 {
1128 if (dtNVRAM) return dtNVRAM->writeNVRAMPartition(partitionID, offset,
1129 buffer, length);
1130 else return kIOReturnNotReady;
1131 }
1132
1133 IOByteCount IODTPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length)
1134 {
1135 IOByteCount lengthSaved = 0;
1136
1137 if (dtNVRAM) lengthSaved = dtNVRAM->savePanicInfo(buffer, length);
1138
1139 if (lengthSaved == 0) lengthSaved = super::savePanicInfo(buffer, length);
1140
1141 return lengthSaved;
1142 }
1143
1144 OSString* IODTPlatformExpert::createSystemSerialNumberString(OSData* myProperty) {
1145 UInt8* serialNumber;
1146 unsigned int serialNumberSize;
1147 unsigned short pos = 0;
1148 char* temp;
1149 char SerialNo[30];
1150
1151 if (myProperty != NULL) {
1152 serialNumberSize = myProperty->getLength();
1153 serialNumber = (UInt8*)(myProperty->getBytesNoCopy());
1154 temp = (char*)serialNumber;
1155 if (serialNumberSize > 0) {
1156 // check to see if this is a CTO serial number...
1157 while (pos < serialNumberSize && temp[pos] != '-') pos++;
1158
1159 if (pos < serialNumberSize) { // there was a hyphen, so it's a CTO serial number
1160 memcpy(SerialNo, serialNumber + 12, 8);
1161 memcpy(&SerialNo[8], serialNumber, 3);
1162 SerialNo[11] = '-';
1163 memcpy(&SerialNo[12], serialNumber + 3, 8);
1164 SerialNo[20] = 0;
1165 } else { // just a normal serial number
1166 memcpy(SerialNo, serialNumber + 13, 8);
1167 memcpy(&SerialNo[8], serialNumber, 3);
1168 SerialNo[11] = 0;
1169 }
1170 return OSString::withCString(SerialNo);
1171 }
1172 }
1173 return NULL;
1174 }
1175
1176
1177 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1178
1179 #undef super
1180 #define super IOService
1181
1182 OSDefineMetaClassAndStructors(IOPlatformExpertDevice, IOService)
1183
1184 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 0);
1185 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 1);
1186 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 2);
1187 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 3);
1188
1189 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1190
1191 bool IOPlatformExpertDevice::compareName( OSString * name,
1192 OSString ** matched ) const
1193 {
1194 return( IODTCompareNubName( this, name, matched ));
1195 }
1196
1197 bool
1198 IOPlatformExpertDevice::initWithArgs(
1199 void * dtTop, void * p2, void * p3, void * p4 )
1200 {
1201 IORegistryEntry * dt = 0;
1202 void * argsData[ 4 ];
1203 bool ok;
1204
1205 // dtTop may be zero on non- device tree systems
1206 if( dtTop && (dt = IODeviceTreeAlloc( dtTop )))
1207 ok = super::init( dt, gIODTPlane );
1208 else
1209 ok = super::init();
1210
1211 if( !ok)
1212 return( false);
1213
1214 workLoop = IOWorkLoop::workLoop();
1215 if (!workLoop)
1216 return false;
1217
1218 argsData[ 0 ] = dtTop;
1219 argsData[ 1 ] = p2;
1220 argsData[ 2 ] = p3;
1221 argsData[ 3 ] = p4;
1222
1223 setProperty("IOPlatformArgs", (void *)argsData, sizeof( argsData));
1224
1225 return( true);
1226 }
1227
1228 IOWorkLoop *IOPlatformExpertDevice::getWorkLoop() const
1229 {
1230 return workLoop;
1231 }
1232
1233 void IOPlatformExpertDevice::free()
1234 {
1235 if (workLoop)
1236 workLoop->release();
1237 }
1238
1239 bool IOPlatformExpertDevice::attachToChild( IORegistryEntry * child,
1240 const IORegistryPlane * plane )
1241 {
1242 return IOService::attachToChild( child, plane );
1243 }
1244
1245 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1246
1247 #undef super
1248 #define super IOService
1249
1250 OSDefineMetaClassAndStructors(IOPlatformDevice, IOService)
1251
1252 OSMetaClassDefineReservedUnused(IOPlatformDevice, 0);
1253 OSMetaClassDefineReservedUnused(IOPlatformDevice, 1);
1254 OSMetaClassDefineReservedUnused(IOPlatformDevice, 2);
1255 OSMetaClassDefineReservedUnused(IOPlatformDevice, 3);
1256
1257 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1258
1259 bool IOPlatformDevice::compareName( OSString * name,
1260 OSString ** matched ) const
1261 {
1262 return( ((IOPlatformExpert *)getProvider())->
1263 compareNubName( this, name, matched ));
1264 }
1265
1266 IOService * IOPlatformDevice::matchLocation( IOService * /* client */ )
1267 {
1268 return( this );
1269 }
1270
1271 IOReturn IOPlatformDevice::getResources( void )
1272 {
1273 return( ((IOPlatformExpert *)getProvider())->getNubResources( this ));
1274 }
1275
1276 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1277
1278 /*********************************************************************
1279 * IOPanicPlatform class
1280 *
1281 * If no legitimate IOPlatformDevice matches, this one does and panics
1282 * the kernel with a suitable message.
1283 *********************************************************************/
1284
1285 class IOPanicPlatform : IOPlatformExpert {
1286 OSDeclareDefaultStructors(IOPanicPlatform);
1287
1288 public:
1289 bool start(IOService * provider);
1290 };
1291
1292
1293 OSDefineMetaClassAndStructors(IOPanicPlatform, IOPlatformExpert);
1294
1295
1296 bool IOPanicPlatform::start(IOService * provider) {
1297 const char * platform_name = "(unknown platform name)";
1298
1299 if (provider) platform_name = provider->getName();
1300
1301 panic("Unable to find driver for this platform: \"%s\".\n",
1302 platform_name);
1303
1304 return false;
1305 }