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