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