]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOPlatformExpert.cpp
849109fde4da5f0d8aa292f53e9cc43f0a4c7415
[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 * 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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /*
24 * HISTORY
25 */
26
27 #include <IOKit/IOCPU.h>
28 #include <IOKit/IODeviceTreeSupport.h>
29 #include <IOKit/IOKitDebug.h>
30 #include <IOKit/IOMapper.h>
31 #include <IOKit/IOMessage.h>
32 #include <IOKit/IONVRAM.h>
33 #include <IOKit/IOPlatformExpert.h>
34 #include <IOKit/IORangeAllocator.h>
35 #include <IOKit/IOWorkLoop.h>
36 #include <IOKit/pwr_mgt/RootDomain.h>
37 #include <IOKit/IOKitKeys.h>
38 #include <IOKit/IOTimeStamp.h>
39
40 #include <IOKit/system.h>
41
42 #include <libkern/c++/OSContainers.h>
43
44 extern "C" {
45 #include <machine/machine_routines.h>
46 #include <pexpert/pexpert.h>
47 }
48
49 void printDictionaryKeys (OSDictionary * inDictionary, char * inMsg);
50 static void getCStringForObject (OSObject * inObj, char * outStr);
51
52 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
53
54 #define super IOService
55
56 OSDefineMetaClassAndStructors(IOPlatformExpert, IOService)
57
58 OSMetaClassDefineReservedUsed(IOPlatformExpert, 0);
59
60 OSMetaClassDefineReservedUsed(IOPlatformExpert, 1);
61 OSMetaClassDefineReservedUnused(IOPlatformExpert, 2);
62 OSMetaClassDefineReservedUnused(IOPlatformExpert, 3);
63 OSMetaClassDefineReservedUnused(IOPlatformExpert, 4);
64 OSMetaClassDefineReservedUnused(IOPlatformExpert, 5);
65 OSMetaClassDefineReservedUnused(IOPlatformExpert, 6);
66 OSMetaClassDefineReservedUnused(IOPlatformExpert, 7);
67 OSMetaClassDefineReservedUnused(IOPlatformExpert, 8);
68 OSMetaClassDefineReservedUnused(IOPlatformExpert, 9);
69 OSMetaClassDefineReservedUnused(IOPlatformExpert, 10);
70 OSMetaClassDefineReservedUnused(IOPlatformExpert, 11);
71
72 static IOPlatformExpert * gIOPlatform;
73 static OSDictionary * gIOInterruptControllers;
74 static IOLock * gIOInterruptControllersLock;
75
76 OSSymbol * gPlatformInterruptControllerName;
77
78 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
79
80 bool IOPlatformExpert::attach( IOService * provider )
81 {
82
83 if( !super::attach( provider ))
84 return( false);
85
86 return( true);
87 }
88
89 bool IOPlatformExpert::start( IOService * provider )
90 {
91 IORangeAllocator * physicalRanges;
92 OSData * busFrequency;
93 uint32_t debugFlags;
94
95 if (!super::start(provider))
96 return false;
97
98 // Override the mapper present flag is requested by boot arguments.
99 if (PE_parse_boot_arg("dart", &debugFlags) && (debugFlags == 0))
100 removeProperty(kIOPlatformMapperPresentKey);
101
102 // Register the presence or lack thereof a system
103 // PCI address mapper with the IOMapper class
104 IOMapper::setMapperRequired(0 != getProperty(kIOPlatformMapperPresentKey));
105
106 gIOInterruptControllers = OSDictionary::withCapacity(1);
107 gIOInterruptControllersLock = IOLockAlloc();
108
109 // Correct the bus frequency in the device tree.
110 busFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.bus_clock_rate_hz, 4);
111 provider->setProperty("clock-frequency", busFrequency);
112 busFrequency->release();
113
114 gPlatformInterruptControllerName = (OSSymbol *)OSSymbol::withCStringNoCopy("IOPlatformInterruptController");
115
116 physicalRanges = IORangeAllocator::withRange(0xffffffff, 1, 16,
117 IORangeAllocator::kLocking);
118 assert(physicalRanges);
119 setProperty("Platform Memory Ranges", physicalRanges);
120
121 setPlatform( this );
122 gIOPlatform = this;
123
124 PMInstantiatePowerDomains();
125
126 // Parse the serial-number data and publish a user-readable string
127 OSData* mydata = (OSData*) (provider->getProperty("serial-number"));
128 if (mydata != NULL) {
129 OSString *serNoString = createSystemSerialNumberString(mydata);
130 if (serNoString != NULL) {
131 provider->setProperty(kIOPlatformSerialNumberKey, serNoString);
132 serNoString->release();
133 }
134 }
135
136 return( configure(provider) );
137 }
138
139 bool IOPlatformExpert::configure( IOService * provider )
140 {
141 OSSet * topLevel;
142 OSDictionary * dict;
143 IOService * nub;
144
145 topLevel = OSDynamicCast( OSSet, getProperty("top-level"));
146
147 if( topLevel) {
148 while( (dict = OSDynamicCast( OSDictionary,
149 topLevel->getAnyObject()))) {
150 dict->retain();
151 topLevel->removeObject( dict );
152 nub = createNub( dict );
153 if( 0 == nub)
154 continue;
155 dict->release();
156 nub->attach( this );
157 nub->registerService();
158 }
159 }
160
161 return( true );
162 }
163
164 IOService * IOPlatformExpert::createNub( OSDictionary * from )
165 {
166 IOService * nub;
167
168 nub = new IOPlatformDevice;
169 if(nub) {
170 if( !nub->init( from )) {
171 nub->release();
172 nub = 0;
173 }
174 }
175 return( nub);
176 }
177
178 bool IOPlatformExpert::compareNubName( const IOService * nub,
179 OSString * name, OSString ** matched ) const
180 {
181 return( nub->IORegistryEntry::compareName( name, matched ));
182 }
183
184 IOReturn IOPlatformExpert::getNubResources( IOService * nub )
185 {
186 return( kIOReturnSuccess );
187 }
188
189 long IOPlatformExpert::getBootROMType(void)
190 {
191 return _peBootROMType;
192 }
193
194 long IOPlatformExpert::getChipSetType(void)
195 {
196 return _peChipSetType;
197 }
198
199 long IOPlatformExpert::getMachineType(void)
200 {
201 return _peMachineType;
202 }
203
204 void IOPlatformExpert::setBootROMType(long peBootROMType)
205 {
206 _peBootROMType = peBootROMType;
207 }
208
209 void IOPlatformExpert::setChipSetType(long peChipSetType)
210 {
211 _peChipSetType = peChipSetType;
212 }
213
214 void IOPlatformExpert::setMachineType(long peMachineType)
215 {
216 _peMachineType = peMachineType;
217 }
218
219 bool IOPlatformExpert::getMachineName( char * /*name*/, int /*maxLength*/)
220 {
221 return( false );
222 }
223
224 bool IOPlatformExpert::getModelName( char * /*name*/, int /*maxLength*/)
225 {
226 return( false );
227 }
228
229 OSString* IOPlatformExpert::createSystemSerialNumberString(OSData* myProperty)
230 {
231 return NULL;
232 }
233
234 IORangeAllocator * IOPlatformExpert::getPhysicalRangeAllocator(void)
235 {
236 return(OSDynamicCast(IORangeAllocator,
237 getProperty("Platform Memory Ranges")));
238 }
239
240 int (*PE_halt_restart)(unsigned int type) = 0;
241
242 int IOPlatformExpert::haltRestart(unsigned int type)
243 {
244 IOPMrootDomain *rd = getPMRootDomain();
245 OSBoolean *b = 0;
246
247 if(rd) b = (OSBoolean *)OSDynamicCast(OSBoolean, rd->getProperty(OSString::withCString("StallSystemAtHalt")));
248
249 if (type == kPEHangCPU) while (1);
250
251 if (kOSBooleanTrue == b) {
252 // Stall shutdown for 5 minutes, and if no outside force has removed our power, continue with
253 // a reboot.
254 IOSleep(1000*60*5);
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 /* IOPMPanicOnShutdownHang
729 * - Called from a timer installed by PEHaltRestart
730 */
731 static void IOPMPanicOnShutdownHang(thread_call_param_t p0, thread_call_param_t p1)
732 {
733 int type = (int)p0;
734
735 /* 30 seconds has elapsed - resume shutdown */
736 gIOPlatform->haltRestart(type);
737 }
738
739
740 extern "C" {
741
742 /*
743 * Callouts from BSD for machine name & model
744 */
745
746 boolean_t PEGetMachineName( char * name, int maxLength )
747 {
748 if( gIOPlatform)
749 return( gIOPlatform->getMachineName( name, maxLength ));
750 else
751 return( false );
752 }
753
754 boolean_t PEGetModelName( char * name, int maxLength )
755 {
756 if( gIOPlatform)
757 return( gIOPlatform->getModelName( name, maxLength ));
758 else
759 return( false );
760 }
761
762 int PEGetPlatformEpoch(void)
763 {
764 if( gIOPlatform)
765 return( gIOPlatform->getBootROMType());
766 else
767 return( -1 );
768 }
769
770 int PEHaltRestart(unsigned int type)
771 {
772 IOPMrootDomain *pmRootDomain = IOService::getPMRootDomain();
773 bool noWaitForResponses;
774 AbsoluteTime deadline;
775 thread_call_t shutdown_hang;
776
777 if(type == kPEHaltCPU || type == kPERestartCPU)
778 {
779 /* Notify IOKit PM clients of shutdown/restart
780 Clients subscribe to this message with a call to
781 IOService::registerInterest()
782 */
783
784 /* Spawn a thread that will panic in 30 seconds.
785 If all goes well the machine will be off by the time
786 the timer expires.
787 */
788 shutdown_hang = thread_call_allocate( &IOPMPanicOnShutdownHang, (thread_call_param_t) type);
789 clock_interval_to_deadline( 30, kSecondScale, &deadline );
790 thread_call_enter1_delayed( shutdown_hang, 0, deadline );
791
792 noWaitForResponses = pmRootDomain->tellChangeDown2(type);
793 /* This notification should have few clients who all do
794 their work synchronously.
795
796 In this "shutdown notification" context we don't give
797 drivers the option of working asynchronously and responding
798 later. PM internals make it very hard to wait for asynchronous
799 replies. In fact, it's a bad idea to even be calling
800 tellChangeDown2 from here at all.
801 */
802 }
803
804 if (gIOPlatform) return gIOPlatform->haltRestart(type);
805 else return -1;
806 }
807
808 UInt32 PESavePanicInfo(UInt8 *buffer, UInt32 length)
809 {
810 if (gIOPlatform != 0) return gIOPlatform->savePanicInfo(buffer, length);
811 else return 0;
812 }
813
814 long PEGetGMTTimeOfDay(void)
815 {
816 if( gIOPlatform)
817 return( gIOPlatform->getGMTTimeOfDay());
818 else
819 return( 0 );
820 }
821
822 void PESetGMTTimeOfDay(long secs)
823 {
824 if( gIOPlatform)
825 gIOPlatform->setGMTTimeOfDay(secs);
826 }
827
828 } /* extern "C" */
829
830 void IOPlatformExpert::registerNVRAMController(IONVRAMController * caller)
831 {
832 publishResource("IONVRAM");
833 }
834
835 IOReturn IOPlatformExpert::callPlatformFunction(const OSSymbol *functionName,
836 bool waitForFunction,
837 void *param1, void *param2,
838 void *param3, void *param4)
839 {
840 IOService *service, *_resources;
841
842 if (waitForFunction) {
843 _resources = waitForService(resourceMatching(functionName));
844 } else {
845 _resources = resources();
846 }
847 if (_resources == 0) return kIOReturnUnsupported;
848
849 service = OSDynamicCast(IOService, _resources->getProperty(functionName));
850 if (service == 0) return kIOReturnUnsupported;
851
852 return service->callPlatformFunction(functionName, waitForFunction,
853 param1, param2, param3, param4);
854 }
855
856 IOByteCount IOPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length)
857 {
858 return 0;
859 }
860
861 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
862
863 #undef super
864 #define super IOPlatformExpert
865
866 OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert, IOPlatformExpert )
867
868 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 0);
869 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 1);
870 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 2);
871 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 3);
872 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 4);
873 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 5);
874 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 6);
875 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 7);
876
877 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
878
879 IOService * IODTPlatformExpert::probe( IOService * provider,
880 SInt32 * score )
881 {
882 if( !super::probe( provider, score))
883 return( 0 );
884
885 // check machine types
886 if( !provider->compareNames( getProperty( gIONameMatchKey ) ))
887 return( 0 );
888
889 return( this);
890 }
891
892 bool IODTPlatformExpert::configure( IOService * provider )
893 {
894 if( !super::configure( provider))
895 return( false);
896
897 processTopLevel( provider );
898
899 return( true );
900 }
901
902 IOService * IODTPlatformExpert::createNub( IORegistryEntry * from )
903 {
904 IOService * nub;
905
906 nub = new IOPlatformDevice;
907 if( nub) {
908 if( !nub->init( from, gIODTPlane )) {
909 nub->free();
910 nub = 0;
911 }
912 }
913 return( nub);
914 }
915
916 bool IODTPlatformExpert::createNubs( IOService * parent, OSIterator * iter )
917 {
918 IORegistryEntry * next;
919 IOService * nub;
920 bool ok = true;
921
922 if( iter) {
923 while( (next = (IORegistryEntry *) iter->getNextObject())) {
924
925 if( 0 == (nub = createNub( next )))
926 continue;
927
928 nub->attach( parent );
929 nub->registerService();
930 }
931 iter->release();
932 }
933
934 return( ok );
935 }
936
937 void IODTPlatformExpert::processTopLevel( IORegistryEntry * rootEntry )
938 {
939 OSIterator * kids;
940 IORegistryEntry * next;
941 IORegistryEntry * cpus;
942 IORegistryEntry * options;
943
944 // infanticide
945 kids = IODTFindMatchingEntries( rootEntry, 0, deleteList() );
946 if( kids) {
947 while( (next = (IORegistryEntry *)kids->getNextObject())) {
948 next->detachAll( gIODTPlane);
949 }
950 kids->release();
951 }
952
953 // Publish an IODTNVRAM class on /options.
954 options = rootEntry->childFromPath("options", gIODTPlane);
955 if (options) {
956 dtNVRAM = new IODTNVRAM;
957 if (dtNVRAM) {
958 if (!dtNVRAM->init(options, gIODTPlane)) {
959 dtNVRAM->release();
960 dtNVRAM = 0;
961 } else {
962 dtNVRAM->attach(this);
963 dtNVRAM->registerService();
964 }
965 }
966 }
967
968 // Publish the cpus.
969 cpus = rootEntry->childFromPath( "cpus", gIODTPlane);
970 if ( cpus)
971 createNubs( this, IODTFindMatchingEntries( cpus, kIODTExclusive, 0));
972
973 // publish top level, minus excludeList
974 createNubs( this, IODTFindMatchingEntries( rootEntry, kIODTExclusive, excludeList()));
975 }
976
977 IOReturn IODTPlatformExpert::getNubResources( IOService * nub )
978 {
979 if( nub->getDeviceMemory())
980 return( kIOReturnSuccess );
981
982 IODTResolveAddressing( nub, "reg", 0);
983
984 return( kIOReturnSuccess);
985 }
986
987 bool IODTPlatformExpert::compareNubName( const IOService * nub,
988 OSString * name, OSString ** matched ) const
989 {
990 return( IODTCompareNubName( nub, name, matched )
991 || super::compareNubName( nub, name, matched) );
992 }
993
994 bool IODTPlatformExpert::getModelName( char * name, int maxLength )
995 {
996 OSData * prop;
997 const char * str;
998 int len;
999 char c;
1000 bool ok = false;
1001
1002 maxLength--;
1003
1004 prop = (OSData *) getProvider()->getProperty( gIODTCompatibleKey );
1005 if( prop ) {
1006 str = (const char *) prop->getBytesNoCopy();
1007
1008 if( 0 == strncmp( str, "AAPL,", strlen( "AAPL," ) ))
1009 str += strlen( "AAPL," );
1010
1011 len = 0;
1012 while( (c = *str++)) {
1013 if( (c == '/') || (c == ' '))
1014 c = '-';
1015
1016 name[ len++ ] = c;
1017 if( len >= maxLength)
1018 break;
1019 }
1020
1021 name[ len ] = 0;
1022 ok = true;
1023 }
1024 return( ok );
1025 }
1026
1027 bool IODTPlatformExpert::getMachineName( char * name, int maxLength )
1028 {
1029 OSData * prop;
1030 bool ok = false;
1031
1032 maxLength--;
1033 prop = (OSData *) getProvider()->getProperty( gIODTModelKey );
1034 ok = (0 != prop);
1035
1036 if( ok )
1037 strncpy( name, (const char *) prop->getBytesNoCopy(), maxLength );
1038
1039 return( ok );
1040 }
1041
1042 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1043
1044 void IODTPlatformExpert::registerNVRAMController( IONVRAMController * nvram )
1045 {
1046 if (dtNVRAM) dtNVRAM->registerNVRAMController(nvram);
1047
1048 super::registerNVRAMController(nvram);
1049 }
1050
1051 int IODTPlatformExpert::haltRestart(unsigned int type)
1052 {
1053 if (dtNVRAM) dtNVRAM->sync();
1054
1055 return super::haltRestart(type);
1056 }
1057
1058 IOReturn IODTPlatformExpert::readXPRAM(IOByteCount offset, UInt8 * buffer,
1059 IOByteCount length)
1060 {
1061 if (dtNVRAM) return dtNVRAM->readXPRAM(offset, buffer, length);
1062 else return kIOReturnNotReady;
1063 }
1064
1065 IOReturn IODTPlatformExpert::writeXPRAM(IOByteCount offset, UInt8 * buffer,
1066 IOByteCount length)
1067 {
1068 if (dtNVRAM) return dtNVRAM->writeXPRAM(offset, buffer, length);
1069 else return kIOReturnNotReady;
1070 }
1071
1072 IOReturn IODTPlatformExpert::readNVRAMProperty(
1073 IORegistryEntry * entry,
1074 const OSSymbol ** name, OSData ** value )
1075 {
1076 if (dtNVRAM) return dtNVRAM->readNVRAMProperty(entry, name, value);
1077 else return kIOReturnNotReady;
1078 }
1079
1080 IOReturn IODTPlatformExpert::writeNVRAMProperty(
1081 IORegistryEntry * entry,
1082 const OSSymbol * name, OSData * value )
1083 {
1084 if (dtNVRAM) return dtNVRAM->writeNVRAMProperty(entry, name, value);
1085 else return kIOReturnNotReady;
1086 }
1087
1088 OSDictionary *IODTPlatformExpert::getNVRAMPartitions(void)
1089 {
1090 if (dtNVRAM) return dtNVRAM->getNVRAMPartitions();
1091 else return 0;
1092 }
1093
1094 IOReturn IODTPlatformExpert::readNVRAMPartition(const OSSymbol * partitionID,
1095 IOByteCount offset, UInt8 * buffer,
1096 IOByteCount length)
1097 {
1098 if (dtNVRAM) return dtNVRAM->readNVRAMPartition(partitionID, offset,
1099 buffer, length);
1100 else return kIOReturnNotReady;
1101 }
1102
1103 IOReturn IODTPlatformExpert::writeNVRAMPartition(const OSSymbol * partitionID,
1104 IOByteCount offset, UInt8 * buffer,
1105 IOByteCount length)
1106 {
1107 if (dtNVRAM) return dtNVRAM->writeNVRAMPartition(partitionID, offset,
1108 buffer, length);
1109 else return kIOReturnNotReady;
1110 }
1111
1112 IOByteCount IODTPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length)
1113 {
1114 IOByteCount lengthSaved = 0;
1115
1116 if (dtNVRAM) lengthSaved = dtNVRAM->savePanicInfo(buffer, length);
1117
1118 if (lengthSaved == 0) lengthSaved = super::savePanicInfo(buffer, length);
1119
1120 return lengthSaved;
1121 }
1122
1123 OSString* IODTPlatformExpert::createSystemSerialNumberString(OSData* myProperty) {
1124 UInt8* serialNumber;
1125 unsigned int serialNumberSize;
1126 unsigned short pos = 0;
1127 char* temp;
1128 char SerialNo[30];
1129
1130 if (myProperty != NULL) {
1131 serialNumberSize = myProperty->getLength();
1132 serialNumber = (UInt8*)(myProperty->getBytesNoCopy());
1133 temp = (char*)serialNumber;
1134 if (serialNumberSize > 0) {
1135 // check to see if this is a CTO serial number...
1136 while (pos < serialNumberSize && temp[pos] != '-') pos++;
1137
1138 if (pos < serialNumberSize) { // there was a hyphen, so it's a CTO serial number
1139 memcpy(SerialNo, serialNumber + 12, 8);
1140 memcpy(&SerialNo[8], serialNumber, 3);
1141 SerialNo[11] = '-';
1142 memcpy(&SerialNo[12], serialNumber + 3, 8);
1143 SerialNo[20] = 0;
1144 } else { // just a normal serial number
1145 memcpy(SerialNo, serialNumber + 13, 8);
1146 memcpy(&SerialNo[8], serialNumber, 3);
1147 SerialNo[11] = 0;
1148 }
1149 return OSString::withCString(SerialNo);
1150 }
1151 }
1152 return NULL;
1153 }
1154
1155
1156 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1157
1158 #undef super
1159 #define super IOService
1160
1161 OSDefineMetaClassAndStructors(IOPlatformExpertDevice, IOService)
1162
1163 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 0);
1164 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 1);
1165 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 2);
1166 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 3);
1167
1168 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1169
1170 bool IOPlatformExpertDevice::compareName( OSString * name,
1171 OSString ** matched ) const
1172 {
1173 return( IODTCompareNubName( this, name, matched ));
1174 }
1175
1176 bool
1177 IOPlatformExpertDevice::initWithArgs(
1178 void * dtTop, void * p2, void * p3, void * p4 )
1179 {
1180 IORegistryEntry * dt = 0;
1181 void * argsData[ 4 ];
1182 bool ok;
1183
1184 // dtTop may be zero on non- device tree systems
1185 if( dtTop && (dt = IODeviceTreeAlloc( dtTop )))
1186 ok = super::init( dt, gIODTPlane );
1187 else
1188 ok = super::init();
1189
1190 if( !ok)
1191 return( false);
1192
1193 workLoop = IOWorkLoop::workLoop();
1194 if (!workLoop)
1195 return false;
1196
1197 argsData[ 0 ] = dtTop;
1198 argsData[ 1 ] = p2;
1199 argsData[ 2 ] = p3;
1200 argsData[ 3 ] = p4;
1201
1202 setProperty("IOPlatformArgs", (void *)argsData, sizeof( argsData));
1203
1204 return( true);
1205 }
1206
1207 IOWorkLoop *IOPlatformExpertDevice::getWorkLoop() const
1208 {
1209 return workLoop;
1210 }
1211
1212 void IOPlatformExpertDevice::free()
1213 {
1214 if (workLoop)
1215 workLoop->release();
1216 }
1217
1218 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1219
1220 #undef super
1221 #define super IOService
1222
1223 OSDefineMetaClassAndStructors(IOPlatformDevice, IOService)
1224
1225 OSMetaClassDefineReservedUnused(IOPlatformDevice, 0);
1226 OSMetaClassDefineReservedUnused(IOPlatformDevice, 1);
1227 OSMetaClassDefineReservedUnused(IOPlatformDevice, 2);
1228 OSMetaClassDefineReservedUnused(IOPlatformDevice, 3);
1229
1230 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1231
1232 bool IOPlatformDevice::compareName( OSString * name,
1233 OSString ** matched ) const
1234 {
1235 return( ((IOPlatformExpert *)getProvider())->
1236 compareNubName( this, name, matched ));
1237 }
1238
1239 IOService * IOPlatformDevice::matchLocation( IOService * /* client */ )
1240 {
1241 return( this );
1242 }
1243
1244 IOReturn IOPlatformDevice::getResources( void )
1245 {
1246 return( ((IOPlatformExpert *)getProvider())->getNubResources( this ));
1247 }
1248
1249 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1250
1251 /*********************************************************************
1252 * IOPanicPlatform class
1253 *
1254 * If no legitimate IOPlatformDevice matches, this one does and panics
1255 * the kernel with a suitable message.
1256 *********************************************************************/
1257
1258 class IOPanicPlatform : IOPlatformExpert {
1259 OSDeclareDefaultStructors(IOPanicPlatform);
1260
1261 public:
1262 bool start(IOService * provider);
1263 };
1264
1265
1266 OSDefineMetaClassAndStructors(IOPanicPlatform, IOPlatformExpert);
1267
1268
1269 bool IOPanicPlatform::start(IOService * provider) {
1270 const char * platform_name = "(unknown platform name)";
1271
1272 if (provider) platform_name = provider->getName();
1273
1274 panic("Unable to find driver for this platform: \"%s\".\n",
1275 platform_name);
1276
1277 return false;
1278 }