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