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