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