]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOPlatformExpert.cpp
xnu-3247.1.106.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 IOCPURunPlatformPanicActions(type);
826 }
827
828 if (gIOPlatform) return gIOPlatform->haltRestart(type);
829 else return -1;
830 }
831
832 UInt32 PESavePanicInfo(UInt8 *buffer, UInt32 length)
833 {
834 if (gIOPlatform != 0) return gIOPlatform->savePanicInfo(buffer, length);
835 else return 0;
836 }
837
838
839
840 inline static int init_gIOOptionsEntry(void)
841 {
842 IORegistryEntry *entry;
843 void *nvram_entry;
844 volatile void **options;
845 int ret = -1;
846
847 if (gIOOptionsEntry)
848 return 0;
849
850 entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
851 if (!entry)
852 return -1;
853
854 nvram_entry = (void *) OSDynamicCast(IODTNVRAM, entry);
855 if (!nvram_entry)
856 goto release;
857
858 options = (volatile void **) &gIOOptionsEntry;
859 if (!OSCompareAndSwapPtr(NULL, nvram_entry, options)) {
860 ret = 0;
861 goto release;
862 }
863
864 return 0;
865
866 release:
867 entry->release();
868 return ret;
869
870 }
871
872 /* pass in a NULL value if you just want to figure out the len */
873 boolean_t PEReadNVRAMProperty(const char *symbol, void *value,
874 unsigned int *len)
875 {
876 OSObject *obj;
877 OSData *data;
878 unsigned int vlen;
879
880 if (!symbol || !len)
881 goto err;
882
883 if (init_gIOOptionsEntry() < 0)
884 goto err;
885
886 vlen = *len;
887 *len = 0;
888
889 obj = gIOOptionsEntry->getProperty(symbol);
890 if (!obj)
891 goto err;
892
893 /* convert to data */
894 data = OSDynamicCast(OSData, obj);
895 if (!data)
896 goto err;
897
898 *len = data->getLength();
899 vlen = min(vlen, *len);
900 if (value && vlen)
901 memcpy((void *) value, data->getBytesNoCopy(), vlen);
902
903 return TRUE;
904
905 err:
906 return FALSE;
907 }
908
909 boolean_t
910 PEWriteNVRAMBooleanProperty(const char *symbol, boolean_t value)
911 {
912 const OSSymbol *sym = NULL;
913 OSBoolean *data = NULL;
914 bool ret = false;
915
916 if (symbol == NULL) {
917 goto exit;
918 }
919
920 if (init_gIOOptionsEntry() < 0) {
921 goto exit;
922 }
923
924 if ((sym = OSSymbol::withCStringNoCopy(symbol)) == NULL) {
925 goto exit;
926 }
927
928 data = value ? kOSBooleanTrue : kOSBooleanFalse;
929 ret = gIOOptionsEntry->setProperty(sym, data);
930
931 sym->release();
932
933 /* success, force the NVRAM to flush writes */
934 if (ret == true) {
935 gIOOptionsEntry->sync();
936 }
937
938 exit:
939 return ret;
940 }
941
942 boolean_t PEWriteNVRAMProperty(const char *symbol, const void *value,
943 const unsigned int len)
944 {
945 const OSSymbol *sym;
946 OSData *data;
947 bool ret = false;
948
949 if (!symbol || !value || !len)
950 goto err;
951
952 if (init_gIOOptionsEntry() < 0)
953 goto err;
954
955 sym = OSSymbol::withCStringNoCopy(symbol);
956 if (!sym)
957 goto err;
958
959 data = OSData::withBytes((void *) value, len);
960 if (!data)
961 goto sym_done;
962
963 ret = gIOOptionsEntry->setProperty(sym, data);
964 data->release();
965
966 sym_done:
967 sym->release();
968
969 if (ret == true) {
970 gIOOptionsEntry->sync();
971 return TRUE;
972 }
973
974 err:
975 return FALSE;
976 }
977
978
979 boolean_t PERemoveNVRAMProperty(const char *symbol)
980 {
981 const OSSymbol *sym;
982
983 if (!symbol)
984 goto err;
985
986 if (init_gIOOptionsEntry() < 0)
987 goto err;
988
989 sym = OSSymbol::withCStringNoCopy(symbol);
990 if (!sym)
991 goto err;
992
993 gIOOptionsEntry->removeProperty(sym);
994
995 sym->release();
996
997 gIOOptionsEntry->sync();
998 return TRUE;
999
1000 err:
1001 return FALSE;
1002
1003 }
1004
1005 long PEGetGMTTimeOfDay(void)
1006 {
1007 clock_sec_t secs;
1008 clock_usec_t usecs;
1009
1010 PEGetUTCTimeOfDay(&secs, &usecs);
1011 return secs;
1012 }
1013
1014 void PESetGMTTimeOfDay(long secs)
1015 {
1016 PESetUTCTimeOfDay(secs, 0);
1017 }
1018
1019 void PEGetUTCTimeOfDay(clock_sec_t * secs, clock_usec_t * usecs)
1020 {
1021 clock_nsec_t nsecs = 0;
1022
1023 *secs = 0;
1024 if (gIOPlatform)
1025 gIOPlatform->getUTCTimeOfDay(secs, &nsecs);
1026
1027 assert(nsecs < NSEC_PER_SEC);
1028 *usecs = nsecs / NSEC_PER_USEC;
1029 }
1030
1031 void PESetUTCTimeOfDay(clock_sec_t secs, clock_usec_t usecs)
1032 {
1033 assert(usecs < USEC_PER_SEC);
1034 if (gIOPlatform)
1035 gIOPlatform->setUTCTimeOfDay(secs, usecs * NSEC_PER_USEC);
1036 }
1037
1038 } /* extern "C" */
1039
1040 void IOPlatformExpert::registerNVRAMController(IONVRAMController * caller)
1041 {
1042 OSData * data;
1043 IORegistryEntry * entry;
1044 OSString * string = 0;
1045 uuid_string_t uuid;
1046
1047 entry = IORegistryEntry::fromPath( "/efi/platform", gIODTPlane );
1048 if ( entry )
1049 {
1050 data = OSDynamicCast( OSData, entry->getProperty( "system-id" ) );
1051 if ( data && data->getLength( ) == 16 )
1052 {
1053 SHA1_CTX context;
1054 uint8_t digest[ SHA_DIGEST_LENGTH ];
1055 const uuid_t space = { 0x2A, 0x06, 0x19, 0x90, 0xD3, 0x8D, 0x44, 0x40, 0xA1, 0x39, 0xC4, 0x97, 0x70, 0x37, 0x65, 0xAC };
1056
1057 SHA1Init( &context );
1058 SHA1Update( &context, space, sizeof( space ) );
1059 SHA1Update( &context, data->getBytesNoCopy( ), data->getLength( ) );
1060 SHA1Final( digest, &context );
1061
1062 digest[ 6 ] = ( digest[ 6 ] & 0x0F ) | 0x50;
1063 digest[ 8 ] = ( digest[ 8 ] & 0x3F ) | 0x80;
1064
1065 uuid_unparse( digest, uuid );
1066 string = OSString::withCString( uuid );
1067 }
1068
1069 entry->release( );
1070 }
1071
1072 if ( string == 0 )
1073 {
1074 entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
1075 if ( entry )
1076 {
1077 data = OSDynamicCast( OSData, entry->getProperty( "platform-uuid" ) );
1078 if ( data && data->getLength( ) == sizeof( uuid_t ) )
1079 {
1080 uuid_unparse( ( uint8_t * ) data->getBytesNoCopy( ), uuid );
1081 string = OSString::withCString( uuid );
1082 }
1083
1084 entry->release( );
1085 }
1086 }
1087
1088 if ( string )
1089 {
1090 getProvider( )->setProperty( kIOPlatformUUIDKey, string );
1091 publishResource( kIOPlatformUUIDKey, string );
1092
1093 string->release( );
1094 }
1095
1096 publishResource("IONVRAM");
1097 }
1098
1099 IOReturn IOPlatformExpert::callPlatformFunction(const OSSymbol *functionName,
1100 bool waitForFunction,
1101 void *param1, void *param2,
1102 void *param3, void *param4)
1103 {
1104 IOService *service, *_resources;
1105
1106 if (waitForFunction) {
1107 _resources = waitForService(resourceMatching(functionName));
1108 } else {
1109 _resources = getResourceService();
1110 }
1111 if (_resources == 0) return kIOReturnUnsupported;
1112
1113 service = OSDynamicCast(IOService, _resources->getProperty(functionName));
1114 if (service == 0) return kIOReturnUnsupported;
1115
1116 return service->callPlatformFunction(functionName, waitForFunction,
1117 param1, param2, param3, param4);
1118 }
1119
1120 IOByteCount IOPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length)
1121 {
1122 return 0;
1123 }
1124
1125 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1126
1127 #undef super
1128 #define super IOPlatformExpert
1129
1130 OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert, IOPlatformExpert )
1131
1132 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 0);
1133 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 1);
1134 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 2);
1135 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 3);
1136 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 4);
1137 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 5);
1138 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 6);
1139 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 7);
1140
1141 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1142
1143 IOService * IODTPlatformExpert::probe( IOService * provider,
1144 SInt32 * score )
1145 {
1146 if( !super::probe( provider, score))
1147 return( 0 );
1148
1149 // check machine types
1150 if( !provider->compareNames( getProperty( gIONameMatchKey ) ))
1151 return( 0 );
1152
1153 return( this);
1154 }
1155
1156 bool IODTPlatformExpert::configure( IOService * provider )
1157 {
1158 if( !super::configure( provider))
1159 return( false);
1160
1161 processTopLevel( provider );
1162
1163 return( true );
1164 }
1165
1166 IOService * IODTPlatformExpert::createNub( IORegistryEntry * from )
1167 {
1168 IOService * nub;
1169
1170 nub = new IOPlatformDevice;
1171 if( nub) {
1172 if( !nub->init( from, gIODTPlane )) {
1173 nub->free();
1174 nub = 0;
1175 }
1176 }
1177 return( nub);
1178 }
1179
1180 bool IODTPlatformExpert::createNubs( IOService * parent, OSIterator * iter )
1181 {
1182 IORegistryEntry * next;
1183 IOService * nub;
1184 bool ok = true;
1185
1186 if( iter) {
1187 while( (next = (IORegistryEntry *) iter->getNextObject())) {
1188
1189 if( 0 == (nub = createNub( next )))
1190 continue;
1191
1192 nub->attach( parent );
1193 nub->registerService();
1194 }
1195 iter->release();
1196 }
1197
1198 return( ok );
1199 }
1200
1201 void IODTPlatformExpert::processTopLevel( IORegistryEntry * rootEntry )
1202 {
1203 OSIterator * kids;
1204 IORegistryEntry * next;
1205 IORegistryEntry * cpus;
1206 IORegistryEntry * options;
1207
1208 // infanticide
1209 kids = IODTFindMatchingEntries( rootEntry, 0, deleteList() );
1210 if( kids) {
1211 while( (next = (IORegistryEntry *)kids->getNextObject())) {
1212 next->detachAll( gIODTPlane);
1213 }
1214 kids->release();
1215 }
1216
1217 // Publish an IODTNVRAM class on /options.
1218 options = rootEntry->childFromPath("options", gIODTPlane);
1219 if (options) {
1220 dtNVRAM = new IODTNVRAM;
1221 if (dtNVRAM) {
1222 if (!dtNVRAM->init(options, gIODTPlane)) {
1223 dtNVRAM->release();
1224 dtNVRAM = 0;
1225 } else {
1226 dtNVRAM->attach(this);
1227 dtNVRAM->registerService();
1228 options->release();
1229 }
1230 }
1231 }
1232
1233 // Publish the cpus.
1234 cpus = rootEntry->childFromPath( "cpus", gIODTPlane);
1235 if ( cpus)
1236 {
1237 createNubs( this, IODTFindMatchingEntries( cpus, kIODTExclusive, 0));
1238 cpus->release();
1239 }
1240
1241 // publish top level, minus excludeList
1242 createNubs( this, IODTFindMatchingEntries( rootEntry, kIODTExclusive, excludeList()));
1243 }
1244
1245 IOReturn IODTPlatformExpert::getNubResources( IOService * nub )
1246 {
1247 if( nub->getDeviceMemory())
1248 return( kIOReturnSuccess );
1249
1250 IODTResolveAddressing( nub, "reg", 0);
1251
1252 return( kIOReturnSuccess);
1253 }
1254
1255 bool IODTPlatformExpert::compareNubName( const IOService * nub,
1256 OSString * name, OSString ** matched ) const
1257 {
1258 return( IODTCompareNubName( nub, name, matched )
1259 || super::compareNubName( nub, name, matched) );
1260 }
1261
1262 bool IODTPlatformExpert::getModelName( char * name, int maxLength )
1263 {
1264 OSData * prop;
1265 const char * str;
1266 int len;
1267 char c;
1268 bool ok = false;
1269
1270 maxLength--;
1271
1272 prop = (OSData *) getProvider()->getProperty( gIODTCompatibleKey );
1273 if( prop ) {
1274 str = (const char *) prop->getBytesNoCopy();
1275
1276 if( 0 == strncmp( str, "AAPL,", strlen( "AAPL," ) ))
1277 str += strlen( "AAPL," );
1278
1279 len = 0;
1280 while( (c = *str++)) {
1281 if( (c == '/') || (c == ' '))
1282 c = '-';
1283
1284 name[ len++ ] = c;
1285 if( len >= maxLength)
1286 break;
1287 }
1288
1289 name[ len ] = 0;
1290 ok = true;
1291 }
1292 return( ok );
1293 }
1294
1295 bool IODTPlatformExpert::getMachineName( char * name, int maxLength )
1296 {
1297 OSData * prop;
1298 bool ok = false;
1299
1300 maxLength--;
1301 prop = (OSData *) getProvider()->getProperty( gIODTModelKey );
1302 ok = (0 != prop);
1303
1304 if( ok )
1305 strlcpy( name, (const char *) prop->getBytesNoCopy(), maxLength );
1306
1307 return( ok );
1308 }
1309
1310 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1311
1312 void IODTPlatformExpert::registerNVRAMController( IONVRAMController * nvram )
1313 {
1314 if (dtNVRAM) dtNVRAM->registerNVRAMController(nvram);
1315
1316 super::registerNVRAMController(nvram);
1317 }
1318
1319 int IODTPlatformExpert::haltRestart(unsigned int type)
1320 {
1321 if (dtNVRAM) dtNVRAM->sync();
1322
1323 return super::haltRestart(type);
1324 }
1325
1326 IOReturn IODTPlatformExpert::readXPRAM(IOByteCount offset, UInt8 * buffer,
1327 IOByteCount length)
1328 {
1329 if (dtNVRAM) return dtNVRAM->readXPRAM(offset, buffer, length);
1330 else return kIOReturnNotReady;
1331 }
1332
1333 IOReturn IODTPlatformExpert::writeXPRAM(IOByteCount offset, UInt8 * buffer,
1334 IOByteCount length)
1335 {
1336 if (dtNVRAM) return dtNVRAM->writeXPRAM(offset, buffer, length);
1337 else return kIOReturnNotReady;
1338 }
1339
1340 IOReturn IODTPlatformExpert::readNVRAMProperty(
1341 IORegistryEntry * entry,
1342 const OSSymbol ** name, OSData ** value )
1343 {
1344 if (dtNVRAM) return dtNVRAM->readNVRAMProperty(entry, name, value);
1345 else return kIOReturnNotReady;
1346 }
1347
1348 IOReturn IODTPlatformExpert::writeNVRAMProperty(
1349 IORegistryEntry * entry,
1350 const OSSymbol * name, OSData * value )
1351 {
1352 if (dtNVRAM) return dtNVRAM->writeNVRAMProperty(entry, name, value);
1353 else return kIOReturnNotReady;
1354 }
1355
1356 OSDictionary *IODTPlatformExpert::getNVRAMPartitions(void)
1357 {
1358 if (dtNVRAM) return dtNVRAM->getNVRAMPartitions();
1359 else return 0;
1360 }
1361
1362 IOReturn IODTPlatformExpert::readNVRAMPartition(const OSSymbol * partitionID,
1363 IOByteCount offset, UInt8 * buffer,
1364 IOByteCount length)
1365 {
1366 if (dtNVRAM) return dtNVRAM->readNVRAMPartition(partitionID, offset,
1367 buffer, length);
1368 else return kIOReturnNotReady;
1369 }
1370
1371 IOReturn IODTPlatformExpert::writeNVRAMPartition(const OSSymbol * partitionID,
1372 IOByteCount offset, UInt8 * buffer,
1373 IOByteCount length)
1374 {
1375 if (dtNVRAM) return dtNVRAM->writeNVRAMPartition(partitionID, offset,
1376 buffer, length);
1377 else return kIOReturnNotReady;
1378 }
1379
1380 IOByteCount IODTPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length)
1381 {
1382 IOByteCount lengthSaved = 0;
1383
1384 if (dtNVRAM) lengthSaved = dtNVRAM->savePanicInfo(buffer, length);
1385
1386 if (lengthSaved == 0) lengthSaved = super::savePanicInfo(buffer, length);
1387
1388 return lengthSaved;
1389 }
1390
1391 OSString* IODTPlatformExpert::createSystemSerialNumberString(OSData* myProperty) {
1392 UInt8* serialNumber;
1393 unsigned int serialNumberSize;
1394 unsigned short pos = 0;
1395 char* temp;
1396 char SerialNo[30];
1397
1398 if (myProperty != NULL) {
1399 serialNumberSize = myProperty->getLength();
1400 serialNumber = (UInt8*)(myProperty->getBytesNoCopy());
1401 temp = (char*)serialNumber;
1402 if (serialNumberSize > 0) {
1403 // check to see if this is a CTO serial number...
1404 while (pos < serialNumberSize && temp[pos] != '-') pos++;
1405
1406 if (pos < serialNumberSize) { // there was a hyphen, so it's a CTO serial number
1407 memcpy(SerialNo, serialNumber + 12, 8);
1408 memcpy(&SerialNo[8], serialNumber, 3);
1409 SerialNo[11] = '-';
1410 memcpy(&SerialNo[12], serialNumber + 3, 8);
1411 SerialNo[20] = 0;
1412 } else { // just a normal serial number
1413 memcpy(SerialNo, serialNumber + 13, 8);
1414 memcpy(&SerialNo[8], serialNumber, 3);
1415 SerialNo[11] = 0;
1416 }
1417 return OSString::withCString(SerialNo);
1418 }
1419 }
1420 return NULL;
1421 }
1422
1423
1424 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1425
1426 #undef super
1427 #define super IOService
1428
1429 OSDefineMetaClassAndStructors(IOPlatformExpertDevice, IOService)
1430
1431 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 0);
1432 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 1);
1433 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 2);
1434 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 3);
1435
1436 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1437
1438 bool IOPlatformExpertDevice::compareName( OSString * name,
1439 OSString ** matched ) const
1440 {
1441 return( IODTCompareNubName( this, name, matched ));
1442 }
1443
1444 bool
1445 IOPlatformExpertDevice::initWithArgs(
1446 void * dtTop, void * p2, void * p3, void * p4 )
1447 {
1448 IORegistryEntry * dt = 0;
1449 bool ok;
1450
1451 // dtTop may be zero on non- device tree systems
1452 if( dtTop && (dt = IODeviceTreeAlloc( dtTop )))
1453 ok = super::init( dt, gIODTPlane );
1454 else
1455 ok = super::init();
1456
1457 if( !ok)
1458 return( false);
1459
1460 reserved = NULL;
1461 workLoop = IOWorkLoop::workLoop();
1462 if (!workLoop)
1463 return false;
1464
1465 return( true);
1466 }
1467
1468 IOWorkLoop *IOPlatformExpertDevice::getWorkLoop() const
1469 {
1470 return workLoop;
1471 }
1472
1473 IOReturn IOPlatformExpertDevice::setProperties( OSObject * properties )
1474 {
1475 OSDictionary * dictionary;
1476 OSObject * object;
1477 IOReturn status;
1478
1479 status = super::setProperties( properties );
1480 if ( status != kIOReturnUnsupported ) return status;
1481
1482 status = IOUserClient::clientHasPrivilege( current_task( ), kIOClientPrivilegeAdministrator );
1483 if ( status != kIOReturnSuccess ) return status;
1484
1485 dictionary = OSDynamicCast( OSDictionary, properties );
1486 if ( dictionary == 0 ) return kIOReturnBadArgument;
1487
1488 object = dictionary->getObject( kIOPlatformUUIDKey );
1489 if ( object )
1490 {
1491 IORegistryEntry * entry;
1492 OSString * string;
1493 uuid_t uuid;
1494
1495 string = ( OSString * ) getProperty( kIOPlatformUUIDKey );
1496 if ( string ) return kIOReturnNotPermitted;
1497
1498 string = OSDynamicCast( OSString, object );
1499 if ( string == 0 ) return kIOReturnBadArgument;
1500
1501 status = uuid_parse( string->getCStringNoCopy( ), uuid );
1502 if ( status != 0 ) return kIOReturnBadArgument;
1503
1504 entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
1505 if ( entry )
1506 {
1507 entry->setProperty( "platform-uuid", uuid, sizeof( uuid_t ) );
1508 entry->release( );
1509 }
1510
1511 setProperty( kIOPlatformUUIDKey, string );
1512 publishResource( kIOPlatformUUIDKey, string );
1513
1514 return kIOReturnSuccess;
1515 }
1516
1517 return kIOReturnUnsupported;
1518 }
1519
1520 IOReturn IOPlatformExpertDevice::newUserClient( task_t owningTask, void * securityID,
1521 UInt32 type, OSDictionary * properties,
1522 IOUserClient ** handler )
1523 {
1524 IOReturn err = kIOReturnSuccess;
1525 IOUserClient * newConnect = 0;
1526 IOUserClient * theConnect = 0;
1527
1528 switch (type)
1529 {
1530 case kIOKitDiagnosticsClientType:
1531 newConnect = IOKitDiagnosticsClient::withTask(owningTask);
1532 if (!newConnect) err = kIOReturnNotPermitted;
1533 break;
1534 default:
1535 err = kIOReturnBadArgument;
1536 }
1537
1538 if (newConnect)
1539 {
1540 if ((false == newConnect->attach(this))
1541 || (false == newConnect->start(this)))
1542 {
1543 newConnect->detach( this );
1544 newConnect->release();
1545 }
1546 else
1547 theConnect = newConnect;
1548 }
1549
1550 *handler = theConnect;
1551 return (err);
1552 }
1553
1554 void IOPlatformExpertDevice::free()
1555 {
1556 if (workLoop)
1557 workLoop->release();
1558 }
1559
1560 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1561
1562 #undef super
1563 #define super IOService
1564
1565 OSDefineMetaClassAndStructors(IOPlatformDevice, IOService)
1566
1567 OSMetaClassDefineReservedUnused(IOPlatformDevice, 0);
1568 OSMetaClassDefineReservedUnused(IOPlatformDevice, 1);
1569 OSMetaClassDefineReservedUnused(IOPlatformDevice, 2);
1570 OSMetaClassDefineReservedUnused(IOPlatformDevice, 3);
1571
1572 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1573
1574 bool IOPlatformDevice::compareName( OSString * name,
1575 OSString ** matched ) const
1576 {
1577 return( ((IOPlatformExpert *)getProvider())->
1578 compareNubName( this, name, matched ));
1579 }
1580
1581 IOService * IOPlatformDevice::matchLocation( IOService * /* client */ )
1582 {
1583 return( this );
1584 }
1585
1586 IOReturn IOPlatformDevice::getResources( void )
1587 {
1588 return( ((IOPlatformExpert *)getProvider())->getNubResources( this ));
1589 }
1590
1591 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1592
1593 /*********************************************************************
1594 * IOPanicPlatform class
1595 *
1596 * If no legitimate IOPlatformDevice matches, this one does and panics
1597 * the kernel with a suitable message.
1598 *********************************************************************/
1599
1600 class IOPanicPlatform : IOPlatformExpert {
1601 OSDeclareDefaultStructors(IOPanicPlatform);
1602
1603 public:
1604 bool start(IOService * provider) APPLE_KEXT_OVERRIDE;
1605 };
1606
1607
1608 OSDefineMetaClassAndStructors(IOPanicPlatform, IOPlatformExpert);
1609
1610
1611 bool IOPanicPlatform::start(IOService * provider) {
1612 const char * platform_name = "(unknown platform name)";
1613
1614 if (provider) platform_name = provider->getName();
1615
1616 panic("Unable to find driver for this platform: \"%s\".\n",
1617 platform_name);
1618
1619 return false;
1620 }
1621