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