1 /* 2 * Copyright (c) 1998-2022 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/IOPlatformActions.h> 31 #include <IOKit/IODeviceTreeSupport.h> 32 #include <IOKit/IOKitDebug.h> 33 #include <IOKit/IOMapper.h> 34 #include <IOKit/IOMessage.h> 35 #include <IOKit/IONVRAM.h> 36 #include <IOKit/IOPlatformExpert.h> 37 #include <IOKit/IORangeAllocator.h> 38 #include <IOKit/IOWorkLoop.h> 39 #include <IOKit/pwr_mgt/RootDomain.h> 40 #include <IOKit/IOKitKeys.h> 41 #include <IOKit/IOTimeStamp.h> 42 #include <IOKit/IOUserClient.h> 43 #include <IOKit/IOKitDiagnosticsUserClient.h> 44 #include <IOKit/IOUserServer.h> 45 46 #include "IOKitKernelInternal.h" 47 48 #include <IOKit/system.h> 49 #include <sys/csr.h> 50 51 #include <libkern/c++/OSContainers.h> 52 #include <libkern/c++/OSSharedPtr.h> 53 #include <libkern/crypto/sha1.h> 54 #include <libkern/OSAtomic.h> 55 56 #if defined(__arm64__) 57 #include <arm64/tlb.h> 58 #endif 59 60 extern "C" { 61 #include <machine/machine_routines.h> 62 #include <pexpert/pexpert.h> 63 #include <uuid/uuid.h> 64 #include <sys/sysctl.h> 65 } 66 67 #define kShutdownTimeout 30 //in secs 68 69 #if defined(XNU_TARGET_OS_OSX) 70 71 boolean_t coprocessor_cross_panic_enabled = TRUE; 72 #define APPLE_VENDOR_VARIABLE_GUID "4d1ede05-38c7-4a6a-9cc6-4bcca8b38c14" 73 #endif /* defined(XNU_TARGET_OS_OSX) */ 74 75 void printDictionaryKeys(OSDictionary * inDictionary, char * inMsg); 76 static void getCStringForObject(OSObject *inObj, char *outStr, size_t outStrLen); 77 78 /* 79 * There are drivers which take mutexes in the quiesce callout or pass 80 * the quiesce/active action to super. Even though it sometimes panics, 81 * because it doesn't *always* panic, they get away with it. 82 * We need a chicken bit to diagnose and fix them all before this 83 * can be enabled by default. 84 * 85 * <rdar://problem/33831837> tracks turning this on by default. 86 */ 87 uint32_t gEnforcePlatformActionSafety = 0; 88 89 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 90 91 #define super IOService 92 93 OSDefineMetaClassAndStructors(IOPlatformExpert, IOService) 94 95 OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 0); 96 OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 1); 97 OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 2); 98 OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 3); 99 OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 4); 100 OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 5); 101 OSMetaClassDefineReservedUsedX86(IOPlatformExpert, 6); 102 103 OSMetaClassDefineReservedUnused(IOPlatformExpert, 7); 104 OSMetaClassDefineReservedUnused(IOPlatformExpert, 8); 105 OSMetaClassDefineReservedUnused(IOPlatformExpert, 9); 106 OSMetaClassDefineReservedUnused(IOPlatformExpert, 10); 107 OSMetaClassDefineReservedUnused(IOPlatformExpert, 11); 108 109 static IOPlatformExpert * gIOPlatform; 110 static OSDictionary * gIOInterruptControllers; 111 static IOLock * gIOInterruptControllersLock; 112 static IODTNVRAM *gIOOptionsEntry; 113 114 OSSymbol * gPlatformInterruptControllerName; 115 116 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 117 118 bool 119 IOPlatformExpert::attach( IOService * provider ) 120 { 121 if (!super::attach( provider )) { 122 return false; 123 } 124 125 return true; 126 } 127 128 bool 129 IOPlatformExpert::start( IOService * provider ) 130 { 131 IORangeAllocator * physicalRanges; 132 OSData * busFrequency; 133 uint32_t debugFlags; 134 135 136 if (!super::start(provider)) { 137 return false; 138 } 139 140 // Override the mapper present flag is requested by boot arguments, if SIP disabled. 141 #if CONFIG_CSR 142 if (csr_check(CSR_ALLOW_UNRESTRICTED_FS) == 0) 143 #endif /* CONFIG_CSR */ 144 { 145 if (PE_parse_boot_argn("dart", &debugFlags, sizeof(debugFlags)) && (debugFlags == 0)) { 146 removeProperty(kIOPlatformMapperPresentKey); 147 } 148 #if DEBUG || DEVELOPMENT 149 if (PE_parse_boot_argn("-x", &debugFlags, sizeof(debugFlags))) { 150 removeProperty(kIOPlatformMapperPresentKey); 151 } 152 #endif /* DEBUG || DEVELOPMENT */ 153 } 154 155 // Register the presence or lack thereof a system 156 // PCI address mapper with the IOMapper class 157 IOMapper::setMapperRequired(NULL != getProperty(kIOPlatformMapperPresentKey)); 158 159 gIOInterruptControllers = OSDictionary::withCapacity(1); 160 gIOInterruptControllersLock = IOLockAlloc(); 161 162 // Correct the bus frequency in the device tree. 163 busFrequency = OSData::withBytesNoCopy((void *)&gPEClockFrequencyInfo.bus_clock_rate_hz, 4); 164 provider->setProperty("clock-frequency", busFrequency); 165 busFrequency->release(); 166 167 gPlatformInterruptControllerName = (OSSymbol *)OSSymbol::withCStringNoCopy("IOPlatformInterruptController"); 168 169 physicalRanges = IORangeAllocator::withRange(0xffffffff, 1, 16, 170 IORangeAllocator::kLocking); 171 assert(physicalRanges); 172 setProperty("Platform Memory Ranges", physicalRanges); 173 OSSafeReleaseNULL(physicalRanges); 174 175 setPlatform( this ); 176 gIOPlatform = this; 177 178 PMInstantiatePowerDomains(); 179 180 #if !defined(__x86_64__) 181 publishPlatformUUIDAndSerial(); 182 #endif /* !defined(__x86_64__) */ 183 184 #if defined (__x86_64__) 185 if (PEGetCoprocessorVersion() >= kCoprocessorVersion2) { 186 coprocessor_paniclog_flush = TRUE; 187 extended_debug_log_init(); 188 } 189 #endif 190 191 PE_parse_boot_argn("enforce_platform_action_safety", &gEnforcePlatformActionSafety, 192 sizeof(gEnforcePlatformActionSafety)); 193 194 return configure(provider); 195 } 196 197 bool 198 IOPlatformExpert::configure( IOService * provider ) 199 { 200 OSSet * topLevel; 201 OSDictionary * dict; 202 IOService * nub = NULL; 203 204 topLevel = OSDynamicCast( OSSet, getProperty("top-level")); 205 206 if (topLevel) { 207 while ((dict = OSDynamicCast( OSDictionary, 208 topLevel->getAnyObject()))) { 209 dict->retain(); 210 topLevel->removeObject( dict ); 211 OSSafeReleaseNULL(nub); 212 nub = createNub( dict ); 213 dict->release(); 214 if (NULL == nub) { 215 continue; 216 } 217 nub->attach( this ); 218 nub->registerService(); 219 } 220 } 221 OSSafeReleaseNULL(nub); 222 return true; 223 } 224 225 IOService * 226 IOPlatformExpert::createNub( OSDictionary * from ) 227 { 228 IOService * nub; 229 230 nub = new IOPlatformDevice; 231 if (nub) { 232 if (!nub->init( from )) { 233 nub->release(); 234 nub = NULL; 235 } 236 } 237 return nub; 238 } 239 240 bool 241 IOPlatformExpert::compareNubName( const IOService * nub, 242 OSString * name, OSString ** matched ) const 243 { 244 return nub->IORegistryEntry::compareName( name, matched ); 245 } 246 247 bool 248 IOPlatformExpert::compareNubName( const IOService * nub, 249 OSString * name, OSSharedPtr<OSString>& matched ) const 250 { 251 OSString* matchedRaw = NULL; 252 bool result = compareNubName(nub, name, &matchedRaw); 253 matched.reset(matchedRaw, OSNoRetain); 254 return result; 255 } 256 257 IOReturn 258 IOPlatformExpert::getNubResources( IOService * nub ) 259 { 260 return kIOReturnSuccess; 261 } 262 263 long 264 IOPlatformExpert::getBootROMType(void) 265 { 266 return _peBootROMType; 267 } 268 269 long 270 IOPlatformExpert::getChipSetType(void) 271 { 272 return _peChipSetType; 273 } 274 275 long 276 IOPlatformExpert::getMachineType(void) 277 { 278 return _peMachineType; 279 } 280 281 void 282 IOPlatformExpert::setBootROMType(long peBootROMType) 283 { 284 _peBootROMType = peBootROMType; 285 } 286 287 void 288 IOPlatformExpert::setChipSetType(long peChipSetType) 289 { 290 _peChipSetType = peChipSetType; 291 } 292 293 void 294 IOPlatformExpert::setMachineType(long peMachineType) 295 { 296 _peMachineType = peMachineType; 297 } 298 299 bool 300 IOPlatformExpert::getMachineName( char * /*name*/, int /*maxLength*/) 301 { 302 return false; 303 } 304 305 bool 306 IOPlatformExpert::getModelName( char * /*name*/, int /*maxLength*/) 307 { 308 return false; 309 } 310 311 bool 312 IOPlatformExpert::getTargetName( char * /*name*/, int /*maxLength*/) 313 { 314 return false; 315 } 316 317 bool 318 IOPlatformExpert::getProductName( char * /*name*/, int /*maxLength*/) 319 { 320 return false; 321 } 322 323 OSString* 324 IOPlatformExpert::createSystemSerialNumberString(OSData* myProperty) 325 { 326 return NULL; 327 } 328 329 IORangeAllocator * 330 IOPlatformExpert::getPhysicalRangeAllocator(void) 331 { 332 return OSDynamicCast(IORangeAllocator, 333 getProperty("Platform Memory Ranges")); 334 } 335 336 int (*PE_halt_restart)(unsigned int type) = NULL; 337 338 int 339 IOPlatformExpert::haltRestart(unsigned int type) 340 { 341 if (type == kPEPanicSync) { 342 return 0; 343 } 344 345 if (type == kPEHangCPU) { 346 while (true) { 347 asm volatile (""); 348 } 349 } 350 351 if (type == kPEUPSDelayHaltCPU) { 352 // RestartOnPowerLoss feature was turned on, proceed with shutdown. 353 type = kPEHaltCPU; 354 } 355 356 #if defined (__x86_64__) 357 // On ARM kPEPanicRestartCPU is supported in the drivers 358 if (type == kPEPanicRestartCPU) { 359 type = kPERestartCPU; 360 } 361 #endif 362 363 if (PE_halt_restart) { 364 return (*PE_halt_restart)(type); 365 } else { 366 return -1; 367 } 368 } 369 370 void 371 IOPlatformExpert::sleepKernel(void) 372 { 373 #if 0 374 long cnt; 375 boolean_t intState; 376 377 intState = ml_set_interrupts_enabled(false); 378 379 for (cnt = 0; cnt < 10000; cnt++) { 380 IODelay(1000); 381 } 382 383 ml_set_interrupts_enabled(intState); 384 #else 385 // PE_initialize_console(0, kPEDisableScreen); 386 387 IOCPUSleepKernel(); 388 389 // PE_initialize_console(0, kPEEnableScreen); 390 #endif 391 } 392 393 long 394 IOPlatformExpert::getGMTTimeOfDay(void) 395 { 396 return 0; 397 } 398 399 void 400 IOPlatformExpert::setGMTTimeOfDay(long secs) 401 { 402 } 403 404 405 IOReturn 406 IOPlatformExpert::getConsoleInfo( PE_Video * consoleInfo ) 407 { 408 return PE_current_console( consoleInfo); 409 } 410 411 IOReturn 412 IOPlatformExpert::setConsoleInfo( PE_Video * consoleInfo, 413 unsigned int op) 414 { 415 return PE_initialize_console( consoleInfo, op ); 416 } 417 418 IOReturn 419 IOPlatformExpert::registerInterruptController(OSSymbol *name, IOInterruptController *interruptController) 420 { 421 IOLockLock(gIOInterruptControllersLock); 422 423 gIOInterruptControllers->setObject(name, interruptController); 424 425 IOLockWakeup(gIOInterruptControllersLock, 426 gIOInterruptControllers, /* one-thread */ false); 427 428 IOLockUnlock(gIOInterruptControllersLock); 429 430 return kIOReturnSuccess; 431 } 432 433 IOReturn 434 IOPlatformExpert::deregisterInterruptController(OSSymbol *name) 435 { 436 IOLockLock(gIOInterruptControllersLock); 437 438 gIOInterruptControllers->removeObject(name); 439 440 IOLockUnlock(gIOInterruptControllersLock); 441 442 return kIOReturnSuccess; 443 } 444 445 IOInterruptController * 446 IOPlatformExpert::lookUpInterruptController(OSSymbol *name) 447 { 448 OSObject *object; 449 450 IOLockLock(gIOInterruptControllersLock); 451 while (1) { 452 object = gIOInterruptControllers->getObject(name); 453 454 if (object != NULL) { 455 break; 456 } 457 458 IOLockSleep(gIOInterruptControllersLock, 459 gIOInterruptControllers, THREAD_UNINT); 460 } 461 462 IOLockUnlock(gIOInterruptControllersLock); 463 return OSDynamicCast(IOInterruptController, object); 464 } 465 466 467 void 468 IOPlatformExpert::setCPUInterruptProperties(IOService *service) 469 { 470 IOInterruptController *controller; 471 472 OSDictionary *matching = serviceMatching("IOInterruptController"); 473 matching = propertyMatching(gPlatformInterruptControllerName, kOSBooleanTrue, matching); 474 475 controller = OSDynamicCast(IOInterruptController, waitForService(matching)); 476 if (controller) { 477 controller->setCPUInterruptProperties(service); 478 } 479 } 480 481 bool 482 IOPlatformExpert::atInterruptLevel(void) 483 { 484 return ml_at_interrupt_context(); 485 } 486 487 bool 488 IOPlatformExpert::platformAdjustService(IOService */*service*/) 489 { 490 return true; 491 } 492 493 void 494 IOPlatformExpert::getUTCTimeOfDay(clock_sec_t * secs, clock_nsec_t * nsecs) 495 { 496 *secs = getGMTTimeOfDay(); 497 *nsecs = 0; 498 } 499 500 void 501 IOPlatformExpert::setUTCTimeOfDay(clock_sec_t secs, __unused clock_nsec_t nsecs) 502 { 503 setGMTTimeOfDay(secs); 504 } 505 506 507 //********************************************************************************* 508 // PMLog 509 // 510 //********************************************************************************* 511 512 void 513 IOPlatformExpert:: 514 PMLog(const char *who, unsigned long event, 515 unsigned long param1, unsigned long param2) 516 { 517 clock_sec_t nows; 518 clock_usec_t nowus; 519 clock_get_system_microtime(&nows, &nowus); 520 nowus += (nows % 1000) * 1000000; 521 522 kprintf("pm%u %p %.30s %d %lx %lx\n", 523 nowus, OBFUSCATE(current_thread()), who, // Identity 524 (int) event, (long)OBFUSCATE(param1), (long)OBFUSCATE(param2)); // Args 525 } 526 527 528 //********************************************************************************* 529 // PMInstantiatePowerDomains 530 // 531 // In this vanilla implementation, a Root Power Domain is instantiated. 532 // All other objects which register will be children of this Root. 533 // Where this is inappropriate, PMInstantiatePowerDomains is overridden 534 // in a platform-specific subclass. 535 //********************************************************************************* 536 537 void 538 IOPlatformExpert::PMInstantiatePowerDomains( void ) 539 { 540 root = new IOPMrootDomain; 541 root->init(); 542 root->attach(this); 543 root->start(this); 544 } 545 546 547 //********************************************************************************* 548 // PMRegisterDevice 549 // 550 // In this vanilla implementation, all callers are made children of the root power domain. 551 // Where this is inappropriate, PMRegisterDevice is overridden in a platform-specific subclass. 552 //********************************************************************************* 553 554 void 555 IOPlatformExpert::PMRegisterDevice(IOService * theNub, IOService * theDevice) 556 { 557 root->addPowerChild( theDevice ); 558 } 559 560 //********************************************************************************* 561 // hasPMFeature 562 // 563 //********************************************************************************* 564 565 bool 566 IOPlatformExpert::hasPMFeature(unsigned long featureMask) 567 { 568 return (_pePMFeatures & featureMask) != 0; 569 } 570 571 //********************************************************************************* 572 // hasPrivPMFeature 573 // 574 //********************************************************************************* 575 576 bool 577 IOPlatformExpert::hasPrivPMFeature(unsigned long privFeatureMask) 578 { 579 return (_pePrivPMFeatures & privFeatureMask) != 0; 580 } 581 582 //********************************************************************************* 583 // numBatteriesSupported 584 // 585 //********************************************************************************* 586 587 int 588 IOPlatformExpert::numBatteriesSupported(void) 589 { 590 return _peNumBatteriesSupported; 591 } 592 593 //********************************************************************************* 594 // CheckSubTree 595 // 596 // This method is called by the instantiated sublass of the platform expert to 597 // determine how a device should be inserted into the Power Domain. The subclass 598 // provides an XML power tree description against which a device is matched based 599 // on class and provider. If a match is found this routine returns true in addition 600 // to flagging the description tree at the appropriate node that a device has been 601 // registered for the given service. 602 //********************************************************************************* 603 604 bool 605 IOPlatformExpert::CheckSubTree(OSArray * inSubTree, IOService * theNub, IOService * theDevice, OSDictionary * theParent) 606 { 607 unsigned int i; 608 unsigned int numPowerTreeNodes; 609 OSDictionary * entry; 610 OSDictionary * matchingDictionary; 611 OSDictionary * providerDictionary; 612 OSDictionary * deviceDictionary; 613 OSDictionary * nubDictionary; 614 OSArray * children; 615 bool nodeFound = false; 616 bool continueSearch = false; 617 bool deviceMatch = false; 618 bool providerMatch = false; 619 bool multiParentMatch = false; 620 621 if ((NULL == theDevice) || (NULL == inSubTree)) { 622 return false; 623 } 624 625 numPowerTreeNodes = inSubTree->getCount(); 626 627 // iterate through the power tree to find a home for this device 628 629 for (i = 0; i < numPowerTreeNodes; i++) { 630 entry = (OSDictionary *) inSubTree->getObject(i); 631 632 matchingDictionary = (OSDictionary *) entry->getObject("device"); 633 providerDictionary = (OSDictionary *) entry->getObject("provider"); 634 635 deviceMatch = true; // if no matching dictionary, this is not a criteria and so must match 636 if (matchingDictionary) { 637 deviceMatch = false; 638 if (NULL != (deviceDictionary = theDevice->dictionaryWithProperties())) { 639 deviceMatch = deviceDictionary->isEqualTo( matchingDictionary, matchingDictionary ); 640 deviceDictionary->release(); 641 } 642 } 643 644 providerMatch = true; // we indicate a match if there is no nub or provider 645 if (theNub && providerDictionary) { 646 providerMatch = false; 647 if (NULL != (nubDictionary = theNub->dictionaryWithProperties())) { 648 providerMatch = nubDictionary->isEqualTo( providerDictionary, providerDictionary ); 649 nubDictionary->release(); 650 } 651 } 652 653 multiParentMatch = true; // again we indicate a match if there is no multi-parent node 654 if (deviceMatch && providerMatch) { 655 if (NULL != multipleParentKeyValue) { 656 OSNumber * aNumber = (OSNumber *) entry->getObject("multiple-parent"); 657 multiParentMatch = (NULL != aNumber) ? multipleParentKeyValue->isEqualTo(aNumber) : false; 658 } 659 } 660 661 nodeFound = (deviceMatch && providerMatch && multiParentMatch); 662 663 // if the power tree specifies a provider dictionary but theNub is 664 // NULL then we cannot match with this entry. 665 666 if (theNub == NULL && providerDictionary != NULL) { 667 nodeFound = false; 668 } 669 670 // if this node is THE ONE...then register the device 671 672 if (nodeFound) { 673 if (RegisterServiceInTree(theDevice, entry, theParent, theNub)) { 674 if (kIOLogPower & gIOKitDebug) { 675 IOLog("PMRegisterDevice/CheckSubTree - service registered!\n"); 676 } 677 678 numInstancesRegistered++; 679 680 // determine if we need to search for additional nodes for this item 681 multipleParentKeyValue = (OSNumber *) entry->getObject("multiple-parent"); 682 } else { 683 nodeFound = false; 684 } 685 } 686 687 continueSearch = ((false == nodeFound) || (NULL != multipleParentKeyValue)); 688 689 if (continueSearch && (NULL != (children = (OSArray *) entry->getObject("children")))) { 690 nodeFound = CheckSubTree( children, theNub, theDevice, entry ); 691 continueSearch = ((false == nodeFound) || (NULL != multipleParentKeyValue)); 692 } 693 694 if (false == continueSearch) { 695 break; 696 } 697 } 698 699 return nodeFound; 700 } 701 702 //********************************************************************************* 703 // RegisterServiceInTree 704 // 705 // Register a device at the specified node of our power tree. 706 //********************************************************************************* 707 708 bool 709 IOPlatformExpert::RegisterServiceInTree(IOService * theService, OSDictionary * theTreeNode, OSDictionary * theTreeParentNode, IOService * theProvider) 710 { 711 IOService * aService; 712 bool registered = false; 713 OSArray * children; 714 unsigned int numChildren; 715 OSDictionary * child; 716 717 // make sure someone is not already registered here 718 719 if (NULL == theTreeNode->getObject("service")) { 720 if (theTreeNode->setObject("service", OSDynamicCast( OSObject, theService))) { 721 // 1. CHILDREN ------------------ 722 723 // we registered the node in the tree...now if the node has children 724 // registered we must tell this service to add them. 725 726 if (NULL != (children = (OSArray *) theTreeNode->getObject("children"))) { 727 numChildren = children->getCount(); 728 for (unsigned int i = 0; i < numChildren; i++) { 729 if (NULL != (child = (OSDictionary *) children->getObject(i))) { 730 if (NULL != (aService = (IOService *) child->getObject("service"))) { 731 theService->addPowerChild(aService); 732 } 733 } 734 } 735 } 736 737 // 2. PARENT -------------------- 738 739 // also we must notify the parent of this node (if a registered service 740 // exists there) of a new child. 741 742 if (theTreeParentNode) { 743 if (NULL != (aService = (IOService *) theTreeParentNode->getObject("service"))) { 744 if (aService != theProvider) { 745 aService->addPowerChild(theService); 746 } 747 } 748 } 749 750 registered = true; 751 } 752 } 753 754 return registered; 755 } 756 757 //********************************************************************************* 758 // printDictionaryKeys 759 // 760 // Print the keys for the given dictionary and selected contents. 761 //********************************************************************************* 762 void 763 printDictionaryKeys(OSDictionary * inDictionary, char * inMsg) 764 { 765 OSCollectionIterator * mcoll = OSCollectionIterator::withCollection(inDictionary); 766 OSSymbol * mkey; 767 OSString * ioClass; 768 unsigned int i = 0; 769 770 mcoll->reset(); 771 772 mkey = OSDynamicCast(OSSymbol, mcoll->getNextObject()); 773 774 while (mkey) { 775 // kprintf ("dictionary key #%d: %s\n", i, mkey->getCStringNoCopy () ); 776 777 // if this is the IOClass key, print it's contents 778 779 if (mkey->isEqualTo("IOClass")) { 780 ioClass = (OSString *) inDictionary->getObject("IOClass"); 781 if (ioClass) { 782 IOLog("%s IOClass is %s\n", inMsg, ioClass->getCStringNoCopy()); 783 } 784 } 785 786 // if this is an IOProviderClass key print it 787 788 if (mkey->isEqualTo("IOProviderClass")) { 789 ioClass = (OSString *) inDictionary->getObject("IOProviderClass"); 790 if (ioClass) { 791 IOLog("%s IOProviderClass is %s\n", inMsg, ioClass->getCStringNoCopy()); 792 } 793 } 794 795 // also print IONameMatch keys 796 if (mkey->isEqualTo("IONameMatch")) { 797 ioClass = (OSString *) inDictionary->getObject("IONameMatch"); 798 if (ioClass) { 799 IOLog("%s IONameMatch is %s\n", inMsg, ioClass->getCStringNoCopy()); 800 } 801 } 802 803 // also print IONameMatched keys 804 805 if (mkey->isEqualTo("IONameMatched")) { 806 ioClass = (OSString *) inDictionary->getObject("IONameMatched"); 807 if (ioClass) { 808 IOLog("%s IONameMatched is %s\n", inMsg, ioClass->getCStringNoCopy()); 809 } 810 } 811 812 #if 0 813 // print clock-id 814 815 if (mkey->isEqualTo("AAPL,clock-id")) { 816 char * cstr; 817 cstr = getCStringForObject(inDictionary->getObject("AAPL,clock-id")); 818 if (cstr) { 819 kprintf(" ===> AAPL,clock-id is %s\n", cstr ); 820 } 821 } 822 #endif 823 824 // print name 825 826 if (mkey->isEqualTo("name")) { 827 char nameStr[64]; 828 nameStr[0] = 0; 829 getCStringForObject(inDictionary->getObject("name"), nameStr, 830 sizeof(nameStr)); 831 if (strlen(nameStr) > 0) { 832 IOLog("%s name is %s\n", inMsg, nameStr); 833 } 834 } 835 836 mkey = (OSSymbol *) mcoll->getNextObject(); 837 838 i++; 839 } 840 841 mcoll->release(); 842 } 843 844 static void 845 getCStringForObject(OSObject *inObj, char *outStr, size_t outStrLen) 846 { 847 char * buffer; 848 unsigned int len, i; 849 850 if ((NULL == inObj) || (NULL == outStr)) { 851 return; 852 } 853 854 char * objString = (char *) (inObj->getMetaClass())->getClassName(); 855 856 if ((0 == strncmp(objString, "OSString", sizeof("OSString"))) || 857 (0 == strncmp(objString, "OSSymbol", sizeof("OSSymbol")))) { 858 strlcpy(outStr, ((OSString *)inObj)->getCStringNoCopy(), outStrLen); 859 } else if (0 == strncmp(objString, "OSData", sizeof("OSData"))) { 860 len = ((OSData *)inObj)->getLength(); 861 buffer = (char *)((OSData *)inObj)->getBytesNoCopy(); 862 if (buffer && (len > 0)) { 863 for (i = 0; i < len; i++) { 864 outStr[i] = buffer[i]; 865 } 866 outStr[len] = 0; 867 } 868 } 869 } 870 871 /* IOShutdownNotificationsTimedOut 872 * - Called from a timer installed by PEHaltRestart 873 */ 874 #if !defined(__x86_64) 875 __abortlike 876 #endif 877 static void 878 IOShutdownNotificationsTimedOut( 879 thread_call_param_t p0, 880 thread_call_param_t p1) 881 { 882 #if !defined(__x86_64__) 883 /* 30 seconds has elapsed - panic */ 884 panic("Halt/Restart Timed Out"); 885 886 #else /* !defined(__x86_64__) */ 887 int type = (int)(long)p0; 888 uint32_t timeout = (uint32_t)(uintptr_t)p1; 889 890 IOPMrootDomain *pmRootDomain = IOService::getPMRootDomain(); 891 if (pmRootDomain) { 892 if ((PEGetCoprocessorVersion() >= kCoprocessorVersion2) || pmRootDomain->checkShutdownTimeout()) { 893 pmRootDomain->panicWithShutdownLog(timeout * 1000); 894 } 895 } 896 897 /* 30 seconds has elapsed - resume shutdown */ 898 if (gIOPlatform) { 899 gIOPlatform->haltRestart(type); 900 } 901 #endif /* defined(__x86_64__) */ 902 } 903 904 905 extern "C" { 906 /* 907 * Callouts from BSD for machine name & model 908 */ 909 910 /* 911 * PEGetMachineName() and PEGetModelName() are inconsistent across 912 * architectures, and considered deprecated. Use PEGetTargetName() and 913 * PEGetProductName() instead. 914 */ 915 boolean_t 916 PEGetMachineName( char * name, int maxLength ) 917 { 918 if (gIOPlatform) { 919 return gIOPlatform->getMachineName( name, maxLength ); 920 } else { 921 return false; 922 } 923 } 924 925 /* 926 * PEGetMachineName() and PEGetModelName() are inconsistent across 927 * architectures, and considered deprecated. Use PEGetTargetName() and 928 * PEGetProductName() instead. 929 */ 930 boolean_t 931 PEGetModelName( char * name, int maxLength ) 932 { 933 if (gIOPlatform) { 934 return gIOPlatform->getModelName( name, maxLength ); 935 } else { 936 return false; 937 } 938 } 939 940 boolean_t 941 PEGetTargetName( char * name, int maxLength ) 942 { 943 if (gIOPlatform) { 944 return gIOPlatform->getTargetName( name, maxLength ); 945 } else { 946 return false; 947 } 948 } 949 950 boolean_t 951 PEGetProductName( char * name, int maxLength ) 952 { 953 if (gIOPlatform) { 954 return gIOPlatform->getProductName( name, maxLength ); 955 } else { 956 return false; 957 } 958 } 959 960 int 961 PEGetPlatformEpoch(void) 962 { 963 if (gIOPlatform) { 964 return (int) gIOPlatform->getBootROMType(); 965 } else { 966 return -1; 967 } 968 } 969 970 /* Handle necessary platform specific actions prior to panic */ 971 void 972 PEInitiatePanic(void) 973 { 974 #if defined(__arm64__) 975 /* 976 * Trigger a TLB flush so any hard hangs exercise the SoC diagnostic 977 * collection flow rather than hanging late in panic (see rdar://58062030) 978 */ 979 flush_mmu_tlb_entries_async(0, PAGE_SIZE, PAGE_SIZE, true, true); 980 arm64_sync_tlb(true); 981 #endif // defined(__arm64__) 982 } 983 984 int 985 PEHaltRestartInternal(unsigned int type, uint32_t details) 986 { 987 IOPMrootDomain *pmRootDomain; 988 AbsoluteTime deadline; 989 thread_call_t shutdown_hang; 990 IORegistryEntry *node; 991 OSData *data; 992 uint32_t timeout = kShutdownTimeout; 993 static boolean_t panic_begin_called = FALSE; 994 995 if (type == kPEHaltCPU || type == kPERestartCPU || type == kPEUPSDelayHaltCPU) { 996 /* If we're in the panic path, the locks and memory allocations required below 997 * could fail. So just try to reboot instead of risking a nested panic. 998 */ 999 if (panic_begin_called) { 1000 goto skip_to_haltRestart; 1001 } 1002 1003 pmRootDomain = IOService::getPMRootDomain(); 1004 /* Notify IOKit PM clients of shutdown/restart 1005 * Clients subscribe to this message with a call to 1006 * IOService::registerInterest() 1007 */ 1008 1009 /* Spawn a thread that will panic in 30 seconds. 1010 * If all goes well the machine will be off by the time 1011 * the timer expires. If the device wants a different 1012 * timeout, use that value instead of 30 seconds. 1013 */ 1014 #if defined(__arm64__) 1015 #define RESTART_NODE_PATH "/defaults" 1016 #else 1017 #define RESTART_NODE_PATH "/chosen" 1018 #endif 1019 node = IORegistryEntry::fromPath( RESTART_NODE_PATH, gIODTPlane ); 1020 if (node) { 1021 data = OSDynamicCast( OSData, node->getProperty( "halt-restart-timeout" )); 1022 if (data && data->getLength() == 4) { 1023 timeout = *((uint32_t *) data->getBytesNoCopy()); 1024 } 1025 OSSafeReleaseNULL(node); 1026 } 1027 1028 #if (DEVELOPMENT || DEBUG) 1029 /* Override the default timeout via a boot-arg */ 1030 uint32_t boot_arg_val; 1031 if (PE_parse_boot_argn("halt_restart_timeout", &boot_arg_val, sizeof(boot_arg_val))) { 1032 timeout = boot_arg_val; 1033 } 1034 #endif 1035 1036 if (timeout) { 1037 shutdown_hang = thread_call_allocate( &IOShutdownNotificationsTimedOut, 1038 (thread_call_param_t)(uintptr_t) type); 1039 clock_interval_to_deadline( timeout, kSecondScale, &deadline ); 1040 thread_call_enter1_delayed( shutdown_hang, (thread_call_param_t)(uintptr_t)timeout, deadline ); 1041 } 1042 1043 pmRootDomain->handlePlatformHaltRestart(type); 1044 /* This notification should have few clients who all do 1045 * their work synchronously. 1046 * 1047 * In this "shutdown notification" context we don't give 1048 * drivers the option of working asynchronously and responding 1049 * later. PM internals make it very hard to wait for asynchronous 1050 * replies. 1051 */ 1052 } else if (type == kPEPanicRestartCPU || type == kPEPanicSync || type == kPEPanicRestartCPUNoCallouts) { 1053 if (type == kPEPanicRestartCPU) { 1054 // Notify any listeners that we're done collecting 1055 // panic data before we call through to do the restart 1056 #if defined(__x86_64__) 1057 if (coprocessor_cross_panic_enabled) 1058 #endif 1059 IOCPURunPlatformPanicActions(kPEPanicEnd, details); 1060 } else if (type == kPEPanicRestartCPUNoCallouts) { 1061 // We skipped the callouts so now set the type to 1062 // the variant that the platform uses for panic restarts. 1063 type = kPEPanicRestartCPU; 1064 } 1065 1066 1067 // Do an initial sync to flush as much panic data as possible, 1068 // in case we have a problem in one of the platorm panic handlers. 1069 // After running the platform handlers, do a final sync w/ 1070 // platform hardware quiesced for the panic. 1071 PE_sync_panic_buffers(); 1072 IOCPURunPlatformPanicActions(type, details); 1073 PE_sync_panic_buffers(); 1074 } else if (type == kPEPanicEnd) { 1075 #if defined(__x86_64__) 1076 if (coprocessor_cross_panic_enabled) 1077 #endif 1078 IOCPURunPlatformPanicActions(type, details); 1079 } else if (type == kPEPanicBegin) { 1080 #if defined(__x86_64__) 1081 if (coprocessor_cross_panic_enabled) 1082 #endif 1083 { 1084 // Only call the kPEPanicBegin callout once 1085 if (!panic_begin_called) { 1086 panic_begin_called = TRUE; 1087 IOCPURunPlatformPanicActions(type, details); 1088 } 1089 } 1090 } else if (type == kPEPanicDiagnosticsDone || type == kPEPanicDiagnosticsInProgress) { 1091 IOCPURunPlatformPanicActions(type, details); 1092 } 1093 1094 skip_to_haltRestart: 1095 if (gIOPlatform) { 1096 // note that this will not necessarily halt or restart the system... 1097 // Implementors of this function will check the type and take action accordingly 1098 return gIOPlatform->haltRestart(type); 1099 } else { 1100 return -1; 1101 } 1102 } 1103 1104 int 1105 PEHaltRestart(unsigned int type) 1106 { 1107 return PEHaltRestartInternal(type, 0); 1108 } 1109 1110 UInt32 1111 PESavePanicInfo(UInt8 *buffer, UInt32 length) 1112 { 1113 if (gIOPlatform != NULL) { 1114 return (UInt32) gIOPlatform->savePanicInfo(buffer, length); 1115 } else { 1116 return 0; 1117 } 1118 } 1119 1120 void 1121 PESavePanicInfoAction(void *buffer, UInt32 offset, UInt32 length) 1122 { 1123 IOCPURunPlatformPanicSyncAction(buffer, offset, length); 1124 return; 1125 } 1126 1127 1128 /* 1129 * Depending on the platform, the /options node may not be created 1130 * until after IOKit matching has started, by an externally-supplied 1131 * platform expert subclass. Therefore, we must check for its presence 1132 * here and update gIOOptionsEntry for the platform code as necessary. 1133 */ 1134 inline static int 1135 init_gIOOptionsEntry(void) 1136 { 1137 IORegistryEntry *entry; 1138 void *nvram_entry; 1139 volatile void **options; 1140 int ret = -1; 1141 1142 if (gIOOptionsEntry) { 1143 return 0; 1144 } 1145 1146 entry = IORegistryEntry::fromPath( "/options", gIODTPlane ); 1147 if (!entry) { 1148 return -1; 1149 } 1150 1151 nvram_entry = (void *) OSDynamicCast(IODTNVRAM, entry); 1152 if (!nvram_entry) { 1153 goto release; 1154 } 1155 1156 options = (volatile void **) &gIOOptionsEntry; 1157 if (!OSCompareAndSwapPtr(NULL, nvram_entry, options)) { 1158 ret = 0; 1159 goto release; 1160 } 1161 1162 return 0; 1163 1164 release: 1165 entry->release(); 1166 return ret; 1167 } 1168 1169 /* pass in a NULL value if you just want to figure out the len */ 1170 boolean_t 1171 PEReadNVRAMProperty(const char *symbol, void *value, 1172 unsigned int *len) 1173 { 1174 OSObject *obj; 1175 OSData *data; 1176 unsigned int vlen; 1177 1178 if (!symbol || !len) { 1179 goto err; 1180 } 1181 1182 if (init_gIOOptionsEntry() < 0) { 1183 goto err; 1184 } 1185 1186 vlen = *len; 1187 *len = 0; 1188 1189 obj = gIOOptionsEntry->getProperty(symbol); 1190 if (!obj) { 1191 goto err; 1192 } 1193 1194 /* convert to data */ 1195 data = OSDynamicCast(OSData, obj); 1196 if (!data) { 1197 goto err; 1198 } 1199 1200 *len = data->getLength(); 1201 vlen = min(vlen, *len); 1202 if (value && vlen) { 1203 memcpy((void *) value, data->getBytesNoCopy(), vlen); 1204 } 1205 1206 return TRUE; 1207 1208 err: 1209 return FALSE; 1210 } 1211 1212 boolean_t 1213 PEReadNVRAMBooleanProperty(const char *symbol, boolean_t *value) 1214 { 1215 OSObject *obj; 1216 OSBoolean *data; 1217 1218 if (!symbol || !value) { 1219 goto err; 1220 } 1221 1222 if (init_gIOOptionsEntry() < 0) { 1223 goto err; 1224 } 1225 1226 obj = gIOOptionsEntry->getProperty(symbol); 1227 if (!obj) { 1228 return TRUE; 1229 } 1230 1231 /* convert to bool */ 1232 data = OSDynamicCast(OSBoolean, obj); 1233 if (!data) { 1234 goto err; 1235 } 1236 1237 *value = data->isTrue() ? TRUE : FALSE; 1238 1239 return TRUE; 1240 1241 err: 1242 return FALSE; 1243 } 1244 1245 boolean_t 1246 PEWriteNVRAMBooleanProperty(const char *symbol, boolean_t value) 1247 { 1248 const OSSymbol *sym = NULL; 1249 OSBoolean *data = NULL; 1250 bool ret = false; 1251 1252 if (symbol == NULL) { 1253 goto exit; 1254 } 1255 1256 if (init_gIOOptionsEntry() < 0) { 1257 goto exit; 1258 } 1259 1260 if ((sym = OSSymbol::withCStringNoCopy(symbol)) == NULL) { 1261 goto exit; 1262 } 1263 1264 data = value ? kOSBooleanTrue : kOSBooleanFalse; 1265 ret = gIOOptionsEntry->setProperty(sym, data); 1266 1267 sym->release(); 1268 1269 /* success, force the NVRAM to flush writes */ 1270 if (ret == true) { 1271 gIOOptionsEntry->sync(); 1272 } 1273 1274 exit: 1275 return ret; 1276 } 1277 1278 static boolean_t 1279 PEWriteNVRAMPropertyInternal(const char *symbol, boolean_t copySymbol, const void *value, 1280 const unsigned int len) 1281 { 1282 const OSSymbol *sym; 1283 OSData *data; 1284 bool ret = false; 1285 1286 if (!symbol || !value || !len) { 1287 goto err; 1288 } 1289 1290 if (init_gIOOptionsEntry() < 0) { 1291 goto err; 1292 } 1293 1294 if (copySymbol == TRUE) { 1295 sym = OSSymbol::withCString(symbol); 1296 } else { 1297 sym = OSSymbol::withCStringNoCopy(symbol); 1298 } 1299 1300 if (!sym) { 1301 goto err; 1302 } 1303 1304 data = OSData::withBytes((void *) value, len); 1305 if (!data) { 1306 goto sym_done; 1307 } 1308 1309 ret = gIOOptionsEntry->setProperty(sym, data); 1310 data->release(); 1311 1312 sym_done: 1313 sym->release(); 1314 1315 if (ret == true) { 1316 gIOOptionsEntry->sync(); 1317 return TRUE; 1318 } 1319 1320 err: 1321 return FALSE; 1322 } 1323 1324 boolean_t 1325 PEWriteNVRAMProperty(const char *symbol, const void *value, 1326 const unsigned int len) 1327 { 1328 return PEWriteNVRAMPropertyInternal(symbol, FALSE, value, len); 1329 } 1330 1331 boolean_t 1332 PEWriteNVRAMPropertyWithCopy(const char *symbol, const void *value, 1333 const unsigned int len) 1334 { 1335 return PEWriteNVRAMPropertyInternal(symbol, TRUE, value, len); 1336 } 1337 1338 boolean_t 1339 PERemoveNVRAMProperty(const char *symbol) 1340 { 1341 const OSSymbol *sym; 1342 1343 if (!symbol) { 1344 goto err; 1345 } 1346 1347 if (init_gIOOptionsEntry() < 0) { 1348 goto err; 1349 } 1350 1351 sym = OSSymbol::withCStringNoCopy(symbol); 1352 if (!sym) { 1353 goto err; 1354 } 1355 1356 gIOOptionsEntry->removeProperty(sym); 1357 1358 sym->release(); 1359 1360 gIOOptionsEntry->sync(); 1361 return TRUE; 1362 1363 err: 1364 return FALSE; 1365 } 1366 1367 boolean_t 1368 PESyncNVRAM(void) 1369 { 1370 if (gIOOptionsEntry != nullptr) { 1371 gIOOptionsEntry->sync(); 1372 } 1373 1374 return TRUE; 1375 } 1376 1377 long 1378 PEGetGMTTimeOfDay(void) 1379 { 1380 clock_sec_t secs; 1381 clock_usec_t usecs; 1382 1383 PEGetUTCTimeOfDay(&secs, &usecs); 1384 return secs; 1385 } 1386 1387 void 1388 PESetGMTTimeOfDay(long secs) 1389 { 1390 PESetUTCTimeOfDay(secs, 0); 1391 } 1392 1393 void 1394 PEGetUTCTimeOfDay(clock_sec_t * secs, clock_usec_t * usecs) 1395 { 1396 clock_nsec_t nsecs = 0; 1397 1398 *secs = 0; 1399 if (gIOPlatform) { 1400 gIOPlatform->getUTCTimeOfDay(secs, &nsecs); 1401 } 1402 1403 assert(nsecs < NSEC_PER_SEC); 1404 *usecs = nsecs / NSEC_PER_USEC; 1405 } 1406 1407 void 1408 PESetUTCTimeOfDay(clock_sec_t secs, clock_usec_t usecs) 1409 { 1410 assert(usecs < USEC_PER_SEC); 1411 if (gIOPlatform) { 1412 gIOPlatform->setUTCTimeOfDay(secs, usecs * NSEC_PER_USEC); 1413 } 1414 } 1415 1416 coprocessor_type_t 1417 PEGetCoprocessorVersion( void ) 1418 { 1419 coprocessor_type_t coprocessor_version = kCoprocessorVersionNone; 1420 #if defined(__x86_64__) 1421 IORegistryEntry *platform_entry = NULL; 1422 OSData *coprocessor_version_obj = NULL; 1423 1424 platform_entry = IORegistryEntry::fromPath(kIODeviceTreePlane ":/efi/platform"); 1425 if (platform_entry != NULL) { 1426 coprocessor_version_obj = OSDynamicCast(OSData, platform_entry->getProperty("apple-coprocessor-version")); 1427 if ((coprocessor_version_obj != NULL) && (coprocessor_version_obj->getLength() <= sizeof(uint64_t))) { 1428 memcpy(&coprocessor_version, coprocessor_version_obj->getBytesNoCopy(), coprocessor_version_obj->getLength()); 1429 } 1430 platform_entry->release(); 1431 } 1432 #endif 1433 return coprocessor_version; 1434 } 1435 } /* extern "C" */ 1436 1437 bool gIOPlatformUUIDAndSerialDone = false; 1438 1439 void 1440 IOPlatformExpert::publishPlatformUUIDAndSerial( void ) 1441 { 1442 if (!gIOPlatformUUIDAndSerialDone) { 1443 // Parse the serial-number data and publish a user-readable string 1444 if (NULL == getProvider()->getProperty(kIOPlatformSerialNumberKey)) { 1445 OSData* mydata = (OSData*) (getProvider()->getProperty("serial-number")); 1446 if (mydata != NULL) { 1447 OSString *serNoString = createSystemSerialNumberString(mydata); 1448 if (serNoString != NULL) { 1449 getProvider()->setProperty(kIOPlatformSerialNumberKey, serNoString); 1450 serNoString->release(); 1451 } 1452 } 1453 } 1454 IOPlatformExpertDevice *provider = OSDynamicCast(IOPlatformExpertDevice, getProvider()); 1455 assert(provider != NULL); 1456 provider->generatePlatformUUID(); 1457 } 1458 1459 if (gIOPlatformUUIDAndSerialDone) { 1460 publishResource(kIOPlatformUUIDKey, getProvider()->getProperty(kIOPlatformUUIDKey)); 1461 } 1462 } 1463 1464 void 1465 IOPlatformExpert::publishNVRAM( void ) 1466 { 1467 if (init_gIOOptionsEntry() < 0) { 1468 IOPlatformExpertDevice *provider = OSDynamicCast(IOPlatformExpertDevice, getProvider()); 1469 assert(provider != NULL); 1470 provider->createNVRAM(); 1471 } 1472 if (gIOOptionsEntry != NULL) { 1473 gIOOptionsEntry->registerService(); 1474 } 1475 } 1476 1477 void 1478 IOPlatformExpert::registerNVRAMController(IONVRAMController * caller) 1479 { 1480 #if defined(__x86_64__) 1481 OSData * data; 1482 IORegistryEntry * entry; 1483 1484 /* 1485 * If we have panic debugging enabled WITHOUT behavior to reboot after any crash (DB_REBOOT_ALWAYS) 1486 * and we are on a co-processor system that has the panic SoC watchdog enabled, disable 1487 * cross panics so that the co-processor doesn't cause the system 1488 * to reset when we enter the debugger or hit a panic on the x86 side. 1489 */ 1490 if (panicDebugging && !(debug_boot_arg & DB_REBOOT_ALWAYS)) { 1491 entry = IORegistryEntry::fromPath( "/options", gIODTPlane ); 1492 if (entry) { 1493 data = OSDynamicCast( OSData, entry->getProperty( APPLE_VENDOR_VARIABLE_GUID":BridgeOSPanicWatchdogEnabled" )); 1494 if (data && (data->getLength() == sizeof(UInt8))) { 1495 UInt8 *panicWatchdogEnabled = (UInt8 *) data->getBytesNoCopy(); 1496 UInt32 debug_flags = 0; 1497 if (*panicWatchdogEnabled || (PE_i_can_has_debugger(&debug_flags) && 1498 (debug_flags & DB_DISABLE_CROSS_PANIC))) { 1499 coprocessor_cross_panic_enabled = FALSE; 1500 } 1501 } 1502 entry->release(); 1503 } 1504 } 1505 1506 #if (DEVELOPMENT || DEBUG) 1507 entry = IORegistryEntry::fromPath( "/options", gIODTPlane ); 1508 if (entry) { 1509 data = OSDynamicCast( OSData, entry->getProperty(nvram_osenvironment)); 1510 if (data) { 1511 sysctl_set_osenvironment(data->getLength(), data->getBytesNoCopy()); 1512 entry->removeProperty(nvram_osenvironment); 1513 IODTNVRAM * nvramOptionsEntry = OSDynamicCast(IODTNVRAM, entry); 1514 if (nvramOptionsEntry) { 1515 nvramOptionsEntry->sync(); 1516 } 1517 } 1518 entry->release(); 1519 } 1520 sysctl_unblock_osenvironment(); 1521 #endif 1522 /* on intel the UUID must be published after nvram is available */ 1523 publishPlatformUUIDAndSerial(); 1524 1525 #endif /* defined(__x86_64__) */ 1526 1527 publishResource("IONVRAM"); 1528 } 1529 1530 IOReturn 1531 IOPlatformExpert::callPlatformFunction(const OSSymbol *functionName, 1532 bool waitForFunction, 1533 void *param1, void *param2, 1534 void *param3, void *param4) 1535 { 1536 IOService *service, *_resources; 1537 OSObject *prop = NULL; 1538 IOReturn ret; 1539 1540 if (functionName == gIOPlatformQuiesceActionKey || 1541 functionName == gIOPlatformActiveActionKey || 1542 functionName == gIOPlatformPanicActionKey) { 1543 /* 1544 * Services which register for IOPlatformQuiesceAction / IOPlatformActiveAction / IOPlatformPanicAction 1545 * must consume that event themselves, without passing it up to super/IOPlatformExpert. 1546 */ 1547 if (gEnforcePlatformActionSafety) { 1548 panic("Class %s passed the %s action to IOPlatformExpert", 1549 getMetaClass()->getClassName(), functionName->getCStringNoCopy()); 1550 } 1551 } 1552 1553 if (waitForFunction) { 1554 _resources = waitForService(resourceMatching(functionName)); 1555 } else { 1556 _resources = getResourceService(); 1557 } 1558 if (_resources == NULL) { 1559 return kIOReturnUnsupported; 1560 } 1561 1562 prop = _resources->copyProperty(functionName); 1563 service = OSDynamicCast(IOService, prop); 1564 if (service == NULL) { 1565 ret = kIOReturnUnsupported; 1566 goto finish; 1567 } 1568 1569 ret = service->callPlatformFunction(functionName, waitForFunction, 1570 param1, param2, param3, param4); 1571 1572 finish: 1573 OSSafeReleaseNULL(prop); 1574 return ret; 1575 } 1576 1577 IOByteCount 1578 IOPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length) 1579 { 1580 return 0; 1581 } 1582 1583 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 1584 1585 #undef super 1586 #define super IOPlatformExpert 1587 1588 OSDefineMetaClassAndAbstractStructors( IODTPlatformExpert, IOPlatformExpert ) 1589 1590 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 0); 1591 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 1); 1592 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 2); 1593 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 3); 1594 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 4); 1595 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 5); 1596 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 6); 1597 OSMetaClassDefineReservedUnused(IODTPlatformExpert, 7); 1598 1599 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 1600 1601 IOService * 1602 IODTPlatformExpert::probe( IOService * provider, 1603 SInt32 * score ) 1604 { 1605 if (!super::probe( provider, score)) { 1606 return NULL; 1607 } 1608 1609 // check machine types 1610 if (!provider->compareNames( getProperty( gIONameMatchKey ))) { 1611 return NULL; 1612 } 1613 1614 return this; 1615 } 1616 1617 bool 1618 IODTPlatformExpert::configure( IOService * provider ) 1619 { 1620 if (!super::configure( provider)) { 1621 return false; 1622 } 1623 1624 processTopLevel( provider ); 1625 1626 return true; 1627 } 1628 1629 IOService * 1630 IODTPlatformExpert::createNub( IORegistryEntry * from ) 1631 { 1632 IOService * nub; 1633 1634 nub = new IOPlatformDevice; 1635 if (nub) { 1636 if (!nub->init( from, gIODTPlane )) { 1637 nub->free(); 1638 nub = NULL; 1639 } 1640 } 1641 return nub; 1642 } 1643 1644 bool 1645 IODTPlatformExpert::createNubs( IOService * parent, OSIterator * iter ) 1646 { 1647 IORegistryEntry * next; 1648 IOService * nub = NULL; 1649 bool ok = true; 1650 1651 if (iter) { 1652 while ((next = (IORegistryEntry *) iter->getNextObject())) { 1653 OSSafeReleaseNULL(nub); 1654 1655 if (NULL == (nub = createNub( next ))) { 1656 continue; 1657 } 1658 1659 nub->attach( parent ); 1660 #if !defined(__x86_64__) 1661 OSData *tmpData = (OSData *)next->getProperty("device_type"); 1662 if (tmpData == NULL) { 1663 nub->registerService(); 1664 continue; 1665 } 1666 1667 char *device_type = (char *)tmpData->getBytesNoCopy(); 1668 if (strcmp(device_type, "cpu") != 0) { 1669 nub->registerService(); 1670 continue; 1671 } 1672 1673 tmpData = (OSData *)next->getProperty("reg"); 1674 assert(tmpData != NULL); 1675 assert(tmpData->getLength() >= sizeof(UInt32)); 1676 1677 uint32_t phys_id = *(UInt32 *)tmpData->getBytesNoCopy(); 1678 int logical_cpu_id = ml_get_cpu_number(phys_id); 1679 int logical_cluster_id = ml_get_cluster_number(phys_id); 1680 1681 /* 1682 * If the following condition triggers, it means that a CPU that was present in the DT 1683 * was ignored by XNU at topology parsing time. This can happen currently when using the 1684 * cpus=N boot-arg; for example, cpus=1 will cause XNU to parse and enable a single CPU. 1685 * 1686 * Note that this condition will not trigger for harvested cores because these do not show up 1687 * in the DT/IORegistry in the first place. 1688 */ 1689 if (logical_cpu_id < 0) { 1690 nub->registerService(); 1691 continue; 1692 } 1693 1694 __assert_only bool logical_id_added_to_ioreg = nub->setProperty("logical-cpu-id", logical_cpu_id, 32U); 1695 assert(logical_id_added_to_ioreg == true); 1696 logical_id_added_to_ioreg = nub->setProperty("logical-cluster-id", logical_cluster_id, 32U); 1697 assert(logical_id_added_to_ioreg == true); 1698 #endif 1699 nub->registerService(); 1700 } 1701 OSSafeReleaseNULL(nub); 1702 iter->release(); 1703 } 1704 1705 return ok; 1706 } 1707 1708 void 1709 IODTPlatformExpert::processTopLevel( IORegistryEntry * rootEntry ) 1710 { 1711 OSIterator * kids; 1712 IORegistryEntry * next; 1713 IORegistryEntry * cpus; 1714 1715 // infanticide 1716 kids = IODTFindMatchingEntries( rootEntry, 0, deleteList()); 1717 if (kids) { 1718 while ((next = (IORegistryEntry *)kids->getNextObject())) { 1719 next->detachAll( gIODTPlane); 1720 } 1721 kids->release(); 1722 } 1723 1724 publishNVRAM(); 1725 assert(gIOOptionsEntry != NULL); // subclasses that do their own NVRAM initialization shouldn't be calling this 1726 dtNVRAM = gIOOptionsEntry; 1727 1728 // Publish the cpus. 1729 cpus = rootEntry->childFromPath( "cpus", gIODTPlane); 1730 if (cpus) { 1731 createNubs( this, IODTFindMatchingEntries( cpus, kIODTExclusive, NULL)); 1732 cpus->release(); 1733 } 1734 1735 // publish top level, minus excludeList 1736 createNubs( this, IODTFindMatchingEntries( rootEntry, kIODTExclusive, excludeList())); 1737 } 1738 1739 IOReturn 1740 IODTPlatformExpert::getNubResources( IOService * nub ) 1741 { 1742 if (nub->getDeviceMemory()) { 1743 return kIOReturnSuccess; 1744 } 1745 1746 IODTResolveAddressing( nub, "reg", NULL); 1747 1748 return kIOReturnSuccess; 1749 } 1750 1751 bool 1752 IODTPlatformExpert::compareNubName( const IOService * nub, 1753 OSString * name, OSString ** matched ) const 1754 { 1755 return IODTCompareNubName( nub, name, matched ) 1756 || super::compareNubName( nub, name, matched); 1757 } 1758 1759 1760 /* 1761 * Do not use this method directly, it returns inconsistent results 1762 * across architectures and is considered deprecated. 1763 * 1764 * Use getTargetName and getProductName respectively. For example: 1765 * 1766 * targetName: J137AP 1767 * productName: iMacPro1,1 1768 * 1769 * targetName: D331pAP 1770 * productName: iPhone11,6 1771 */ 1772 1773 bool 1774 IODTPlatformExpert::getModelName( char * name, int maxLength ) 1775 { 1776 OSData * prop; 1777 const char * str; 1778 int len; 1779 char c; 1780 bool ok = false; 1781 1782 maxLength--; 1783 1784 prop = (OSData *) getProvider()->getProperty( gIODTCompatibleKey ); 1785 if (prop) { 1786 str = (const char *) prop->getBytesNoCopy(); 1787 1788 if (0 == strncmp( str, "AAPL,", strlen( "AAPL," ))) { 1789 str += strlen( "AAPL," ); 1790 } 1791 1792 len = 0; 1793 while ((c = *str++)) { 1794 if ((c == '/') || (c == ' ')) { 1795 c = '-'; 1796 } 1797 1798 name[len++] = c; 1799 if (len >= maxLength) { 1800 break; 1801 } 1802 } 1803 1804 name[len] = 0; 1805 ok = true; 1806 } 1807 return ok; 1808 } 1809 1810 /* 1811 * Do not use this method directly, it returns inconsistent results 1812 * across architectures and is considered deprecated. 1813 * 1814 * Use getTargetName and getProductName respectively. For example: 1815 * 1816 * targetName: J137AP 1817 * productName: iMacPro1,1 1818 * 1819 * targetName: D331pAP 1820 * productName: iPhone11,6 1821 */ 1822 1823 bool 1824 IODTPlatformExpert::getMachineName( char * name, int maxLength ) 1825 { 1826 OSData * prop; 1827 bool ok = false; 1828 1829 maxLength--; 1830 prop = (OSData *) getProvider()->getProperty( gIODTModelKey ); 1831 ok = (NULL != prop); 1832 1833 if (ok) { 1834 strlcpy( name, (const char *) prop->getBytesNoCopy(), maxLength ); 1835 } 1836 1837 return ok; 1838 } 1839 1840 /* Examples: J137AP, D331pAP... */ 1841 1842 bool 1843 IODTPlatformExpert::getTargetName( char * name, int maxLength ) 1844 { 1845 #if __x86_64__ 1846 OSData * prop; 1847 1848 const OSSymbol * key = gIODTBridgeModelKey; 1849 1850 maxLength--; 1851 prop = (OSData *) getProvider()->getProperty( key ); 1852 1853 if (prop == NULL) { 1854 // This happens if there is no bridge. 1855 char const * const unknown = ""; 1856 1857 strlcpy( name, unknown, maxLength ); 1858 } else { 1859 strlcpy( name, (const char *)prop->getBytesNoCopy(), maxLength ); 1860 } 1861 1862 return true; 1863 #else 1864 return getModelName( name, maxLength ); 1865 #endif 1866 } 1867 1868 /* Examples: iMacPro1,1, iPhone11,6... */ 1869 1870 bool 1871 IODTPlatformExpert::getProductName( char * name, int maxLength ) 1872 { 1873 #if __x86_64__ 1874 return getModelName( name, maxLength ); 1875 #else 1876 return getMachineName( name, maxLength ); 1877 #endif 1878 } 1879 1880 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 1881 1882 void 1883 IODTPlatformExpert::registerNVRAMController( IONVRAMController * nvram ) 1884 { 1885 if (dtNVRAM) { 1886 dtNVRAM->registerNVRAMController(nvram); 1887 } 1888 1889 super::registerNVRAMController(nvram); 1890 } 1891 1892 int 1893 IODTPlatformExpert::haltRestart(unsigned int type) 1894 { 1895 return super::haltRestart(type); 1896 } 1897 1898 IOReturn 1899 IODTPlatformExpert::readXPRAM(IOByteCount offset, UInt8 * buffer, 1900 IOByteCount length) 1901 { 1902 if (dtNVRAM) { 1903 return dtNVRAM->readXPRAM(offset, buffer, length); 1904 } else { 1905 return kIOReturnNotReady; 1906 } 1907 } 1908 1909 IOReturn 1910 IODTPlatformExpert::writeXPRAM(IOByteCount offset, UInt8 * buffer, 1911 IOByteCount length) 1912 { 1913 if (dtNVRAM) { 1914 return dtNVRAM->writeXPRAM(offset, buffer, length); 1915 } else { 1916 return kIOReturnNotReady; 1917 } 1918 } 1919 1920 IOReturn 1921 IODTPlatformExpert::readNVRAMProperty( 1922 IORegistryEntry * entry, 1923 const OSSymbol ** name, OSData ** value ) 1924 { 1925 if (dtNVRAM) { 1926 return dtNVRAM->readNVRAMProperty(entry, name, value); 1927 } else { 1928 return kIOReturnNotReady; 1929 } 1930 } 1931 1932 IOReturn 1933 IODTPlatformExpert::readNVRAMProperty( 1934 IORegistryEntry * entry, 1935 OSSharedPtr<const OSSymbol>& name, OSSharedPtr<OSData>& value ) 1936 { 1937 const OSSymbol* nameRaw = NULL; 1938 OSData* valueRaw = NULL; 1939 1940 IOReturn result = readNVRAMProperty(entry, &nameRaw, &valueRaw); 1941 1942 name.reset(nameRaw, OSNoRetain); 1943 value.reset(valueRaw, OSNoRetain); 1944 1945 return result; 1946 } 1947 1948 IOReturn 1949 IODTPlatformExpert::writeNVRAMProperty( 1950 IORegistryEntry * entry, 1951 const OSSymbol * name, OSData * value ) 1952 { 1953 if (dtNVRAM) { 1954 return dtNVRAM->writeNVRAMProperty(entry, name, value); 1955 } else { 1956 return kIOReturnNotReady; 1957 } 1958 } 1959 1960 OSDictionary * 1961 IODTPlatformExpert::getNVRAMPartitions(void) 1962 { 1963 if (dtNVRAM) { 1964 return dtNVRAM->getNVRAMPartitions(); 1965 } else { 1966 return NULL; 1967 } 1968 } 1969 1970 IOReturn 1971 IODTPlatformExpert::readNVRAMPartition(const OSSymbol * partitionID, 1972 IOByteCount offset, UInt8 * buffer, 1973 IOByteCount length) 1974 { 1975 if (dtNVRAM) { 1976 return dtNVRAM->readNVRAMPartition(partitionID, offset, 1977 buffer, length); 1978 } else { 1979 return kIOReturnNotReady; 1980 } 1981 } 1982 1983 IOReturn 1984 IODTPlatformExpert::writeNVRAMPartition(const OSSymbol * partitionID, 1985 IOByteCount offset, UInt8 * buffer, 1986 IOByteCount length) 1987 { 1988 if (dtNVRAM) { 1989 return dtNVRAM->writeNVRAMPartition(partitionID, offset, 1990 buffer, length); 1991 } else { 1992 return kIOReturnNotReady; 1993 } 1994 } 1995 1996 IOByteCount 1997 IODTPlatformExpert::savePanicInfo(UInt8 *buffer, IOByteCount length) 1998 { 1999 IOByteCount lengthSaved = 0; 2000 2001 if (dtNVRAM) { 2002 lengthSaved = dtNVRAM->savePanicInfo(buffer, length); 2003 } 2004 2005 if (lengthSaved == 0) { 2006 lengthSaved = super::savePanicInfo(buffer, length); 2007 } 2008 2009 return lengthSaved; 2010 } 2011 2012 OSString* 2013 IODTPlatformExpert::createSystemSerialNumberString(OSData* myProperty) 2014 { 2015 UInt8* serialNumber; 2016 unsigned int serialNumberSize; 2017 unsigned short pos = 0; 2018 char* temp; 2019 char SerialNo[30]; 2020 2021 if (myProperty != NULL) { 2022 serialNumberSize = myProperty->getLength(); 2023 serialNumber = (UInt8*)(myProperty->getBytesNoCopy()); 2024 temp = (char*)serialNumber; 2025 if (serialNumberSize > 0) { 2026 // check to see if this is a CTO serial number... 2027 while (pos < serialNumberSize && temp[pos] != '-') { 2028 pos++; 2029 } 2030 2031 if (pos < serialNumberSize) { // there was a hyphen, so it's a CTO serial number 2032 memcpy(SerialNo, serialNumber + 12, 8); 2033 memcpy(&SerialNo[8], serialNumber, 3); 2034 SerialNo[11] = '-'; 2035 memcpy(&SerialNo[12], serialNumber + 3, 8); 2036 SerialNo[20] = 0; 2037 } else { // just a normal serial number 2038 memcpy(SerialNo, serialNumber + 13, 8); 2039 memcpy(&SerialNo[8], serialNumber, 3); 2040 SerialNo[11] = 0; 2041 } 2042 return OSString::withCString(SerialNo); 2043 } 2044 } 2045 return NULL; 2046 } 2047 2048 2049 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 2050 2051 #undef super 2052 #define super IOService 2053 2054 OSDefineMetaClassAndStructors(IOPlatformExpertDevice, IOService) 2055 2056 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 0); 2057 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 1); 2058 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 2); 2059 OSMetaClassDefineReservedUnused(IOPlatformExpertDevice, 3); 2060 2061 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 2062 2063 bool 2064 IOPlatformExpertDevice::compareName( OSString * name, 2065 OSString ** matched ) const 2066 { 2067 return IODTCompareNubName( this, name, matched ); 2068 } 2069 2070 bool 2071 IOPlatformExpertDevice::init(void *dtRoot) 2072 { 2073 IORegistryEntry * dt = NULL; 2074 bool ok; 2075 2076 if ((dtRoot != NULL) && (dt = IODeviceTreeAlloc(dtRoot))) { 2077 ok = super::init( dt, gIODTPlane ); 2078 } else { 2079 ok = super::init(); 2080 } 2081 2082 if (!ok) { 2083 return false; 2084 } 2085 2086 return true; 2087 } 2088 2089 bool 2090 IOPlatformExpertDevice::startIOServiceMatching(void) 2091 { 2092 workLoop = IOWorkLoop::workLoop(); 2093 if (!workLoop) { 2094 return false; 2095 } 2096 2097 registerService(); 2098 2099 return true; 2100 } 2101 2102 IOWorkLoop * 2103 IOPlatformExpertDevice::getWorkLoop() const 2104 { 2105 return workLoop; 2106 } 2107 2108 IOReturn 2109 IOPlatformExpertDevice::setProperties( OSObject * properties ) 2110 { 2111 return kIOReturnUnsupported; 2112 } 2113 2114 IOReturn 2115 IOPlatformExpertDevice::newUserClient( task_t owningTask, void * securityID, 2116 UInt32 type, OSDictionary * properties, 2117 IOUserClient ** handler ) 2118 { 2119 IOReturn err = kIOReturnSuccess; 2120 IOUserClient * newConnect = NULL; 2121 IOUserClient * theConnect = NULL; 2122 2123 switch (type) { 2124 case kIOKitDiagnosticsClientType: 2125 newConnect = IOKitDiagnosticsClient::withTask(owningTask); 2126 if (!newConnect) { 2127 err = kIOReturnNotPermitted; 2128 } 2129 break; 2130 case kIOKitUserServerClientType: 2131 newConnect = IOUserServer::withTask(owningTask); 2132 if (!newConnect) { 2133 err = kIOReturnNotPermitted; 2134 } 2135 break; 2136 default: 2137 err = kIOReturnBadArgument; 2138 } 2139 2140 if (newConnect) { 2141 if ((false == newConnect->attach(this)) 2142 || (false == newConnect->start(this))) { 2143 newConnect->detach( this ); 2144 newConnect->release(); 2145 err = kIOReturnNotPermitted; 2146 } else { 2147 theConnect = newConnect; 2148 } 2149 } 2150 2151 *handler = theConnect; 2152 return err; 2153 } 2154 2155 void 2156 IOPlatformExpertDevice::free() 2157 { 2158 if (workLoop) { 2159 workLoop->release(); 2160 } 2161 } 2162 2163 void 2164 IOPlatformExpertDevice::configureDefaults( void ) 2165 { 2166 createNVRAM(); 2167 // Parse the serial-number data and publish a user-readable string 2168 OSData* mydata = (OSData*) (getProperty("serial-number")); 2169 if (mydata != NULL) { 2170 OSString *serNoString = OSString::withCString((const char *)mydata->getBytesNoCopy()); 2171 if (serNoString != NULL) { 2172 setProperty(kIOPlatformSerialNumberKey, serNoString); 2173 serNoString->release(); 2174 } 2175 } 2176 generatePlatformUUID(); 2177 } 2178 2179 void 2180 IOPlatformExpertDevice::createNVRAM( void ) 2181 { 2182 /* 2183 * Publish an IODTNVRAM class on /options, if present. 2184 * DT-based platforms may need NVRAM access prior to the start 2185 * of IOKit matching, to support security-related operations 2186 * that must happen before machine_lockdown(). 2187 */ 2188 IORegistryEntry *options = IORegistryEntry::fromPath("/options", gIODTPlane); 2189 if (options == NULL) { 2190 return; // /options may not be present 2191 } 2192 2193 assert(gIOOptionsEntry == NULL); 2194 gIOOptionsEntry = new IODTNVRAM; 2195 2196 assert(gIOOptionsEntry != NULL); 2197 2198 gIOOptionsEntry->init(options, gIODTPlane); 2199 gIOOptionsEntry->attach(this); 2200 gIOOptionsEntry->start(this); 2201 options->release(); 2202 } 2203 2204 void 2205 IOPlatformExpertDevice::generatePlatformUUID( void ) 2206 { 2207 IORegistryEntry * entry; 2208 OSString * string = NULL; 2209 uuid_string_t uuid; 2210 2211 #if !defined(__x86_64__) 2212 entry = IORegistryEntry::fromPath( "/chosen", gIODTPlane ); 2213 if (entry) { 2214 OSData * data1; 2215 2216 data1 = OSDynamicCast( OSData, entry->getProperty( "unique-chip-id" )); 2217 if (data1 && data1->getLength() == 8) { 2218 OSData * data2; 2219 2220 data2 = OSDynamicCast( OSData, entry->getProperty( "chip-id" )); 2221 if (data2 && data2->getLength() == 4) { 2222 SHA1_CTX context; 2223 uint8_t digest[SHA_DIGEST_LENGTH]; 2224 const uuid_t space = { 0xA6, 0xDD, 0x4C, 0xCB, 0xB5, 0xE8, 0x4A, 0xF5, 0xAC, 0xDD, 0xB6, 0xDC, 0x6A, 0x05, 0x42, 0xB8 }; 2225 2226 SHA1Init( &context ); 2227 SHA1Update( &context, space, sizeof(space)); 2228 SHA1Update( &context, data1->getBytesNoCopy(), data1->getLength()); 2229 SHA1Update( &context, data2->getBytesNoCopy(), data2->getLength()); 2230 SHA1Final( digest, &context ); 2231 2232 digest[6] = (digest[6] & 0x0F) | 0x50; 2233 digest[8] = (digest[8] & 0x3F) | 0x80; 2234 2235 uuid_unparse( digest, uuid ); 2236 string = OSString::withCString( uuid ); 2237 } 2238 } 2239 2240 entry->release(); 2241 } 2242 #else /* !defined(__x86_64__) */ 2243 OSData * data; 2244 2245 entry = IORegistryEntry::fromPath( "/efi/platform", gIODTPlane ); 2246 if (entry) { 2247 data = OSDynamicCast( OSData, entry->getProperty( "system-id" )); 2248 if (data && data->getLength() == 16) { 2249 SHA1_CTX context; 2250 uint8_t digest[SHA_DIGEST_LENGTH]; 2251 const uuid_t space = { 0x2A, 0x06, 0x19, 0x90, 0xD3, 0x8D, 0x44, 0x40, 0xA1, 0x39, 0xC4, 0x97, 0x70, 0x37, 0x65, 0xAC }; 2252 2253 SHA1Init( &context ); 2254 SHA1Update( &context, space, sizeof(space)); 2255 SHA1Update( &context, data->getBytesNoCopy(), data->getLength()); 2256 SHA1Final( digest, &context ); 2257 2258 digest[6] = (digest[6] & 0x0F) | 0x50; 2259 digest[8] = (digest[8] & 0x3F) | 0x80; 2260 2261 uuid_unparse( digest, uuid ); 2262 string = OSString::withCString( uuid ); 2263 } 2264 2265 entry->release(); 2266 } 2267 if (!string) { 2268 /* vmware still runs this path */ 2269 entry = IORegistryEntry::fromPath( "/options", gIODTPlane ); 2270 if (entry) { 2271 data = OSDynamicCast( OSData, entry->getProperty( "platform-uuid" )); 2272 if (data && data->getLength() == sizeof(uuid_t)) { 2273 uuid_unparse((uint8_t *) data->getBytesNoCopy(), uuid ); 2274 string = OSString::withCString( uuid ); 2275 } 2276 entry->release(); 2277 } 2278 } 2279 #endif /* defined(__x86_64__) */ 2280 2281 if (string) { 2282 setProperty( kIOPlatformUUIDKey, string ); 2283 gIOPlatformUUIDAndSerialDone = true; 2284 2285 string->release(); 2286 } 2287 } 2288 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 2289 2290 #undef super 2291 #define super IOService 2292 2293 OSDefineMetaClassAndStructors(IOPlatformDevice, IOService) 2294 2295 OSMetaClassDefineReservedUnused(IOPlatformDevice, 0); 2296 OSMetaClassDefineReservedUnused(IOPlatformDevice, 1); 2297 OSMetaClassDefineReservedUnused(IOPlatformDevice, 2); 2298 OSMetaClassDefineReservedUnused(IOPlatformDevice, 3); 2299 2300 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 2301 2302 bool 2303 IOPlatformDevice::compareName( OSString * name, 2304 OSString ** matched ) const 2305 { 2306 return ((IOPlatformExpert *)getProvider())-> 2307 compareNubName( this, name, matched ); 2308 } 2309 2310 IOService * 2311 IOPlatformDevice::matchLocation( IOService * /* client */ ) 2312 { 2313 return this; 2314 } 2315 2316 IOReturn 2317 IOPlatformDevice::getResources( void ) 2318 { 2319 return ((IOPlatformExpert *)getProvider())->getNubResources( this ); 2320 } 2321 2322 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 2323 2324 /********************************************************************* 2325 * IOPanicPlatform class 2326 * 2327 * If no legitimate IOPlatformDevice matches, this one does and panics 2328 * the kernel with a suitable message. 2329 *********************************************************************/ 2330 2331 class IOPanicPlatform : IOPlatformExpert { 2332 OSDeclareDefaultStructors(IOPanicPlatform); 2333 2334 public: 2335 bool start(IOService * provider) APPLE_KEXT_OVERRIDE; 2336 }; 2337 2338 2339 OSDefineMetaClassAndStructors(IOPanicPlatform, IOPlatformExpert); 2340 2341 2342 bool 2343 IOPanicPlatform::start(IOService * provider) 2344 { 2345 const char * platform_name = "(unknown platform name)"; 2346 2347 if (provider) { 2348 platform_name = provider->getName(); 2349 } 2350 2351 panic("Unable to find driver for this platform: \"%s\".", 2352 platform_name); 2353 2354 return false; 2355 } 2356