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