]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOPlatformExpert.cpp
xnu-3789.60.24.tar.gz
[apple/xnu.git] / iokit / Kernel / IOPlatformExpert.cpp
1 /*
2 * Copyright (c) 1998-2014 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <IOKit/IOCPU.h>
30 #include <IOKit/IODeviceTreeSupport.h>
31 #include <IOKit/IOKitDebug.h>
32 #include <IOKit/IOMapper.h>
33 #include <IOKit/IOMessage.h>
34 #include <IOKit/IONVRAM.h>
35 #include <IOKit/IOPlatformExpert.h>
36 #include <IOKit/IORangeAllocator.h>
37 #include <IOKit/IOWorkLoop.h>
38 #include <IOKit/pwr_mgt/RootDomain.h>
39 #include <IOKit/IOKitKeys.h>
40 #include <IOKit/IOTimeStamp.h>
41 #include <IOKit/IOUserClient.h>
42 #include <IOKit/IOKitDiagnosticsUserClient.h>
43
44 #include <IOKit/system.h>
45
46 #include <libkern/c++/OSContainers.h>
47 #include <libkern/crypto/sha1.h>
48 #include <libkern/OSAtomic.h>
49
50 extern "C" {
51 #include <machine/machine_routines.h>
52 #include <pexpert/pexpert.h>
53 #include <uuid/uuid.h>
54 }
55
56 void printDictionaryKeys (OSDictionary * inDictionary, char * inMsg);
57 static void getCStringForObject(OSObject *inObj, char *outStr, size_t outStrLen);
58
59 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
60
61 #define super IOService
62
63 OSDefineMetaClassAndStructors(IOPlatformExpert, IOService)
64
65 OSMetaClassDefineReservedUsed(IOPlatformExpert, 0);
66 OSMetaClassDefineReservedUsed(IOPlatformExpert, 1);
67 OSMetaClassDefineReservedUsed(IOPlatformExpert, 2);
68 OSMetaClassDefineReservedUsed(IOPlatformExpert, 3);
69 OSMetaClassDefineReservedUsed(IOPlatformExpert, 4);
70
71 OSMetaClassDefineReservedUnused(IOPlatformExpert, 5);
72 OSMetaClassDefineReservedUnused(IOPlatformExpert, 6);
73 OSMetaClassDefineReservedUnused(IOPlatformExpert, 7);
74 OSMetaClassDefineReservedUnused(IOPlatformExpert, 8);
75 OSMetaClassDefineReservedUnused(IOPlatformExpert, 9);
76 OSMetaClassDefineReservedUnused(IOPlatformExpert, 10);
77 OSMetaClassDefineReservedUnused(IOPlatformExpert, 11);
78
79 static IOPlatformExpert * gIOPlatform;
80 static OSDictionary * gIOInterruptControllers;
81 static IOLock * gIOInterruptControllersLock;
82 static IODTNVRAM *gIOOptionsEntry;
83
84 OSSymbol * gPlatformInterruptControllerName;
85
86 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
87
88 bool IOPlatformExpert::attach( IOService * provider )
89 {
90
91 if( !super::attach( provider ))
92 return( false);
93
94 return( true);
95 }
96
97 bool IOPlatformExpert::start( IOService * provider )
98 {
99 IORangeAllocator * physicalRanges;
100 OSData * busFrequency;
101 uint32_t debugFlags;
102
103 if (!super::start(provider))
104 return false;
105
106 // Override the mapper present flag is requested by boot arguments.
107 if (PE_parse_boot_argn("dart", &debugFlags, sizeof (debugFlags)) && (debugFlags == 0))
108 removeProperty(kIOPlatformMapperPresentKey);
109 if (PE_parse_boot_argn("-x", &debugFlags, sizeof (debugFlags)))
110 removeProperty(kIOPlatformMapperPresentKey);
111
112 // Register the presence or lack thereof a system
113 // PCI address mapper with the IOMapper class
114 IOMapper::setMapperRequired(0 != getProperty(kIOPlatformMapperPresentKey));
115
116 gIOInterruptControllers = OSDictionary::withCapacity(1);
117 gIOInterruptControllersLock = IOLockAlloc();
118
119 // Correct the bus frequency in the device tree.
120 busFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.bus_clock_rate_hz, 4);
121 provider->setProperty("clock-frequency", busFrequency);
122 busFrequency->release();
123
124 gPlatformInterruptControllerName = (OSSymbol *)OSSymbol::withCStringNoCopy("IOPlatformInterruptController");
125
126 physicalRanges = IORangeAllocator::withRange(0xffffffff, 1, 16,
127 IORangeAllocator::kLocking);
128 assert(physicalRanges);
129 setProperty("Platform Memory Ranges", physicalRanges);
130
131 setPlatform( this );
132 gIOPlatform = this;
133
134 PMInstantiatePowerDomains();
135
136 // Parse the serial-number data and publish a user-readable string
137 OSData* mydata = (OSData*) (provider->getProperty("serial-number"));
138 if (mydata != NULL) {
139 OSString *serNoString = createSystemSerialNumberString(mydata);
140 if (serNoString != NULL) {
141 provider->setProperty(kIOPlatformSerialNumberKey, serNoString);
142 serNoString->release();
143 }
144 }
145
146 return( configure(provider) );
147 }
148
149 bool IOPlatformExpert::configure( IOService * provider )
150 {
151 OSSet * topLevel;
152 OSDictionary * dict;
153 IOService * nub;
154
155 topLevel = OSDynamicCast( OSSet, getProperty("top-level"));
156
157 if( topLevel) {
158 while( (dict = OSDynamicCast( OSDictionary,
159 topLevel->getAnyObject()))) {
160 dict->retain();
161 topLevel->removeObject( dict );
162 nub = createNub( dict );
163 if( 0 == nub)
164 continue;
165 dict->release();
166 nub->attach( this );
167 nub->registerService();
168 }
169 }
170
171 return( true );
172 }
173
174 IOService * IOPlatformExpert::createNub( OSDictionary * from )
175 {
176 IOService * nub;
177
178 nub = new IOPlatformDevice;
179 if(nub) {
180 if( !nub->init( from )) {
181 nub->release();
182 nub = 0;
183 }
184 }
185 return( nub);
186 }
187
188 bool IOPlatformExpert::compareNubName( const IOService * nub,
189 OSString * name, OSString ** matched ) const
190 {
191 return( nub->IORegistryEntry::compareName( name, matched ));
192 }
193
194 IOReturn IOPlatformExpert::getNubResources( IOService * nub )
195 {
196 return( kIOReturnSuccess );
197 }
198
199 long IOPlatformExpert::getBootROMType(void)
200 {
201 return _peBootROMType;
202 }
203
204 long IOPlatformExpert::getChipSetType(void)
205 {
206 return _peChipSetType;
207 }
208
209 long IOPlatformExpert::getMachineType(void)
210 {
211 return _peMachineType;
212 }
213
214 void IOPlatformExpert::setBootROMType(long peBootROMType)
215 {
216 _peBootROMType = peBootROMType;
217 }
218
219 void IOPlatformExpert::setChipSetType(long peChipSetType)
220 {
221 _peChipSetType = peChipSetType;
222 }
223
224 void IOPlatformExpert::setMachineType(long peMachineType)
225 {
226 _peMachineType = peMachineType;
227 }
228
229 bool IOPlatformExpert::getMachineName( char * /*name*/, int /*maxLength*/)
230 {
231 return( false );
232 }
233
234 bool IOPlatformExpert::getModelName( char * /*name*/, int /*maxLength*/)
235 {
236 return( false );
237 }
238
239 OSString* IOPlatformExpert::createSystemSerialNumberString(OSData* myProperty)
240 {
241 return NULL;
242 }
243
244 IORangeAllocator * IOPlatformExpert::getPhysicalRangeAllocator(void)
245 {
246 return(OSDynamicCast(IORangeAllocator,
247 getProperty("Platform Memory Ranges")));
248 }
249
250 int (*PE_halt_restart)(unsigned int type) = 0;
251
252 int IOPlatformExpert::haltRestart(unsigned int type)
253 {
254 if (type == kPEPanicSync) return 0;
255
256 if (type == kPEHangCPU) while (true) {}
257
258 if (type == kPEUPSDelayHaltCPU) {
259 // RestartOnPowerLoss feature was turned on, proceed with shutdown.
260 type = kPEHaltCPU;
261 }
262
263 // On ARM kPEPanicRestartCPU is supported in the drivers
264 if (type == kPEPanicRestartCPU)
265 type = kPERestartCPU;
266
267 if (PE_halt_restart) return (*PE_halt_restart)(type);
268 else return -1;
269 }
270
271 void IOPlatformExpert::sleepKernel(void)
272 {
273 #if 0
274 long cnt;
275 boolean_t intState;
276
277 intState = ml_set_interrupts_enabled(false);
278
279 for (cnt = 0; cnt < 10000; cnt++) {
280 IODelay(1000);
281 }
282
283 ml_set_interrupts_enabled(intState);
284 #else
285 // PE_initialize_console(0, kPEDisableScreen);
286
287 IOCPUSleepKernel();
288
289 // PE_initialize_console(0, kPEEnableScreen);
290 #endif
291 }
292
293 long IOPlatformExpert::getGMTTimeOfDay(void)
294 {
295 return(0);
296 }
297
298 void IOPlatformExpert::setGMTTimeOfDay(long secs)
299 {
300 }
301
302
303 IOReturn IOPlatformExpert::getConsoleInfo( PE_Video * consoleInfo )
304 {
305 return( PE_current_console( consoleInfo));
306 }
307
308 IOReturn IOPlatformExpert::setConsoleInfo( PE_Video * consoleInfo,
309 unsigned int op)
310 {
311 return( PE_initialize_console( consoleInfo, op ));
312 }
313
314 IOReturn IOPlatformExpert::registerInterruptController(OSSymbol *name, IOInterruptController *interruptController)
315 {
316 IOLockLock(gIOInterruptControllersLock);
317
318 gIOInterruptControllers->setObject(name, interruptController);
319
320 IOLockWakeup(gIOInterruptControllersLock,
321 gIOInterruptControllers, /* one-thread */ false);
322
323 IOLockUnlock(gIOInterruptControllersLock);
324
325 return kIOReturnSuccess;
326 }
327
328 IOReturn IOPlatformExpert::deregisterInterruptController(OSSymbol *name)
329 {
330 IOLockLock(gIOInterruptControllersLock);
331
332 gIOInterruptControllers->removeObject(name);
333
334 IOLockUnlock(gIOInterruptControllersLock);
335
336 return kIOReturnSuccess;
337 }
338
339 IOInterruptController *IOPlatformExpert::lookUpInterruptController(OSSymbol *name)
340 {
341 OSObject *object;
342
343 IOLockLock(gIOInterruptControllersLock);
344 while (1) {
345
346 object = gIOInterruptControllers->getObject(name);
347
348 if (object != 0)
349 break;
350
351 IOLockSleep(gIOInterruptControllersLock,
352 gIOInterruptControllers, THREAD_UNINT);
353 }
354
355 IOLockUnlock(gIOInterruptControllersLock);
356 return OSDynamicCast(IOInterruptController, object);
357 }
358
359
360 void IOPlatformExpert::setCPUInterruptProperties(IOService *service)
361 {
362 IOCPUInterruptController *controller;
363
364 controller = OSDynamicCast(IOCPUInterruptController, waitForService(serviceMatching("IOCPUInterruptController")));
365 if (controller) controller->setCPUInterruptProperties(service);
366 }
367
368 bool IOPlatformExpert::atInterruptLevel(void)
369 {
370 return ml_at_interrupt_context();
371 }
372
373 bool IOPlatformExpert::platformAdjustService(IOService */*service*/)
374 {
375 return true;
376 }
377
378 void IOPlatformExpert::getUTCTimeOfDay(clock_sec_t * secs, clock_nsec_t * nsecs)
379 {
380 *secs = getGMTTimeOfDay();
381 *nsecs = 0;
382 }
383
384 void IOPlatformExpert::setUTCTimeOfDay(clock_sec_t secs, __unused clock_nsec_t nsecs)
385 {
386 setGMTTimeOfDay(secs);
387 }
388
389
390 //*********************************************************************************
391 // PMLog
392 //
393 //*********************************************************************************
394
395 void IOPlatformExpert::
396 PMLog(const char *who, unsigned long event,
397 unsigned long param1, unsigned long param2)
398 {
399 clock_sec_t nows;
400 clock_usec_t nowus;
401 clock_get_system_microtime(&nows, &nowus);
402 nowus += (nows % 1000) * 1000000;
403
404 kprintf("pm%u %p %.30s %d %lx %lx\n",
405 nowus, OBFUSCATE(current_thread()), who, // Identity
406 (int) event, (long)OBFUSCATE(param1), (long)OBFUSCATE(param2)); // Args
407 }
408
409
410 //*********************************************************************************
411 // PMInstantiatePowerDomains
412 //
413 // In this vanilla implementation, a Root Power Domain is instantiated.
414 // All other objects which register will be children of this Root.
415 // Where this is inappropriate, PMInstantiatePowerDomains is overridden
416 // in a platform-specific subclass.
417 //*********************************************************************************
418
419 void IOPlatformExpert::PMInstantiatePowerDomains ( void )
420 {
421 root = new IOPMrootDomain;
422 root->init();
423 root->attach(this);
424 root->start(this);
425 }
426
427
428 //*********************************************************************************
429 // PMRegisterDevice
430 //
431 // In this vanilla implementation, all callers are made children of the root power domain.
432 // Where this is inappropriate, PMRegisterDevice is overridden in a platform-specific subclass.
433 //*********************************************************************************
434
435 void IOPlatformExpert::PMRegisterDevice(IOService * theNub, IOService * theDevice)
436 {
437 root->addPowerChild ( theDevice );
438 }
439
440 //*********************************************************************************
441 // hasPMFeature
442 //
443 //*********************************************************************************
444
445 bool IOPlatformExpert::hasPMFeature (unsigned long featureMask)
446 {
447 return ((_pePMFeatures & featureMask) != 0);
448 }
449
450 //*********************************************************************************
451 // hasPrivPMFeature
452 //
453 //*********************************************************************************
454
455 bool IOPlatformExpert::hasPrivPMFeature (unsigned long privFeatureMask)
456 {
457 return ((_pePrivPMFeatures & privFeatureMask) != 0);
458 }
459
460 //*********************************************************************************
461 // numBatteriesSupported
462 //
463 //*********************************************************************************
464
465 int IOPlatformExpert::numBatteriesSupported (void)
466 {
467 return (_peNumBatteriesSupported);
468 }
469
470 //*********************************************************************************
471 // CheckSubTree
472 //
473 // This method is called by the instantiated sublass of the platform expert to
474 // determine how a device should be inserted into the Power Domain. The subclass
475 // provides an XML power tree description against which a device is matched based
476 // on class and provider. If a match is found this routine returns true in addition
477 // to flagging the description tree at the appropriate node that a device has been
478 // registered for the given service.
479 //*********************************************************************************
480
481 bool IOPlatformExpert::CheckSubTree (OSArray * inSubTree, IOService * theNub, IOService * theDevice, OSDictionary * theParent)
482 {
483 unsigned int i;
484 unsigned int numPowerTreeNodes;
485 OSDictionary * entry;
486 OSDictionary * matchingDictionary;
487 OSDictionary * providerDictionary;
488 OSDictionary * deviceDictionary;
489 OSDictionary * nubDictionary;
490 OSArray * children;
491 bool nodeFound = false;
492 bool continueSearch = false;
493 bool deviceMatch = false;
494 bool providerMatch = false;
495 bool multiParentMatch = false;
496
497 if ( (NULL == theDevice) || (NULL == inSubTree) )
498 return false;
499
500 numPowerTreeNodes = inSubTree->getCount ();
501
502 // iterate through the power tree to find a home for this device
503
504 for ( i = 0; i < numPowerTreeNodes; i++ ) {
505
506 entry = (OSDictionary *) inSubTree->getObject (i);
507
508 matchingDictionary = (OSDictionary *) entry->getObject ("device");
509 providerDictionary = (OSDictionary *) entry->getObject ("provider");
510
511 deviceMatch = true; // if no matching dictionary, this is not a criteria and so must match
512 if ( matchingDictionary ) {
513 deviceMatch = false;
514 if ( NULL != (deviceDictionary = theDevice->dictionaryWithProperties ())) {
515 deviceMatch = deviceDictionary->isEqualTo ( matchingDictionary, matchingDictionary );
516 deviceDictionary->release ();
517 }
518 }
519
520 providerMatch = true; // we indicate a match if there is no nub or provider
521 if ( theNub && providerDictionary ) {
522 providerMatch = false;
523 if ( NULL != (nubDictionary = theNub->dictionaryWithProperties ()) ) {
524 providerMatch = nubDictionary->isEqualTo ( providerDictionary, providerDictionary );
525 nubDictionary->release ();
526 }
527 }
528
529 multiParentMatch = true; // again we indicate a match if there is no multi-parent node
530 if (deviceMatch && providerMatch) {
531 if (NULL != multipleParentKeyValue) {
532 OSNumber * aNumber = (OSNumber *) entry->getObject ("multiple-parent");
533 multiParentMatch = (NULL != aNumber) ? multipleParentKeyValue->isEqualTo (aNumber) : false;
534 }
535 }
536
537 nodeFound = (deviceMatch && providerMatch && multiParentMatch);
538
539 // if the power tree specifies a provider dictionary but theNub is
540 // NULL then we cannot match with this entry.
541
542 if ( theNub == NULL && providerDictionary != NULL )
543 nodeFound = false;
544
545 // if this node is THE ONE...then register the device
546
547 if ( nodeFound ) {
548 if (RegisterServiceInTree (theDevice, entry, theParent, theNub) ) {
549
550 if ( kIOLogPower & gIOKitDebug)
551 IOLog ("PMRegisterDevice/CheckSubTree - service registered!\n");
552
553 numInstancesRegistered++;
554
555 // determine if we need to search for additional nodes for this item
556 multipleParentKeyValue = (OSNumber *) entry->getObject ("multiple-parent");
557 }
558 else
559 nodeFound = false;
560 }
561
562 continueSearch = ( (false == nodeFound) || (NULL != multipleParentKeyValue) );
563
564 if ( continueSearch && (NULL != (children = (OSArray *) entry->getObject ("children"))) ) {
565 nodeFound = CheckSubTree ( children, theNub, theDevice, entry );
566 continueSearch = ( (false == nodeFound) || (NULL != multipleParentKeyValue) );
567 }
568
569 if ( false == continueSearch )
570 break;
571 }
572
573 return ( nodeFound );
574 }
575
576 //*********************************************************************************
577 // RegisterServiceInTree
578 //
579 // Register a device at the specified node of our power tree.
580 //*********************************************************************************
581
582 bool IOPlatformExpert::RegisterServiceInTree (IOService * theService, OSDictionary * theTreeNode, OSDictionary * theTreeParentNode, IOService * theProvider)
583 {
584 IOService * aService;
585 bool registered = false;
586 OSArray * children;
587 unsigned int numChildren;
588 OSDictionary * child;
589
590 // make sure someone is not already registered here
591
592 if ( NULL == theTreeNode->getObject ("service") ) {
593
594 if ( theTreeNode->setObject ("service", OSDynamicCast ( OSObject, theService)) ) {
595
596 // 1. CHILDREN ------------------
597
598 // we registered the node in the tree...now if the node has children
599 // registered we must tell this service to add them.
600
601 if ( NULL != (children = (OSArray *) theTreeNode->getObject ("children")) ) {
602 numChildren = children->getCount ();
603 for ( unsigned int i = 0; i < numChildren; i++ ) {
604 if ( NULL != (child = (OSDictionary *) children->getObject (i)) ) {
605 if ( NULL != (aService = (IOService *) child->getObject ("service")) )
606 theService->addPowerChild (aService);
607 }
608 }
609 }
610
611 // 2. PARENT --------------------
612
613 // also we must notify the parent of this node (if a registered service
614 // exists there) of a new child.
615
616 if ( theTreeParentNode ) {
617 if ( NULL != (aService = (IOService *) theTreeParentNode->getObject ("service")) )
618 if (aService != theProvider)
619 aService->addPowerChild (theService);
620 }
621
622 registered = true;
623 }
624 }
625
626 return registered;
627 }
628
629 //*********************************************************************************
630 // printDictionaryKeys
631 //
632 // Print the keys for the given dictionary and selected contents.
633 //*********************************************************************************
634 void printDictionaryKeys (OSDictionary * inDictionary, char * inMsg)
635 {
636 OSCollectionIterator * mcoll = OSCollectionIterator::withCollection (inDictionary);
637 OSSymbol * mkey;
638 OSString * ioClass;
639 unsigned int i = 0;
640
641 mcoll->reset ();
642
643 mkey = OSDynamicCast (OSSymbol, mcoll->getNextObject ());
644
645 while (mkey) {
646
647 // kprintf ("dictionary key #%d: %s\n", i, mkey->getCStringNoCopy () );
648
649 // if this is the IOClass key, print it's contents
650
651 if ( mkey->isEqualTo ("IOClass") ) {
652 ioClass = (OSString *) inDictionary->getObject ("IOClass");
653 if ( ioClass ) IOLog ("%s IOClass is %s\n", inMsg, ioClass->getCStringNoCopy () );
654 }
655
656 // if this is an IOProviderClass key print it
657
658 if ( mkey->isEqualTo ("IOProviderClass") ) {
659 ioClass = (OSString *) inDictionary->getObject ("IOProviderClass");
660 if ( ioClass ) IOLog ("%s IOProviderClass is %s\n", inMsg, ioClass->getCStringNoCopy () );
661
662 }
663
664 // also print IONameMatch keys
665 if ( mkey->isEqualTo ("IONameMatch") ) {
666 ioClass = (OSString *) inDictionary->getObject ("IONameMatch");
667 if ( ioClass ) IOLog ("%s IONameMatch is %s\n", inMsg, ioClass->getCStringNoCopy () );
668 }
669
670 // also print IONameMatched keys
671
672 if ( mkey->isEqualTo ("IONameMatched") ) {
673 ioClass = (OSString *) inDictionary->getObject ("IONameMatched");
674 if ( ioClass ) IOLog ("%s IONameMatched is %s\n", inMsg, ioClass->getCStringNoCopy () );
675 }
676
677 #if 0
678 // print clock-id
679
680 if ( mkey->isEqualTo ("AAPL,clock-id") ) {
681 char * cstr;
682 cstr = getCStringForObject (inDictionary->getObject ("AAPL,clock-id"));
683 if (cstr)
684 kprintf (" ===> AAPL,clock-id is %s\n", cstr );
685 }
686 #endif
687
688 // print name
689
690 if ( mkey->isEqualTo ("name") ) {
691 char nameStr[64];
692 nameStr[0] = 0;
693 getCStringForObject(inDictionary->getObject("name"), nameStr,
694 sizeof(nameStr));
695 if (strlen(nameStr) > 0)
696 IOLog ("%s name is %s\n", inMsg, nameStr);
697 }
698
699 mkey = (OSSymbol *) mcoll->getNextObject ();
700
701 i++;
702 }
703
704 mcoll->release ();
705 }
706
707 static void
708 getCStringForObject(OSObject *inObj, char *outStr, size_t outStrLen)
709 {
710 char * buffer;
711 unsigned int len, i;
712
713 if ( (NULL == inObj) || (NULL == outStr))
714 return;
715
716 char * objString = (char *) (inObj->getMetaClass())->getClassName();
717
718 if ((0 == strncmp(objString, "OSString", sizeof("OSString"))) ||
719 (0 == strncmp(objString, "OSSymbol", sizeof("OSSymbol"))))
720 strlcpy(outStr, ((OSString *)inObj)->getCStringNoCopy(), outStrLen);
721
722 else if (0 == strncmp(objString, "OSData", sizeof("OSData"))) {
723 len = ((OSData *)inObj)->getLength();
724 buffer = (char *)((OSData *)inObj)->getBytesNoCopy();
725 if (buffer && (len > 0)) {
726 for (i=0; i < len; i++) {
727 outStr[i] = buffer[i];
728 }
729 outStr[len] = 0;
730 }
731 }
732 }
733
734 /* IOShutdownNotificationsTimedOut
735 * - Called from a timer installed by PEHaltRestart
736 */
737 static void IOShutdownNotificationsTimedOut(
738 thread_call_param_t p0,
739 thread_call_param_t p1)
740 {
741 int type = (int)(long)p0;
742
743 /* 30 seconds has elapsed - resume shutdown */
744 if(gIOPlatform) gIOPlatform->haltRestart(type);
745 }
746
747
748 extern "C" {
749
750 /*
751 * Callouts from BSD for machine name & model
752 */
753
754 boolean_t PEGetMachineName( char * name, int maxLength )
755 {
756 if( gIOPlatform)
757 return( gIOPlatform->getMachineName( name, maxLength ));
758 else
759 return( false );
760 }
761
762 boolean_t PEGetModelName( char * name, int maxLength )
763 {
764 if( gIOPlatform)
765 return( gIOPlatform->getModelName( name, maxLength ));
766 else
767 return( false );
768 }
769
770 int PEGetPlatformEpoch(void)
771 {
772 if( gIOPlatform)
773 return( gIOPlatform->getBootROMType());
774 else
775 return( -1 );
776 }
777
778 int PEHaltRestart(unsigned int type)
779 {
780 IOPMrootDomain *pmRootDomain;
781 AbsoluteTime deadline;
782 thread_call_t shutdown_hang;
783 IORegistryEntry *node;
784 OSData *data;
785 uint32_t timeout = 30;
786
787 if(type == kPEHaltCPU || type == kPERestartCPU || type == kPEUPSDelayHaltCPU)
788 {
789 pmRootDomain = IOService::getPMRootDomain();
790 /* Notify IOKit PM clients of shutdown/restart
791 Clients subscribe to this message with a call to
792 IOService::registerInterest()
793 */
794
795 /* Spawn a thread that will panic in 30 seconds.
796 If all goes well the machine will be off by the time
797 the timer expires. If the device wants a different
798 timeout, use that value instead of 30 seconds.
799 */
800 #define RESTART_NODE_PATH "/chosen"
801 node = IORegistryEntry::fromPath( RESTART_NODE_PATH, gIODTPlane );
802 if ( node ) {
803 data = OSDynamicCast( OSData, node->getProperty( "halt-restart-timeout" ) );
804 if ( data && data->getLength() == 4 )
805 timeout = *((uint32_t *) data->getBytesNoCopy());
806 }
807
808 shutdown_hang = thread_call_allocate( &IOShutdownNotificationsTimedOut,
809 (thread_call_param_t)(uintptr_t) type);
810 clock_interval_to_deadline( timeout, kSecondScale, &deadline );
811 thread_call_enter1_delayed( shutdown_hang, 0, deadline );
812
813 pmRootDomain->handlePlatformHaltRestart(type);
814 /* This notification should have few clients who all do
815 their work synchronously.
816
817 In this "shutdown notification" context we don't give
818 drivers the option of working asynchronously and responding
819 later. PM internals make it very hard to wait for asynchronous
820 replies.
821 */
822 }
823 else if(type == kPEPanicRestartCPU || type == kPEPanicSync)
824 {
825 // Do an initial sync to flush as much panic data as possible,
826 // in case we have a problem in one of the platorm panic handlers.
827 // After running the platform handlers, do a final sync w/
828 // platform hardware quiesced for the panic.
829 PE_sync_panic_buffers();
830 IOCPURunPlatformPanicActions(type);
831 PE_sync_panic_buffers();
832 }
833
834 if (gIOPlatform) return gIOPlatform->haltRestart(type);
835 else return -1;
836 }
837
838 UInt32 PESavePanicInfo(UInt8 *buffer, UInt32 length)
839 {
840 if (gIOPlatform != 0) return gIOPlatform->savePanicInfo(buffer, length);
841 else return 0;
842 }
843
844
845
846 inline static int init_gIOOptionsEntry(void)
847 {
848 IORegistryEntry *entry;
849 void *nvram_entry;
850 volatile void **options;
851 int ret = -1;
852
853 if (gIOOptionsEntry)
854 return 0;
855
856 entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
857 if (!entry)
858 return -1;
859
860 nvram_entry = (void *) OSDynamicCast(IODTNVRAM, entry);
861 if (!nvram_entry)
862 goto release;
863
864 options = (volatile void **) &gIOOptionsEntry;
865 if (!OSCompareAndSwapPtr(NULL, nvram_entry, options)) {
866 ret = 0;
867 goto release;
868 }
869
870 return 0;
871
872 release:
873 entry->release();
874 return ret;
875
876 }
877
878 /* pass in a NULL value if you just want to figure out the len */
879 boolean_t PEReadNVRAMProperty(const char *symbol, void *value,
880 unsigned int *len)
881 {
882 OSObject *obj;
883 OSData *data;
884 unsigned int vlen;
885
886 if (!symbol || !len)
887 goto err;
888
889 if (init_gIOOptionsEntry() < 0)
890 goto err;
891
892 vlen = *len;
893 *len = 0;
894
895 obj = gIOOptionsEntry->getProperty(symbol);
896 if (!obj)
897 goto err;
898
899 /* convert to data */
900 data = OSDynamicCast(OSData, obj);
901 if (!data)
902 goto err;
903
904 *len = data->getLength();
905 vlen = min(vlen, *len);
906 if (value && vlen)
907 memcpy((void *) value, data->getBytesNoCopy(), vlen);
908
909 return TRUE;
910
911 err:
912 return FALSE;
913 }
914
915 boolean_t
916 PEWriteNVRAMBooleanProperty(const char *symbol, boolean_t value)
917 {
918 const OSSymbol *sym = NULL;
919 OSBoolean *data = NULL;
920 bool ret = false;
921
922 if (symbol == NULL) {
923 goto exit;
924 }
925
926 if (init_gIOOptionsEntry() < 0) {
927 goto exit;
928 }
929
930 if ((sym = OSSymbol::withCStringNoCopy(symbol)) == NULL) {
931 goto exit;
932 }
933
934 data = value ? kOSBooleanTrue : kOSBooleanFalse;
935 ret = gIOOptionsEntry->setProperty(sym, data);
936
937 sym->release();
938
939 /* success, force the NVRAM to flush writes */
940 if (ret == true) {
941 gIOOptionsEntry->sync();
942 }
943
944 exit:
945 return ret;
946 }
947
948 boolean_t PEWriteNVRAMProperty(const char *symbol, const void *value,
949 const unsigned int len)
950 {
951 const OSSymbol *sym;
952 OSData *data;
953 bool ret = false;
954
955 if (!symbol || !value || !len)
956 goto err;
957
958 if (init_gIOOptionsEntry() < 0)
959 goto err;
960
961 sym = OSSymbol::withCStringNoCopy(symbol);
962 if (!sym)
963 goto err;
964
965 data = OSData::withBytes((void *) value, len);
966 if (!data)
967 goto sym_done;
968
969 ret = gIOOptionsEntry->setProperty(sym, data);
970 data->release();
971
972 sym_done:
973 sym->release();
974
975 if (ret == true) {
976 gIOOptionsEntry->sync();
977 return TRUE;
978 }
979
980 err:
981 return FALSE;
982 }
983
984
985 boolean_t PERemoveNVRAMProperty(const char *symbol)
986 {
987 const OSSymbol *sym;
988
989 if (!symbol)
990 goto err;
991
992 if (init_gIOOptionsEntry() < 0)
993 goto err;
994
995 sym = OSSymbol::withCStringNoCopy(symbol);
996 if (!sym)
997 goto err;
998
999 gIOOptionsEntry->removeProperty(sym);
1000
1001 sym->release();
1002
1003 gIOOptionsEntry->sync();
1004 return TRUE;
1005
1006 err:
1007 return FALSE;
1008
1009 }
1010
1011 long PEGetGMTTimeOfDay(void)
1012 {
1013 clock_sec_t secs;
1014 clock_usec_t usecs;
1015
1016 PEGetUTCTimeOfDay(&secs, &usecs);
1017 return secs;
1018 }
1019
1020 void PESetGMTTimeOfDay(long secs)
1021 {
1022 PESetUTCTimeOfDay(secs, 0);
1023 }
1024
1025 void PEGetUTCTimeOfDay(clock_sec_t * secs, clock_usec_t * usecs)
1026 {
1027 clock_nsec_t nsecs = 0;
1028
1029 *secs = 0;
1030 if (gIOPlatform)
1031 gIOPlatform->getUTCTimeOfDay(secs, &nsecs);
1032
1033 assert(nsecs < NSEC_PER_SEC);
1034 *usecs = nsecs / NSEC_PER_USEC;
1035 }
1036
1037 void PESetUTCTimeOfDay(clock_sec_t secs, clock_usec_t usecs)
1038 {
1039 assert(usecs < USEC_PER_SEC);
1040 if (gIOPlatform)
1041 gIOPlatform->setUTCTimeOfDay(secs, usecs * NSEC_PER_USEC);
1042 }
1043
1044 } /* extern "C" */
1045
1046 void IOPlatformExpert::registerNVRAMController(IONVRAMController * caller)
1047 {
1048 OSData * data;
1049 IORegistryEntry * entry;
1050 OSString * string = 0;
1051 uuid_string_t uuid;
1052
1053 entry = IORegistryEntry::fromPath( "/efi/platform", gIODTPlane );
1054 if ( entry )
1055 {
1056 data = OSDynamicCast( OSData, entry->getProperty( "system-id" ) );
1057 if ( data && data->getLength( ) == 16 )
1058 {
1059 SHA1_CTX context;
1060 uint8_t digest[ SHA_DIGEST_LENGTH ];
1061 const uuid_t space = { 0x2A, 0x06, 0x19, 0x90, 0xD3, 0x8D, 0x44, 0x40, 0xA1, 0x39, 0xC4, 0x97, 0x70, 0x37, 0x65, 0xAC };
1062
1063 SHA1Init( &context );
1064 SHA1Update( &context, space, sizeof( space ) );
1065 SHA1Update( &context, data->getBytesNoCopy( ), data->getLength( ) );
1066 SHA1Final( digest, &context );
1067
1068 digest[ 6 ] = ( digest[ 6 ] & 0x0F ) | 0x50;
1069 digest[ 8 ] = ( digest[ 8 ] & 0x3F ) | 0x80;
1070
1071 uuid_unparse( digest, uuid );
1072 string = OSString::withCString( uuid );
1073 }
1074
1075 entry->release( );
1076 }
1077
1078 if ( string == 0 )
1079 {
1080 entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
1081 if ( entry )
1082 {
1083 data = OSDynamicCast( OSData, entry->getProperty( "platform-uuid" ) );
1084 if ( data && data->getLength( ) == sizeof( uuid_t ) )
1085 {
1086 uuid_unparse( ( uint8_t * ) data->getBytesNoCopy( ), uuid );
1087 string = OSString::withCString( uuid );
1088 }
1089
1090 entry->release( );
1091 }
1092 }
1093
1094 if ( string )
1095 {
1096 getProvider( )->setProperty( kIOPlatformUUIDKey, string );
1097 publishResource( kIOPlatformUUIDKey, string );
1098
1099 string->release( );
1100 }
1101
1102 publishResource("IONVRAM");
1103 }
1104
1105 IOReturn IOPlatformExpert::callPlatformFunction(const OSSymbol *functionName,
1106 bool waitForFunction,
1107 void *param1, void *param2,
1108 void *param3, void *param4)
1109 {
1110 IOService *service, *_resources;
1111
1112 if (waitForFunction) {
1113 _resources = waitForService(resourceMatching(functionName));
1114 } else {
1115 _resources = getResourceService();
1116 }
1117 if (_resources == 0) return kIOReturnUnsupported;
1118
1119 service = OSDynamicCast(IOService, _resources->getProperty(functionName));
1120 if (service == 0) return kIOReturnUnsupported;
1121
1122 return service->callPlatformFunction(functionName, waitForFunction,
1123 param1, param2, param3, param4);
1124 }
1125
1126 IOByteCount IOPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length)
1127 {
1128 return 0;
1129 }
1130
1131 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1132
1133 #undef super
1134 #define super IOPlatformExpert
1135
1136 OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert, IOPlatformExpert )
1137
1138 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 0);
1139 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 1);
1140 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 2);
1141 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 3);
1142 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 4);
1143 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 5);
1144 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 6);
1145 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 7);
1146
1147 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1148
1149 IOService * IODTPlatformExpert::probe( IOService * provider,
1150 SInt32 * score )
1151 {
1152 if( !super::probe( provider, score))
1153 return( 0 );
1154
1155 // check machine types
1156 if( !provider->compareNames( getProperty( gIONameMatchKey ) ))
1157 return( 0 );
1158
1159 return( this);
1160 }
1161
1162 bool IODTPlatformExpert::configure( IOService * provider )
1163 {
1164 if( !super::configure( provider))
1165 return( false);
1166
1167 processTopLevel( provider );
1168
1169 return( true );
1170 }
1171
1172 IOService * IODTPlatformExpert::createNub( IORegistryEntry * from )
1173 {
1174 IOService * nub;
1175
1176 nub = new IOPlatformDevice;
1177 if( nub) {
1178 if( !nub->init( from, gIODTPlane )) {
1179 nub->free();
1180 nub = 0;
1181 }
1182 }
1183 return( nub);
1184 }
1185
1186 bool IODTPlatformExpert::createNubs( IOService * parent, OSIterator * iter )
1187 {
1188 IORegistryEntry * next;
1189 IOService * nub;
1190 bool ok = true;
1191
1192 if( iter) {
1193 while( (next = (IORegistryEntry *) iter->getNextObject())) {
1194
1195 if( 0 == (nub = createNub( next )))
1196 continue;
1197
1198 nub->attach( parent );
1199 nub->registerService();
1200 }
1201 iter->release();
1202 }
1203
1204 return( ok );
1205 }
1206
1207 void IODTPlatformExpert::processTopLevel( IORegistryEntry * rootEntry )
1208 {
1209 OSIterator * kids;
1210 IORegistryEntry * next;
1211 IORegistryEntry * cpus;
1212 IORegistryEntry * options;
1213
1214 // infanticide
1215 kids = IODTFindMatchingEntries( rootEntry, 0, deleteList() );
1216 if( kids) {
1217 while( (next = (IORegistryEntry *)kids->getNextObject())) {
1218 next->detachAll( gIODTPlane);
1219 }
1220 kids->release();
1221 }
1222
1223 // Publish an IODTNVRAM class on /options.
1224 options = rootEntry->childFromPath("options", gIODTPlane);
1225 if (options) {
1226 dtNVRAM = new IODTNVRAM;
1227 if (dtNVRAM) {
1228 if (!dtNVRAM->init(options, gIODTPlane)) {
1229 dtNVRAM->release();
1230 dtNVRAM = 0;
1231 } else {
1232 dtNVRAM->attach(this);
1233 dtNVRAM->registerService();
1234 options->release();
1235 }
1236 }
1237 }
1238
1239 // Publish the cpus.
1240 cpus = rootEntry->childFromPath( "cpus", gIODTPlane);
1241 if ( cpus)
1242 {
1243 createNubs( this, IODTFindMatchingEntries( cpus, kIODTExclusive, 0));
1244 cpus->release();
1245 }
1246
1247 // publish top level, minus excludeList
1248 createNubs( this, IODTFindMatchingEntries( rootEntry, kIODTExclusive, excludeList()));
1249 }
1250
1251 IOReturn IODTPlatformExpert::getNubResources( IOService * nub )
1252 {
1253 if( nub->getDeviceMemory())
1254 return( kIOReturnSuccess );
1255
1256 IODTResolveAddressing( nub, "reg", 0);
1257
1258 return( kIOReturnSuccess);
1259 }
1260
1261 bool IODTPlatformExpert::compareNubName( const IOService * nub,
1262 OSString * name, OSString ** matched ) const
1263 {
1264 return( IODTCompareNubName( nub, name, matched )
1265 || super::compareNubName( nub, name, matched) );
1266 }
1267
1268 bool IODTPlatformExpert::getModelName( char * name, int maxLength )
1269 {
1270 OSData * prop;
1271 const char * str;
1272 int len;
1273 char c;
1274 bool ok = false;
1275
1276 maxLength--;
1277
1278 prop = (OSData *) getProvider()->getProperty( gIODTCompatibleKey );
1279 if( prop ) {
1280 str = (const char *) prop->getBytesNoCopy();
1281
1282 if( 0 == strncmp( str, "AAPL,", strlen( "AAPL," ) ))
1283 str += strlen( "AAPL," );
1284
1285 len = 0;
1286 while( (c = *str++)) {
1287 if( (c == '/') || (c == ' '))
1288 c = '-';
1289
1290 name[ len++ ] = c;
1291 if( len >= maxLength)
1292 break;
1293 }
1294
1295 name[ len ] = 0;
1296 ok = true;
1297 }
1298 return( ok );
1299 }
1300
1301 bool IODTPlatformExpert::getMachineName( char * name, int maxLength )
1302 {
1303 OSData * prop;
1304 bool ok = false;
1305
1306 maxLength--;
1307 prop = (OSData *) getProvider()->getProperty( gIODTModelKey );
1308 ok = (0 != prop);
1309
1310 if( ok )
1311 strlcpy( name, (const char *) prop->getBytesNoCopy(), maxLength );
1312
1313 return( ok );
1314 }
1315
1316 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1317
1318 void IODTPlatformExpert::registerNVRAMController( IONVRAMController * nvram )
1319 {
1320 if (dtNVRAM) dtNVRAM->registerNVRAMController(nvram);
1321
1322 super::registerNVRAMController(nvram);
1323 }
1324
1325 int IODTPlatformExpert::haltRestart(unsigned int type)
1326 {
1327 if (dtNVRAM) dtNVRAM->sync();
1328
1329 return super::haltRestart(type);
1330 }
1331
1332 IOReturn IODTPlatformExpert::readXPRAM(IOByteCount offset, UInt8 * buffer,
1333 IOByteCount length)
1334 {
1335 if (dtNVRAM) return dtNVRAM->readXPRAM(offset, buffer, length);
1336 else return kIOReturnNotReady;
1337 }
1338
1339 IOReturn IODTPlatformExpert::writeXPRAM(IOByteCount offset, UInt8 * buffer,
1340 IOByteCount length)
1341 {
1342 if (dtNVRAM) return dtNVRAM->writeXPRAM(offset, buffer, length);
1343 else return kIOReturnNotReady;
1344 }
1345
1346 IOReturn IODTPlatformExpert::readNVRAMProperty(
1347 IORegistryEntry * entry,
1348 const OSSymbol ** name, OSData ** value )
1349 {
1350 if (dtNVRAM) return dtNVRAM->readNVRAMProperty(entry, name, value);
1351 else return kIOReturnNotReady;
1352 }
1353
1354 IOReturn IODTPlatformExpert::writeNVRAMProperty(
1355 IORegistryEntry * entry,
1356 const OSSymbol * name, OSData * value )
1357 {
1358 if (dtNVRAM) return dtNVRAM->writeNVRAMProperty(entry, name, value);
1359 else return kIOReturnNotReady;
1360 }
1361
1362 OSDictionary *IODTPlatformExpert::getNVRAMPartitions(void)
1363 {
1364 if (dtNVRAM) return dtNVRAM->getNVRAMPartitions();
1365 else return 0;
1366 }
1367
1368 IOReturn IODTPlatformExpert::readNVRAMPartition(const OSSymbol * partitionID,
1369 IOByteCount offset, UInt8 * buffer,
1370 IOByteCount length)
1371 {
1372 if (dtNVRAM) return dtNVRAM->readNVRAMPartition(partitionID, offset,
1373 buffer, length);
1374 else return kIOReturnNotReady;
1375 }
1376
1377 IOReturn IODTPlatformExpert::writeNVRAMPartition(const OSSymbol * partitionID,
1378 IOByteCount offset, UInt8 * buffer,
1379 IOByteCount length)
1380 {
1381 if (dtNVRAM) return dtNVRAM->writeNVRAMPartition(partitionID, offset,
1382 buffer, length);
1383 else return kIOReturnNotReady;
1384 }
1385
1386 IOByteCount IODTPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length)
1387 {
1388 IOByteCount lengthSaved = 0;
1389
1390 if (dtNVRAM) lengthSaved = dtNVRAM->savePanicInfo(buffer, length);
1391
1392 if (lengthSaved == 0) lengthSaved = super::savePanicInfo(buffer, length);
1393
1394 return lengthSaved;
1395 }
1396
1397 OSString* IODTPlatformExpert::createSystemSerialNumberString(OSData* myProperty) {
1398 UInt8* serialNumber;
1399 unsigned int serialNumberSize;
1400 unsigned short pos = 0;
1401 char* temp;
1402 char SerialNo[30];
1403
1404 if (myProperty != NULL) {
1405 serialNumberSize = myProperty->getLength();
1406 serialNumber = (UInt8*)(myProperty->getBytesNoCopy());
1407 temp = (char*)serialNumber;
1408 if (serialNumberSize > 0) {
1409 // check to see if this is a CTO serial number...
1410 while (pos < serialNumberSize && temp[pos] != '-') pos++;
1411
1412 if (pos < serialNumberSize) { // there was a hyphen, so it's a CTO serial number
1413 memcpy(SerialNo, serialNumber + 12, 8);
1414 memcpy(&SerialNo[8], serialNumber, 3);
1415 SerialNo[11] = '-';
1416 memcpy(&SerialNo[12], serialNumber + 3, 8);
1417 SerialNo[20] = 0;
1418 } else { // just a normal serial number
1419 memcpy(SerialNo, serialNumber + 13, 8);
1420 memcpy(&SerialNo[8], serialNumber, 3);
1421 SerialNo[11] = 0;
1422 }
1423 return OSString::withCString(SerialNo);
1424 }
1425 }
1426 return NULL;
1427 }
1428
1429
1430 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1431
1432 #undef super
1433 #define super IOService
1434
1435 OSDefineMetaClassAndStructors(IOPlatformExpertDevice, IOService)
1436
1437 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 0);
1438 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 1);
1439 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 2);
1440 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 3);
1441
1442 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1443
1444 bool IOPlatformExpertDevice::compareName( OSString * name,
1445 OSString ** matched ) const
1446 {
1447 return( IODTCompareNubName( this, name, matched ));
1448 }
1449
1450 bool
1451 IOPlatformExpertDevice::initWithArgs(
1452 void * dtTop, void * p2, void * p3, void * p4 )
1453 {
1454 IORegistryEntry * dt = 0;
1455 bool ok;
1456
1457 // dtTop may be zero on non- device tree systems
1458 if( dtTop && (dt = IODeviceTreeAlloc( dtTop )))
1459 ok = super::init( dt, gIODTPlane );
1460 else
1461 ok = super::init();
1462
1463 if( !ok)
1464 return( false);
1465
1466 reserved = NULL;
1467 workLoop = IOWorkLoop::workLoop();
1468 if (!workLoop)
1469 return false;
1470
1471 return( true);
1472 }
1473
1474 IOWorkLoop *IOPlatformExpertDevice::getWorkLoop() const
1475 {
1476 return workLoop;
1477 }
1478
1479 IOReturn IOPlatformExpertDevice::setProperties( OSObject * properties )
1480 {
1481 OSDictionary * dictionary;
1482 OSObject * object;
1483 IOReturn status;
1484
1485 status = super::setProperties( properties );
1486 if ( status != kIOReturnUnsupported ) return status;
1487
1488 status = IOUserClient::clientHasPrivilege( current_task( ), kIOClientPrivilegeAdministrator );
1489 if ( status != kIOReturnSuccess ) return status;
1490
1491 dictionary = OSDynamicCast( OSDictionary, properties );
1492 if ( dictionary == 0 ) return kIOReturnBadArgument;
1493
1494 object = dictionary->getObject( kIOPlatformUUIDKey );
1495 if ( object )
1496 {
1497 IORegistryEntry * entry;
1498 OSString * string;
1499 uuid_t uuid;
1500
1501 string = ( OSString * ) getProperty( kIOPlatformUUIDKey );
1502 if ( string ) return kIOReturnNotPermitted;
1503
1504 string = OSDynamicCast( OSString, object );
1505 if ( string == 0 ) return kIOReturnBadArgument;
1506
1507 status = uuid_parse( string->getCStringNoCopy( ), uuid );
1508 if ( status != 0 ) return kIOReturnBadArgument;
1509
1510 entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
1511 if ( entry )
1512 {
1513 entry->setProperty( "platform-uuid", uuid, sizeof( uuid_t ) );
1514 entry->release( );
1515 }
1516
1517 setProperty( kIOPlatformUUIDKey, string );
1518 publishResource( kIOPlatformUUIDKey, string );
1519
1520 return kIOReturnSuccess;
1521 }
1522
1523 return kIOReturnUnsupported;
1524 }
1525
1526 IOReturn IOPlatformExpertDevice::newUserClient( task_t owningTask, void * securityID,
1527 UInt32 type, OSDictionary * properties,
1528 IOUserClient ** handler )
1529 {
1530 IOReturn err = kIOReturnSuccess;
1531 IOUserClient * newConnect = 0;
1532 IOUserClient * theConnect = 0;
1533
1534 switch (type)
1535 {
1536 case kIOKitDiagnosticsClientType:
1537 newConnect = IOKitDiagnosticsClient::withTask(owningTask);
1538 if (!newConnect) err = kIOReturnNotPermitted;
1539 break;
1540 default:
1541 err = kIOReturnBadArgument;
1542 }
1543
1544 if (newConnect)
1545 {
1546 if ((false == newConnect->attach(this))
1547 || (false == newConnect->start(this)))
1548 {
1549 newConnect->detach( this );
1550 newConnect->release();
1551 err = kIOReturnNotPermitted;
1552 }
1553 else
1554 theConnect = newConnect;
1555 }
1556
1557 *handler = theConnect;
1558 return (err);
1559 }
1560
1561 void IOPlatformExpertDevice::free()
1562 {
1563 if (workLoop)
1564 workLoop->release();
1565 }
1566
1567 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1568
1569 #undef super
1570 #define super IOService
1571
1572 OSDefineMetaClassAndStructors(IOPlatformDevice, IOService)
1573
1574 OSMetaClassDefineReservedUnused(IOPlatformDevice, 0);
1575 OSMetaClassDefineReservedUnused(IOPlatformDevice, 1);
1576 OSMetaClassDefineReservedUnused(IOPlatformDevice, 2);
1577 OSMetaClassDefineReservedUnused(IOPlatformDevice, 3);
1578
1579 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1580
1581 bool IOPlatformDevice::compareName( OSString * name,
1582 OSString ** matched ) const
1583 {
1584 return( ((IOPlatformExpert *)getProvider())->
1585 compareNubName( this, name, matched ));
1586 }
1587
1588 IOService * IOPlatformDevice::matchLocation( IOService * /* client */ )
1589 {
1590 return( this );
1591 }
1592
1593 IOReturn IOPlatformDevice::getResources( void )
1594 {
1595 return( ((IOPlatformExpert *)getProvider())->getNubResources( this ));
1596 }
1597
1598 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1599
1600 /*********************************************************************
1601 * IOPanicPlatform class
1602 *
1603 * If no legitimate IOPlatformDevice matches, this one does and panics
1604 * the kernel with a suitable message.
1605 *********************************************************************/
1606
1607 class IOPanicPlatform : IOPlatformExpert {
1608 OSDeclareDefaultStructors(IOPanicPlatform);
1609
1610 public:
1611 bool start(IOService * provider) APPLE_KEXT_OVERRIDE;
1612 };
1613
1614
1615 OSDefineMetaClassAndStructors(IOPanicPlatform, IOPlatformExpert);
1616
1617
1618 bool IOPanicPlatform::start(IOService * provider) {
1619 const char * platform_name = "(unknown platform name)";
1620
1621 if (provider) platform_name = provider->getName();
1622
1623 panic("Unable to find driver for this platform: \"%s\".\n",
1624 platform_name);
1625
1626 return false;
1627 }
1628