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