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