1/* 2 * Copyright (c) 1998-2008 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#include <libkern/c++/OSKext.h> 29#include <libkern/c++/OSMetaClass.h> 30#include <libkern/OSAtomic.h> 31#include <libkern/OSDebug.h> 32#include <IOKit/IOWorkLoop.h> 33#include <IOKit/IOCommandGate.h> 34#include <IOKit/IOPlatformExpert.h> 35#include <IOKit/IOCPU.h> 36#include <IOKit/IOKitDebug.h> 37#include <IOKit/IOTimeStamp.h> 38#include <IOKit/pwr_mgt/IOPMlog.h> 39#include <IOKit/pwr_mgt/RootDomain.h> 40#include <IOKit/pwr_mgt/IOPMPrivate.h> 41#include <IOKit/IODeviceTreeSupport.h> 42#include <IOKit/IOMessage.h> 43#include <IOKit/IOReturn.h> 44#include <IOKit/IONVRAM.h> 45#include "RootDomainUserClient.h" 46#include "IOKit/pwr_mgt/IOPowerConnection.h" 47#include "IOPMPowerStateQueue.h" 48#include <IOKit/IOCatalogue.h> 49#include <IOKit/IOReportMacros.h> 50#if HIBERNATION 51#include <IOKit/IOHibernatePrivate.h> 52#endif 53#include <console/video_console.h> 54#include <sys/syslog.h> 55#include <sys/sysctl.h> 56#include <sys/vnode.h> 57#include <sys/vnode_internal.h> 58#include <sys/fcntl.h> 59 60#include <sys/time.h> 61#include "IOServicePrivate.h" // _IOServiceInterestNotifier 62#include "IOServicePMPrivate.h" 63 64__BEGIN_DECLS 65#include <mach/shared_region.h> 66__END_DECLS 67 68#if defined(__i386__) || defined(__x86_64__) 69__BEGIN_DECLS 70#include "IOPMrootDomainInternal.h" 71__END_DECLS 72#endif 73 74#define kIOPMrootDomainClass "IOPMrootDomain" 75#define LOG_PREFIX "PMRD: " 76 77 78#define MSG(x...) \ 79 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false) 80 81#define LOG(x...) \ 82 do { kprintf(LOG_PREFIX x); } while (false) 83 84#define DLOG(x...) do { \ 85 if (kIOLogPMRootDomain & gIOKitDebug) \ 86 kprintf(LOG_PREFIX x); \ 87} while (false) 88 89#define DMSG(x...) do { \ 90 if (kIOLogPMRootDomain & gIOKitDebug) { \ 91 kprintf(LOG_PREFIX x); IOLog(x); \ 92 } \ 93} while (false) 94 95 96#define _LOG(x...) 97 98#define CHECK_THREAD_CONTEXT 99#ifdef CHECK_THREAD_CONTEXT 100static IOWorkLoop * gIOPMWorkLoop = 0; 101#define ASSERT_GATED() \ 102do { \ 103 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \ 104 panic("RootDomain: not inside PM gate"); \ 105 } \ 106} while(false) 107#else 108#define ASSERT_GATED() 109#endif /* CHECK_THREAD_CONTEXT */ 110 111#define CAP_LOSS(c) \ 112 (((_pendingCapability & (c)) == 0) && \ 113 ((_currentCapability & (c)) != 0)) 114 115#define CAP_GAIN(c) \ 116 (((_currentCapability & (c)) == 0) && \ 117 ((_pendingCapability & (c)) != 0)) 118 119#define CAP_CHANGE(c) \ 120 (((_currentCapability ^ _pendingCapability) & (c)) != 0) 121 122#define CAP_CURRENT(c) \ 123 ((_currentCapability & (c)) != 0) 124 125#define CAP_HIGHEST(c) \ 126 ((_highestCapability & (c)) != 0) 127 128#if defined(__i386__) || defined(__x86_64__) 129#define DARK_TO_FULL_EVALUATE_CLAMSHELL 1 130#endif 131 132// Event types for IOPMPowerStateQueue::submitPowerEvent() 133enum { 134 kPowerEventFeatureChanged = 1, // 1 135 kPowerEventReceivedPowerNotification, // 2 136 kPowerEventSystemBootCompleted, // 3 137 kPowerEventSystemShutdown, // 4 138 kPowerEventUserDisabledSleep, // 5 139 kPowerEventRegisterSystemCapabilityClient, // 6 140 kPowerEventRegisterKernelCapabilityClient, // 7 141 kPowerEventPolicyStimulus, // 8 142 kPowerEventAssertionCreate, // 9 143 kPowerEventAssertionRelease, // 10 144 kPowerEventAssertionSetLevel, // 11 145 kPowerEventQueueSleepWakeUUID, // 12 146 kPowerEventPublishSleepWakeUUID, // 13 147 kPowerEventSetDisplayPowerOn // 14 148}; 149 150// For evaluatePolicy() 151// List of stimuli that affects the root domain policy. 152enum { 153 kStimulusDisplayWranglerSleep, // 0 154 kStimulusDisplayWranglerWake, // 1 155 kStimulusAggressivenessChanged, // 2 156 kStimulusDemandSystemSleep, // 3 157 kStimulusAllowSystemSleepChanged, // 4 158 kStimulusDarkWakeActivityTickle, // 5 159 kStimulusDarkWakeEntry, // 6 160 kStimulusDarkWakeReentry, // 7 161 kStimulusDarkWakeEvaluate, // 8 162 kStimulusNoIdleSleepPreventers, // 9 163 kStimulusEnterUserActiveState, // 10 164 kStimulusLeaveUserActiveState // 11 165}; 166 167extern "C" { 168IOReturn OSKextSystemSleepOrWake( UInt32 ); 169} 170extern "C" ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va); 171extern "C" addr64_t kvtophys(vm_offset_t va); 172extern "C" int stack_snapshot_from_kernel(pid_t pid, void *buf, uint32_t size, uint32_t flags, unsigned *bytesTraced); 173 174static void idleSleepTimerExpired( thread_call_param_t, thread_call_param_t ); 175static void notifySystemShutdown( IOService * root, unsigned long event ); 176static void handleAggressivesFunction( thread_call_param_t, thread_call_param_t ); 177static void pmEventTimeStamp(uint64_t *recordTS); 178 179// "IOPMSetSleepSupported" callPlatformFunction name 180static const OSSymbol *sleepSupportedPEFunction = NULL; 181static const OSSymbol *sleepMessagePEFunction = NULL; 182 183#define kIOSleepSupportedKey "IOSleepSupported" 184#define kIOPMSystemCapabilitiesKey "System Capabilities" 185 186#define kIORequestWranglerIdleKey "IORequestIdle" 187#define kDefaultWranglerIdlePeriod 25 // in milliseconds 188 189#define kIOSleepWakeDebugKey "Persistent-memory-note" 190 191#define kRD_AllPowerSources (kIOPMSupportedOnAC \ 192 | kIOPMSupportedOnBatt \ 193 | kIOPMSupportedOnUPS) 194 195enum 196{ 197 // not idle around autowake time, secs 198 kAutoWakePreWindow = 45, 199 kAutoWakePostWindow = 15 200}; 201 202#define kLocalEvalClamshellCommand (1 << 15) 203#define kIdleSleepRetryInterval (3 * 60) 204 205enum { 206 kWranglerPowerStateMin = 0, 207 kWranglerPowerStateSleep = 2, 208 kWranglerPowerStateDim = 3, 209 kWranglerPowerStateMax = 4 210}; 211 212enum { 213 OFF_STATE = 0, 214 RESTART_STATE = 1, 215 SLEEP_STATE = 2, 216 ON_STATE = 3, 217 NUM_POWER_STATES 218}; 219 220#define ON_POWER kIOPMPowerOn 221#define RESTART_POWER kIOPMRestart 222#define SLEEP_POWER kIOPMAuxPowerOn 223 224static IOPMPowerState ourPowerStates[NUM_POWER_STATES] = 225{ 226 {1, 0, 0, 0, 0,0,0,0,0,0,0,0}, 227 {1, kIOPMRestartCapability, kIOPMRestart, RESTART_POWER, 0,0,0,0,0,0,0,0}, 228 {1, kIOPMSleepCapability, kIOPMSleep, SLEEP_POWER, 0,0,0,0,0,0,0,0}, 229 {1, kIOPMPowerOn, kIOPMPowerOn, ON_POWER, 0,0,0,0,0,0,0,0} 230}; 231 232#define kIOPMRootDomainWakeTypeSleepService "SleepService" 233#define kIOPMRootDomainWakeTypeMaintenance "Maintenance" 234#define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer" 235#define kIOPMrootDomainWakeTypeLowBattery "LowBattery" 236#define kIOPMRootDomainWakeTypeUser "User" 237#define kIOPMRootDomainWakeTypeAlarm "Alarm" 238#define kIOPMRootDomainWakeTypeNetwork "Network" 239#define kIOPMRootDomainWakeTypeHIDActivity "HID Activity" 240#define kIOPMRootDomainWakeTypeNotification "Notification" 241#define kIOPMRootDomainWakeTypeHibernateError "HibernateError" 242 243// Special interest that entitles the interested client from receiving 244// all system messages. Only used by powerd. 245// 246#define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest" 247 248#define WAKEEVENT_LOCK() IOLockLock(wakeEventLock) 249#define WAKEEVENT_UNLOCK() IOLockUnlock(wakeEventLock) 250 251/* 252 * Aggressiveness 253 */ 254#define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock) 255#define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock) 256 257#define kAggressivesMinValue 1 258 259enum { 260 kAggressivesStateBusy = 0x01, 261 kAggressivesStateQuickSpindown = 0x02 262}; 263 264struct AggressivesRecord { 265 uint32_t flags; 266 uint32_t type; 267 uint32_t value; 268}; 269 270struct AggressivesRequest { 271 queue_chain_t chain; 272 uint32_t options; 273 uint32_t dataType; 274 union { 275 IOService * service; 276 AggressivesRecord record; 277 } data; 278}; 279 280enum { 281 kAggressivesRequestTypeService = 1, 282 kAggressivesRequestTypeRecord 283}; 284 285enum { 286 kAggressivesOptionSynchronous = 0x00000001, 287 kAggressivesOptionQuickSpindownEnable = 0x00000100, 288 kAggressivesOptionQuickSpindownDisable = 0x00000200, 289 kAggressivesOptionQuickSpindownMask = 0x00000300 290}; 291 292enum { 293 kAggressivesRecordFlagModified = 0x00000001, 294 kAggressivesRecordFlagMinValue = 0x00000002 295}; 296 297// gDarkWakeFlags 298enum { 299 kDarkWakeFlagHIDTickleEarly = 0x01, // hid tickle before gfx suppression 300 kDarkWakeFlagHIDTickleLate = 0x02, // hid tickle after gfx suppression 301 kDarkWakeFlagHIDTickleNone = 0x03, // hid tickle is not posted 302 kDarkWakeFlagHIDTickleMask = 0x03, 303 kDarkWakeFlagAlarmIsDark = 0x0100, 304 kDarkWakeFlagGraphicsPowerState1 = 0x0200, 305 kDarkWakeFlagAudioNotSuppressed = 0x0400 306}; 307 308static IOPMrootDomain * gRootDomain; 309static IONotifier * gSysPowerDownNotifier = 0; 310static UInt32 gSleepOrShutdownPending = 0; 311static UInt32 gWillShutdown = 0; 312static UInt32 gPagingOff = 0; 313static UInt32 gSleepWakeUUIDIsSet = false; 314static uint32_t gAggressivesState = 0; 315 316uuid_string_t bootsessionuuid_string; 317 318static uint32_t gDarkWakeFlags = kDarkWakeFlagHIDTickleNone; 319static PMStatsStruct gPMStats; 320 321#if HIBERNATION 322static IOPMSystemSleepPolicyHandler gSleepPolicyHandler = 0; 323static IOPMSystemSleepPolicyVariables * gSleepPolicyVars = 0; 324static void * gSleepPolicyTarget; 325#endif 326 327struct timeval gIOLastSleepTime; 328struct timeval gIOLastWakeTime; 329 330static char gWakeReasonString[128]; 331static bool gWakeReasonSysctlRegistered = false; 332 333// Constants used as arguments to IOPMrootDomain::informCPUStateChange 334#define kCPUUnknownIndex 9999999 335enum { 336 kInformAC = 0, 337 kInformLid = 1, 338 kInformableCount = 2 339}; 340 341const OSSymbol *gIOPMStatsApplicationResponseTimedOut; 342const OSSymbol *gIOPMStatsApplicationResponseCancel; 343const OSSymbol *gIOPMStatsApplicationResponseSlow; 344const OSSymbol *gIOPMStatsApplicationResponsePrompt; 345const OSSymbol *gIOPMStatsDriverPSChangeSlow; 346 347#define kBadPMFeatureID 0 348 349/* 350 * PMSettingHandle 351 * Opaque handle passed to clients of registerPMSettingController() 352 */ 353class PMSettingHandle : public OSObject 354{ 355 OSDeclareFinalStructors( PMSettingHandle ) 356 friend class PMSettingObject; 357 358private: 359 PMSettingObject *pmso; 360 void free(void); 361}; 362 363/* 364 * PMSettingObject 365 * Internal object to track each PM setting controller 366 */ 367class PMSettingObject : public OSObject 368{ 369 OSDeclareFinalStructors( PMSettingObject ) 370 friend class IOPMrootDomain; 371 372private: 373 queue_head_t calloutQueue; 374 thread_t waitThread; 375 IOPMrootDomain *parent; 376 PMSettingHandle *pmsh; 377 IOPMSettingControllerCallback func; 378 OSObject *target; 379 uintptr_t refcon; 380 uint32_t *publishedFeatureID; 381 uint32_t settingCount; 382 bool disabled; 383 384 void free(void); 385 386public: 387 static PMSettingObject *pmSettingObject( 388 IOPMrootDomain *parent_arg, 389 IOPMSettingControllerCallback handler_arg, 390 OSObject *target_arg, 391 uintptr_t refcon_arg, 392 uint32_t supportedPowerSources, 393 const OSSymbol *settings[], 394 OSObject **handle_obj); 395 396 void dispatchPMSetting(const OSSymbol *type, OSObject *object); 397 void clientHandleFreed(void); 398}; 399 400struct PMSettingCallEntry { 401 queue_chain_t link; 402 thread_t thread; 403}; 404 405#define PMSETTING_LOCK() IOLockLock(settingsCtrlLock) 406#define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock) 407#define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT) 408#define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true) 409 410/* 411 * PMTraceWorker 412 * Internal helper object for logging trace points to RTC 413 * IOPMrootDomain and only IOPMrootDomain should instantiate 414 * exactly one of these. 415 */ 416 417typedef void (*IOPMTracePointHandler)( 418 void * target, uint32_t code, uint32_t data ); 419 420class PMTraceWorker : public OSObject 421{ 422 OSDeclareDefaultStructors(PMTraceWorker) 423public: 424 typedef enum { kPowerChangeStart, kPowerChangeCompleted } change_t; 425 426 static PMTraceWorker *tracer( IOPMrootDomain * ); 427 void tracePCIPowerChange(change_t, IOService *, uint32_t, uint32_t); 428 void tracePoint(uint8_t phase); 429 void tracePoint(uint8_t phase, uint8_t data8); 430 void traceDetail(uint32_t detail); 431 void traceLoginWindowPhase(uint8_t phase); 432 int recordTopLevelPCIDevice(IOService *); 433 void RTC_TRACE(void); 434 virtual bool serialize(OSSerialize *s) const; 435 436 IOPMTracePointHandler tracePointHandler; 437 void * tracePointTarget; 438 uint64_t getPMStatusCode(); 439private: 440 IOPMrootDomain *owner; 441 IOLock *pciMappingLock; 442 OSArray *pciDeviceBitMappings; 443 444 uint8_t addedToRegistry; 445 uint8_t tracePhase; 446 uint8_t loginWindowPhase; 447 uint8_t traceData8; 448 uint32_t traceData32; 449}; 450 451/* 452 * PMAssertionsTracker 453 * Tracks kernel and user space PM assertions 454 */ 455class PMAssertionsTracker : public OSObject 456{ 457 OSDeclareFinalStructors(PMAssertionsTracker) 458public: 459 static PMAssertionsTracker *pmAssertionsTracker( IOPMrootDomain * ); 460 461 IOReturn createAssertion(IOPMDriverAssertionType, IOPMDriverAssertionLevel, IOService *, const char *, IOPMDriverAssertionID *); 462 IOReturn releaseAssertion(IOPMDriverAssertionID); 463 IOReturn setAssertionLevel(IOPMDriverAssertionID, IOPMDriverAssertionLevel); 464 IOReturn setUserAssertionLevels(IOPMDriverAssertionType); 465 466 OSArray *copyAssertionsArray(void); 467 IOPMDriverAssertionType getActivatedAssertions(void); 468 IOPMDriverAssertionLevel getAssertionLevel(IOPMDriverAssertionType); 469 470 IOReturn handleCreateAssertion(OSData *); 471 IOReturn handleReleaseAssertion(IOPMDriverAssertionID); 472 IOReturn handleSetAssertionLevel(IOPMDriverAssertionID, IOPMDriverAssertionLevel); 473 IOReturn handleSetUserAssertionLevels(void * arg0); 474 void publishProperties(void); 475 476private: 477 typedef struct { 478 IOPMDriverAssertionID id; 479 IOPMDriverAssertionType assertionBits; 480 uint64_t createdTime; 481 uint64_t modifiedTime; 482 const OSSymbol *ownerString; 483 IOService *ownerService; 484 uint64_t registryEntryID; 485 IOPMDriverAssertionLevel level; 486 } PMAssertStruct; 487 488 uint32_t tabulateProducerCount; 489 uint32_t tabulateConsumerCount; 490 491 PMAssertStruct *detailsForID(IOPMDriverAssertionID, int *); 492 void tabulate(void); 493 494 IOPMrootDomain *owner; 495 OSArray *assertionsArray; 496 IOLock *assertionsArrayLock; 497 IOPMDriverAssertionID issuingUniqueID __attribute__((aligned(8))); /* aligned for atomic access */ 498 IOPMDriverAssertionType assertionsKernel; 499 IOPMDriverAssertionType assertionsUser; 500 IOPMDriverAssertionType assertionsCombined; 501}; 502 503OSDefineMetaClassAndFinalStructors(PMAssertionsTracker, OSObject); 504 505/* 506 * PMHaltWorker 507 * Internal helper object for Shutdown/Restart notifications. 508 */ 509#define kPMHaltMaxWorkers 8 510#define kPMHaltTimeoutMS 100 511 512class PMHaltWorker : public OSObject 513{ 514 OSDeclareFinalStructors( PMHaltWorker ) 515 516public: 517 IOService * service; // service being worked on 518 AbsoluteTime startTime; // time when work started 519 int depth; // work on nubs at this PM-tree depth 520 int visits; // number of nodes visited (debug) 521 IOLock * lock; 522 bool timeout; // service took too long 523 524 static PMHaltWorker * worker( void ); 525 static void main( void * arg, wait_result_t waitResult ); 526 static void work( PMHaltWorker * me ); 527 static void checkTimeout( PMHaltWorker * me, AbsoluteTime * now ); 528 virtual void free( void ); 529}; 530 531OSDefineMetaClassAndFinalStructors( PMHaltWorker, OSObject ) 532 533 534#define super IOService 535OSDefineMetaClassAndFinalStructors(IOPMrootDomain, IOService) 536 537static void IOPMRootDomainWillShutdown(void) 538{ 539 if (OSCompareAndSwap(0, 1, &gWillShutdown)) 540 { 541 OSKext::willShutdown(); 542 for (int i = 0; i < 100; i++) 543 { 544 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending)) break; 545 IOSleep( 100 ); 546 } 547 } 548} 549 550extern "C" 551{ 552 IONotifier * registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref) 553 { 554 return gRootDomain->registerInterest( gIOGeneralInterest, handler, self, ref ); 555 } 556 557 IONotifier * registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref) 558 { 559 return gRootDomain->registerInterest( gIOPriorityPowerStateInterest, handler, self, ref ); 560 } 561 562 IOReturn acknowledgeSleepWakeNotification(void * PMrefcon) 563 { 564 return gRootDomain->allowPowerChange ( (unsigned long)PMrefcon ); 565 } 566 567 IOReturn vetoSleepWakeNotification(void * PMrefcon) 568 { 569 return gRootDomain->cancelPowerChange ( (unsigned long)PMrefcon ); 570 } 571 572 IOReturn rootDomainRestart ( void ) 573 { 574 return gRootDomain->restartSystem(); 575 } 576 577 IOReturn rootDomainShutdown ( void ) 578 { 579 return gRootDomain->shutdownSystem(); 580 } 581 582 void IOSystemShutdownNotification(void) 583 { 584 IOPMRootDomainWillShutdown(); 585 if (OSCompareAndSwap(0, 1, &gPagingOff)) 586 { 587 gRootDomain->handlePlatformHaltRestart(kPEPagingOff); 588 } 589 } 590 591 int sync_internal(void); 592} 593 594/* 595A device is always in the highest power state which satisfies its driver, 596its policy-maker, and any power children it has, but within the constraint 597of the power state provided by its parent. The driver expresses its desire by 598calling changePowerStateTo(), the policy-maker expresses its desire by calling 599changePowerStateToPriv(), and the children express their desires by calling 600requestPowerDomainState(). 601 602The Root Power Domain owns the policy for idle and demand sleep for the system. 603It is a power-managed IOService just like the others in the system. 604It implements several power states which map to what we see as Sleep and On. 605 606The sleep policy is as follows: 6071. Sleep is prevented if the case is open so that nobody will think the machine 608 is off and plug/unplug cards. 6092. Sleep is prevented if the sleep timeout slider in the prefs panel is zero. 6103. System cannot Sleep if some object in the tree is in a power state marked 611 kIOPMPreventSystemSleep. 612 613These three conditions are enforced using the "driver clamp" by calling 614changePowerStateTo(). For example, if the case is opened, 615changePowerStateTo(ON_STATE) is called to hold the system on regardless 616of the desires of the children of the root or the state of the other clamp. 617 618Demand Sleep is initiated by pressing the front panel power button, closing 619the clamshell, or selecting the menu item. In this case the root's parent 620actually initiates the power state change so that the root domain has no 621choice and does not give applications the opportunity to veto the change. 622 623Idle Sleep occurs if no objects in the tree are in a state marked 624kIOPMPreventIdleSleep. When this is true, the root's children are not holding 625the root on, so it sets the "policy-maker clamp" by calling 626changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires. 627This timer is set for the difference between the sleep timeout slider and the 628display dim timeout slider. When the timer expires, it releases its clamp and 629now nothing is holding it awake, so it falls asleep. 630 631Demand sleep is prevented when the system is booting. When preferences are 632transmitted by the loginwindow at the end of boot, a flag is cleared, 633and this allows subsequent Demand Sleep. 634*/ 635 636//****************************************************************************** 637 638IOPMrootDomain * IOPMrootDomain::construct( void ) 639{ 640 IOPMrootDomain *root; 641 642 root = new IOPMrootDomain; 643 if( root) 644 root->init(); 645 646 return( root ); 647} 648 649//****************************************************************************** 650 651static void disk_sync_callout( thread_call_param_t p0, thread_call_param_t p1 ) 652{ 653 IOService * rootDomain = (IOService *) p0; 654 uint32_t notifyRef = (uint32_t)(uintptr_t) p1; 655 uint32_t powerState = rootDomain->getPowerState(); 656 657 DLOG("disk_sync_callout ps=%u\n", powerState); 658 659 if (ON_STATE == powerState) 660 { 661 sync_internal(); 662 } 663#if HIBERNATION 664 else 665 { 666 IOHibernateSystemPostWake(); 667 } 668#endif 669 670 rootDomain->allowPowerChange(notifyRef); 671 DLOG("disk_sync_callout finish\n"); 672} 673 674//****************************************************************************** 675 676static void hib_debugSetup_callout( thread_call_param_t p0, thread_call_param_t p1 ) 677{ 678 IOService * rootDomain = (IOService *) p0; 679 uint32_t notifyRef = (uint32_t)(uintptr_t) p1; 680 681#if HIBERNATION 682 IOHibernateOpenForDebugData(); 683#endif 684 685 rootDomain->allowPowerChange(notifyRef); 686 DLOG("hib_debugSetup_callout finish\n"); 687} 688//****************************************************************************** 689 690static UInt32 computeDeltaTimeMS( const AbsoluteTime * startTime ) 691{ 692 AbsoluteTime endTime; 693 UInt64 nano = 0; 694 695 clock_get_uptime(&endTime); 696 if (CMP_ABSOLUTETIME(&endTime, startTime) > 0) 697 { 698 SUB_ABSOLUTETIME(&endTime, startTime); 699 absolutetime_to_nanoseconds(endTime, &nano); 700 } 701 702 return (UInt32)(nano / 1000000ULL); 703} 704 705//****************************************************************************** 706 707static int 708sysctl_sleepwaketime SYSCTL_HANDLER_ARGS 709{ 710 struct timeval *swt = (struct timeval *)arg1; 711 struct proc *p = req->p; 712 713 if (p == kernproc) { 714 return sysctl_io_opaque(req, swt, sizeof(*swt), NULL); 715 } else if(proc_is64bit(p)) { 716 struct user64_timeval t; 717 t.tv_sec = swt->tv_sec; 718 t.tv_usec = swt->tv_usec; 719 return sysctl_io_opaque(req, &t, sizeof(t), NULL); 720 } else { 721 struct user32_timeval t; 722 t.tv_sec = swt->tv_sec; 723 t.tv_usec = swt->tv_usec; 724 return sysctl_io_opaque(req, &t, sizeof(t), NULL); 725 } 726} 727 728static SYSCTL_PROC(_kern, OID_AUTO, sleeptime, 729 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED, 730 &gIOLastSleepTime, 0, sysctl_sleepwaketime, "S,timeval", ""); 731 732static SYSCTL_PROC(_kern, OID_AUTO, waketime, 733 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED, 734 &gIOLastWakeTime, 0, sysctl_sleepwaketime, "S,timeval", ""); 735 736 737static int 738sysctl_willshutdown 739(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req) 740{ 741 int new_value, changed; 742 int error = sysctl_io_number(req, gWillShutdown, sizeof(int), &new_value, &changed); 743 if (changed) { 744 if (!gWillShutdown && (new_value == 1)) { 745 IOPMRootDomainWillShutdown(); 746 } else 747 error = EINVAL; 748 } 749 return(error); 750} 751 752static SYSCTL_PROC(_kern, OID_AUTO, willshutdown, 753 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED, 754 0, 0, sysctl_willshutdown, "I", ""); 755 756 757static int 758sysctl_progressmeterenable 759(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req) 760{ 761 int error; 762 int new_value, changed; 763 764 error = sysctl_io_number(req, vc_progressmeter_enable, sizeof(int), &new_value, &changed); 765 766 if (changed) vc_enable_progressmeter(new_value); 767 768 return (error); 769} 770 771static int 772sysctl_progressmeter 773(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req) 774{ 775 int error; 776 int new_value, changed; 777 778 error = sysctl_io_number(req, vc_progressmeter_value, sizeof(int), &new_value, &changed); 779 780 if (changed) vc_set_progressmeter(new_value); 781 782 return (error); 783} 784 785static SYSCTL_PROC(_kern, OID_AUTO, progressmeterenable, 786 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED, 787 0, 0, sysctl_progressmeterenable, "I", ""); 788 789static SYSCTL_PROC(_kern, OID_AUTO, progressmeter, 790 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED, 791 0, 0, sysctl_progressmeter, "I", ""); 792 793 794static int 795sysctl_wakereason SYSCTL_HANDLER_ARGS 796{ 797 char wr[ sizeof(gWakeReasonString) ]; 798 799 wr[0] = '\0'; 800 if (gRootDomain) 801 gRootDomain->copyWakeReasonString(wr, sizeof(wr)); 802 803 return sysctl_io_string(req, wr, 0, 0, NULL); 804} 805 806SYSCTL_PROC(_kern, OID_AUTO, wakereason, 807 CTLTYPE_STRING| CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED, 808 NULL, 0, sysctl_wakereason, "A", "wakereason"); 809 810static SYSCTL_INT(_debug, OID_AUTO, darkwake, CTLFLAG_RW, &gDarkWakeFlags, 0, ""); 811 812static const OSSymbol * gIOPMSettingAutoWakeCalendarKey; 813static const OSSymbol * gIOPMSettingAutoWakeSecondsKey; 814static const OSSymbol * gIOPMSettingDebugWakeRelativeKey; 815static const OSSymbol * gIOPMSettingMaintenanceWakeCalendarKey; 816static const OSSymbol * gIOPMSettingSleepServiceWakeCalendarKey; 817static const OSSymbol * gIOPMSettingSilentRunningKey; 818static const OSSymbol * gIOPMUserTriggeredFullWakeKey; 819static const OSSymbol * gIOPMUserIsActiveKey; 820 821//****************************************************************************** 822// start 823// 824//****************************************************************************** 825 826#define kRootDomainSettingsCount 17 827 828bool IOPMrootDomain::start( IOService * nub ) 829{ 830 OSIterator *psIterator; 831 OSDictionary *tmpDict; 832 IORootParent * patriarch; 833#if defined(__i386__) || defined(__x86_64__) 834 IONotifier * notifier; 835#endif 836 837 super::start(nub); 838 839 gRootDomain = this; 840 gIOPMSettingAutoWakeCalendarKey = OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey); 841 gIOPMSettingAutoWakeSecondsKey = OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey); 842 gIOPMSettingDebugWakeRelativeKey = OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey); 843 gIOPMSettingMaintenanceWakeCalendarKey = OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey); 844 gIOPMSettingSleepServiceWakeCalendarKey = OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey); 845 gIOPMSettingSilentRunningKey = OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey); 846 gIOPMUserTriggeredFullWakeKey = OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey); 847 gIOPMUserIsActiveKey = OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey); 848 849 gIOPMStatsApplicationResponseTimedOut = OSSymbol::withCString(kIOPMStatsResponseTimedOut); 850 gIOPMStatsApplicationResponseCancel = OSSymbol::withCString(kIOPMStatsResponseCancel); 851 gIOPMStatsApplicationResponseSlow = OSSymbol::withCString(kIOPMStatsResponseSlow); 852 gIOPMStatsApplicationResponsePrompt = OSSymbol::withCString(kIOPMStatsResponsePrompt); 853 gIOPMStatsDriverPSChangeSlow = OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow); 854 855 sleepSupportedPEFunction = OSSymbol::withCString("IOPMSetSleepSupported"); 856 sleepMessagePEFunction = OSSymbol::withCString("IOPMSystemSleepMessage"); 857 858 const OSSymbol *settingsArr[kRootDomainSettingsCount] = 859 { 860 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey), 861 gIOPMSettingAutoWakeSecondsKey, 862 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey), 863 gIOPMSettingAutoWakeCalendarKey, 864 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey), 865 gIOPMSettingDebugWakeRelativeKey, 866 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey), 867 OSSymbol::withCString(kIOPMSettingWakeOnRingKey), 868 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey), 869 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey), 870 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey), 871 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey), 872 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey), 873 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey), 874 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey), 875 OSSymbol::withCString(kIOPMStateConsoleShutdown), 876 gIOPMSettingSilentRunningKey 877 }; 878 879 PE_parse_boot_argn("darkwake", &gDarkWakeFlags, sizeof(gDarkWakeFlags)); 880 881 queue_init(&aggressivesQueue); 882 aggressivesThreadCall = thread_call_allocate(handleAggressivesFunction, this); 883 aggressivesData = OSData::withCapacity( 884 sizeof(AggressivesRecord) * (kPMLastAggressivenessType + 4)); 885 886 featuresDictLock = IOLockAlloc(); 887 settingsCtrlLock = IOLockAlloc(); 888 wakeEventLock = IOLockAlloc(); 889 setPMRootDomain(this); 890 891 extraSleepTimer = thread_call_allocate( 892 idleSleepTimerExpired, 893 (thread_call_param_t) this); 894 895 diskSyncCalloutEntry = thread_call_allocate( 896 &disk_sync_callout, 897 (thread_call_param_t) this); 898 hibDebugSetupEntry = thread_call_allocate( 899 &hib_debugSetup_callout, 900 (thread_call_param_t) this); 901 902#if DARK_TO_FULL_EVALUATE_CLAMSHELL 903 fullWakeThreadCall = thread_call_allocate( 904 OSMemberFunctionCast(thread_call_func_t, this, 905 &IOPMrootDomain::fullWakeDelayedWork), 906 (thread_call_param_t) this); 907#endif 908 909 setProperty(kIOSleepSupportedKey, true); 910 911 bzero(&gPMStats, sizeof(gPMStats)); 912 913 pmTracer = PMTraceWorker::tracer(this); 914 915 pmAssertions = PMAssertionsTracker::pmAssertionsTracker(this); 916 917 userDisabledAllSleep = false; 918 systemBooting = true; 919 sleepSlider = 0; 920 idleSleepTimerPending = false; 921 wrangler = NULL; 922 clamshellClosed = false; 923 clamshellExists = false; 924 clamshellDisabled = true; 925 acAdaptorConnected = true; 926 clamshellSleepDisabled = false; 927 gWakeReasonString[0] = '\0'; 928 929 // Initialize to user active. 930 // Will never transition to user inactive w/o wrangler. 931 fullWakeReason = kFullWakeReasonLocalUser; 932 userIsActive = userWasActive = true; 933 setProperty(gIOPMUserIsActiveKey, kOSBooleanTrue); 934 935 // Set the default system capabilities at boot. 936 _currentCapability = kIOPMSystemCapabilityCPU | 937 kIOPMSystemCapabilityGraphics | 938 kIOPMSystemCapabilityAudio | 939 kIOPMSystemCapabilityNetwork; 940 941 _pendingCapability = _currentCapability; 942 _desiredCapability = _currentCapability; 943 _highestCapability = _currentCapability; 944 setProperty(kIOPMSystemCapabilitiesKey, _currentCapability, 64); 945 946 queuedSleepWakeUUIDString = NULL; 947 initializeBootSessionUUID(); 948 pmStatsAppResponses = OSArray::withCapacity(5); 949 _statsNameKey = OSSymbol::withCString(kIOPMStatsNameKey); 950 _statsPIDKey = OSSymbol::withCString(kIOPMStatsPIDKey); 951 _statsTimeMSKey = OSSymbol::withCString(kIOPMStatsTimeMSKey); 952 _statsResponseTypeKey = OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey); 953 _statsMessageTypeKey = OSSymbol::withCString(kIOPMStatsMessageTypeKey); 954 _statsPowerCapsKey = OSSymbol::withCString(kIOPMStatsPowerCapabilityKey); 955 956 pmStatsLock = IOLockAlloc(); 957 idxPMCPUClamshell = kCPUUnknownIndex; 958 idxPMCPULimitedPower = kCPUUnknownIndex; 959 960 tmpDict = OSDictionary::withCapacity(1); 961 setProperty(kRootDomainSupportedFeatures, tmpDict); 962 tmpDict->release(); 963 964 settingsCallbacks = OSDictionary::withCapacity(1); 965 966 // Create a list of the valid PM settings that we'll relay to 967 // interested clients in setProperties() => setPMSetting() 968 allowedPMSettings = OSArray::withObjects( 969 (const OSObject **)settingsArr, 970 kRootDomainSettingsCount, 971 0); 972 973 // List of PM settings that should not automatically publish itself 974 // as a feature when registered by a listener. 975 noPublishPMSettings = OSArray::withObjects( 976 (const OSObject **) &gIOPMSettingSilentRunningKey, 1, 0); 977 978 fPMSettingsDict = OSDictionary::withCapacity(5); 979 preventIdleSleepList = OSSet::withCapacity(8); 980 preventSystemSleepList = OSSet::withCapacity(2); 981 982 PMinit(); // creates gIOPMWorkLoop 983 984 // Create IOPMPowerStateQueue used to queue external power 985 // events, and to handle those events on the PM work loop. 986 pmPowerStateQueue = IOPMPowerStateQueue::PMPowerStateQueue( 987 this, OSMemberFunctionCast(IOEventSource::Action, this, 988 &IOPMrootDomain::dispatchPowerEvent)); 989 getPMworkloop()->addEventSource(pmPowerStateQueue); 990#ifdef CHECK_THREAD_CONTEXT 991 gIOPMWorkLoop = getPMworkloop(); 992#endif 993 994 // create our power parent 995 patriarch = new IORootParent; 996 patriarch->init(); 997 patriarch->attach(this); 998 patriarch->start(this); 999 patriarch->addPowerChild(this); 1000 1001 registerPowerDriver(this, ourPowerStates, NUM_POWER_STATES); 1002 changePowerStateToPriv(ON_STATE); 1003 1004 // install power change handler 1005 gSysPowerDownNotifier = registerPrioritySleepWakeInterest( &sysPowerDownHandler, this, 0); 1006 1007#if !NO_KERNEL_HID 1008 // Register for a notification when IODisplayWrangler is published 1009 if ((tmpDict = serviceMatching("IODisplayWrangler"))) 1010 { 1011 _displayWranglerNotifier = addMatchingNotification( 1012 gIOPublishNotification, tmpDict, 1013 (IOServiceMatchingNotificationHandler) &displayWranglerMatchPublished, 1014 this, 0); 1015 tmpDict->release(); 1016 } 1017#endif 1018 1019#if defined(__i386__) || defined(__x86_64__) 1020 1021 if ((tmpDict = serviceMatching("IODTNVRAM"))) 1022 { 1023 notifier = addMatchingNotification( 1024 gIOFirstPublishNotification, tmpDict, 1025 (IOServiceMatchingNotificationHandler) &IONVRAMMatchPublished, 1026 this, 0); 1027 tmpDict->release(); 1028 } 1029 1030 wranglerIdleSettings = NULL; 1031 OSNumber * wranglerIdlePeriod = NULL; 1032 wranglerIdleSettings = OSDictionary::withCapacity(1); 1033 wranglerIdlePeriod = OSNumber::withNumber(kDefaultWranglerIdlePeriod, 32); 1034 1035 if(wranglerIdleSettings && wranglerIdlePeriod) 1036 wranglerIdleSettings->setObject(kIORequestWranglerIdleKey, 1037 wranglerIdlePeriod); 1038 1039 if(wranglerIdlePeriod) 1040 wranglerIdlePeriod->release(); 1041#endif 1042 1043 const OSSymbol *ucClassName = OSSymbol::withCStringNoCopy("RootDomainUserClient"); 1044 setProperty(gIOUserClientClassKey, (OSObject *) ucClassName); 1045 ucClassName->release(); 1046 1047 // IOBacklightDisplay can take a long time to load at boot, or it may 1048 // not load at all if you're booting with clamshell closed. We publish 1049 // 'DisplayDims' here redundantly to get it published early and at all. 1050 psIterator = getMatchingServices( serviceMatching("IOPMPowerSource") ); 1051 if( psIterator && psIterator->getNextObject() ) 1052 { 1053 // There's at least one battery on the system, so we publish 1054 // 'DisplayDims' support for the LCD. 1055 publishFeature("DisplayDims"); 1056 } 1057 if(psIterator) { 1058 psIterator->release(); 1059 } 1060 1061 sysctl_register_oid(&sysctl__kern_sleeptime); 1062 sysctl_register_oid(&sysctl__kern_waketime); 1063 sysctl_register_oid(&sysctl__kern_willshutdown); 1064 sysctl_register_oid(&sysctl__kern_progressmeterenable); 1065 sysctl_register_oid(&sysctl__kern_progressmeter); 1066 sysctl_register_oid(&sysctl__kern_wakereason); 1067 1068#if HIBERNATION 1069 IOHibernateSystemInit(this); 1070#endif 1071 1072 registerService(); // let clients find us 1073 1074 return true; 1075} 1076 1077//****************************************************************************** 1078// setProperties 1079// 1080// Receive a setProperty call 1081// The "System Boot" property means the system is completely booted. 1082//****************************************************************************** 1083 1084IOReturn IOPMrootDomain::setProperties( OSObject * props_obj ) 1085{ 1086 IOReturn return_value = kIOReturnSuccess; 1087 OSDictionary *dict = OSDynamicCast(OSDictionary, props_obj); 1088 OSBoolean *b; 1089 OSNumber *n; 1090 const OSSymbol *key; 1091 OSObject *obj; 1092 OSCollectionIterator * iter = 0; 1093 1094 const OSSymbol *publish_simulated_battery_string = OSSymbol::withCString("SoftwareSimulatedBatteries"); 1095 const OSSymbol *boot_complete_string = OSSymbol::withCString("System Boot Complete"); 1096 const OSSymbol *sys_shutdown_string = OSSymbol::withCString("System Shutdown"); 1097 const OSSymbol *stall_halt_string = OSSymbol::withCString("StallSystemAtHalt"); 1098 const OSSymbol *battery_warning_disabled_string = OSSymbol::withCString("BatteryWarningsDisabled"); 1099 const OSSymbol *idle_seconds_string = OSSymbol::withCString("System Idle Seconds"); 1100 const OSSymbol *sleepdisabled_string = OSSymbol::withCString("SleepDisabled"); 1101 const OSSymbol *ondeck_sleepwake_uuid_string = OSSymbol::withCString(kIOPMSleepWakeUUIDKey); 1102 const OSSymbol *loginwindow_tracepoint_string = OSSymbol::withCString(kIOPMLoginWindowSecurityDebugKey); 1103#if HIBERNATION 1104 const OSSymbol *hibernatemode_string = OSSymbol::withCString(kIOHibernateModeKey); 1105 const OSSymbol *hibernatefile_string = OSSymbol::withCString(kIOHibernateFileKey); 1106 const OSSymbol *hibernatefilemin_string = OSSymbol::withCString(kIOHibernateFileMinSizeKey); 1107 const OSSymbol *hibernatefilemax_string = OSSymbol::withCString(kIOHibernateFileMaxSizeKey); 1108 const OSSymbol *hibernatefreeratio_string = OSSymbol::withCString(kIOHibernateFreeRatioKey); 1109 const OSSymbol *hibernatefreetime_string = OSSymbol::withCString(kIOHibernateFreeTimeKey); 1110#endif 1111 1112 if (!dict) 1113 { 1114 return_value = kIOReturnBadArgument; 1115 goto exit; 1116 } 1117 1118 iter = OSCollectionIterator::withCollection(dict); 1119 if (!iter) 1120 { 1121 return_value = kIOReturnNoMemory; 1122 goto exit; 1123 } 1124 1125 while ((key = (const OSSymbol *) iter->getNextObject()) && 1126 (obj = dict->getObject(key))) 1127 { 1128 if (key->isEqualTo(publish_simulated_battery_string)) 1129 { 1130 if (OSDynamicCast(OSBoolean, obj)) 1131 publishResource(key, kOSBooleanTrue); 1132 } 1133 else if (key->isEqualTo(idle_seconds_string)) 1134 { 1135 if ((n = OSDynamicCast(OSNumber, obj))) 1136 { 1137 setProperty(key, n); 1138 idleSeconds = n->unsigned32BitValue(); 1139 } 1140 } 1141 else if (key->isEqualTo(boot_complete_string)) 1142 { 1143 pmPowerStateQueue->submitPowerEvent(kPowerEventSystemBootCompleted); 1144 } 1145 else if (key->isEqualTo(sys_shutdown_string)) 1146 { 1147 if ((b = OSDynamicCast(OSBoolean, obj))) 1148 pmPowerStateQueue->submitPowerEvent(kPowerEventSystemShutdown, (void *) b); 1149 } 1150 else if (key->isEqualTo(battery_warning_disabled_string)) 1151 { 1152 setProperty(key, obj); 1153 } 1154#if HIBERNATION 1155 else if (key->isEqualTo(hibernatemode_string) || 1156 key->isEqualTo(hibernatefilemin_string) || 1157 key->isEqualTo(hibernatefilemax_string) || 1158 key->isEqualTo(hibernatefreeratio_string) || 1159 key->isEqualTo(hibernatefreetime_string)) 1160 { 1161 if ((n = OSDynamicCast(OSNumber, obj))) 1162 setProperty(key, n); 1163 } 1164 else if (key->isEqualTo(hibernatefile_string)) 1165 { 1166 OSString * str = OSDynamicCast(OSString, obj); 1167 if (str) setProperty(key, str); 1168 } 1169#endif 1170 else if (key->isEqualTo(sleepdisabled_string)) 1171 { 1172 if ((b = OSDynamicCast(OSBoolean, obj))) 1173 { 1174 setProperty(key, b); 1175 pmPowerStateQueue->submitPowerEvent(kPowerEventUserDisabledSleep, (void *) b); 1176 } 1177 } 1178 else if (key->isEqualTo(ondeck_sleepwake_uuid_string)) 1179 { 1180 obj->retain(); 1181 pmPowerStateQueue->submitPowerEvent(kPowerEventQueueSleepWakeUUID, (void *)obj); 1182 } 1183 else if (key->isEqualTo(loginwindow_tracepoint_string)) 1184 { 1185 if (pmTracer && (n = OSDynamicCast(OSNumber, obj))) 1186 pmTracer->traceLoginWindowPhase(n->unsigned8BitValue()); 1187 } 1188 else if (key->isEqualTo(kIOPMDeepSleepEnabledKey) || 1189 key->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey) || 1190 key->isEqualTo(kIOPMAutoPowerOffEnabledKey) || 1191 key->isEqualTo(stall_halt_string)) 1192 { 1193 if ((b = OSDynamicCast(OSBoolean, obj))) 1194 setProperty(key, b); 1195 } 1196 else if (key->isEqualTo(kIOPMDeepSleepDelayKey) || 1197 key->isEqualTo(kIOPMAutoPowerOffDelayKey) || 1198 key->isEqualTo(kIOPMAutoPowerOffTimerKey)) 1199 { 1200 if ((n = OSDynamicCast(OSNumber, obj))) 1201 setProperty(key, n); 1202 } 1203 else if (key->isEqualTo(kIOPMUserWakeAlarmScheduledKey)) 1204 { 1205 if (kOSBooleanTrue == obj) 1206 OSBitOrAtomic(kIOPMAlarmBitCalendarWake, &_userScheduledAlarm); 1207 else 1208 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake, &_userScheduledAlarm); 1209 DLOG("_userScheduledAlarm = 0x%x\n", (uint32_t) _userScheduledAlarm); 1210 } 1211 1212 // Relay our allowed PM settings onto our registered PM clients 1213 else if ((allowedPMSettings->getNextIndexOfObject(key, 0) != (unsigned int) -1)) 1214 { 1215 if ((gIOPMSettingAutoWakeSecondsKey == key) && ((n = OSDynamicCast(OSNumber, obj)))) 1216 { 1217 UInt32 rsecs = n->unsigned32BitValue(); 1218 if (!rsecs) 1219 autoWakeStart = autoWakeEnd = 0; 1220 else 1221 { 1222 AbsoluteTime deadline; 1223 clock_interval_to_deadline(rsecs + kAutoWakePostWindow, kSecondScale, &deadline); 1224 autoWakeEnd = AbsoluteTime_to_scalar(&deadline); 1225 if (rsecs > kAutoWakePreWindow) 1226 rsecs -= kAutoWakePreWindow; 1227 else 1228 rsecs = 0; 1229 clock_interval_to_deadline(rsecs, kSecondScale, &deadline); 1230 autoWakeStart = AbsoluteTime_to_scalar(&deadline); 1231 } 1232 } 1233 1234 return_value = setPMSetting(key, obj); 1235 if (kIOReturnSuccess != return_value) 1236 break; 1237 1238 if (gIOPMSettingDebugWakeRelativeKey == key) 1239 { 1240 if ((n = OSDynamicCast(OSNumber, obj)) && 1241 (_debugWakeSeconds = n->unsigned32BitValue())) 1242 { 1243 OSBitOrAtomic(kIOPMAlarmBitDebugWake, &_scheduledAlarms); 1244 } 1245 else 1246 { 1247 _debugWakeSeconds = 0; 1248 OSBitAndAtomic(~kIOPMAlarmBitDebugWake, &_scheduledAlarms); 1249 } 1250 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms); 1251 } 1252 else if (gIOPMSettingAutoWakeCalendarKey == key) 1253 { 1254 OSData * data; 1255 if ((data = OSDynamicCast(OSData, obj)) && 1256 (data->getLength() == sizeof(IOPMCalendarStruct))) 1257 { 1258 const IOPMCalendarStruct * cs = 1259 (const IOPMCalendarStruct *) data->getBytesNoCopy(); 1260 1261 if (cs->year) 1262 OSBitOrAtomic(kIOPMAlarmBitCalendarWake, &_scheduledAlarms); 1263 else 1264 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake, &_scheduledAlarms); 1265 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms); 1266 } 1267 } 1268 } 1269 else 1270 { 1271 DLOG("setProperties(%s) not handled\n", key->getCStringNoCopy()); 1272 } 1273 } 1274 1275exit: 1276 if(publish_simulated_battery_string) publish_simulated_battery_string->release(); 1277 if(boot_complete_string) boot_complete_string->release(); 1278 if(sys_shutdown_string) sys_shutdown_string->release(); 1279 if(stall_halt_string) stall_halt_string->release(); 1280 if(battery_warning_disabled_string) battery_warning_disabled_string->release(); 1281 if(idle_seconds_string) idle_seconds_string->release(); 1282 if(sleepdisabled_string) sleepdisabled_string->release(); 1283 if(ondeck_sleepwake_uuid_string) ondeck_sleepwake_uuid_string->release(); 1284 if(loginwindow_tracepoint_string) loginwindow_tracepoint_string->release(); 1285#if HIBERNATION 1286 if(hibernatemode_string) hibernatemode_string->release(); 1287 if(hibernatefile_string) hibernatefile_string->release(); 1288 if(hibernatefreeratio_string) hibernatefreeratio_string->release(); 1289 if(hibernatefreetime_string) hibernatefreetime_string->release(); 1290#endif 1291 if (iter) iter->release(); 1292 return return_value; 1293} 1294 1295// MARK: - 1296// MARK: Aggressiveness 1297 1298//****************************************************************************** 1299// setAggressiveness 1300// 1301// Override IOService::setAggressiveness() 1302//****************************************************************************** 1303 1304IOReturn IOPMrootDomain::setAggressiveness( 1305 unsigned long type, 1306 unsigned long value ) 1307{ 1308 return setAggressiveness( type, value, 0 ); 1309} 1310 1311/* 1312 * Private setAggressiveness() with an internal options argument. 1313 */ 1314IOReturn IOPMrootDomain::setAggressiveness( 1315 unsigned long type, 1316 unsigned long value, 1317 IOOptionBits options ) 1318{ 1319 AggressivesRequest * entry; 1320 AggressivesRequest * request; 1321 bool found = false; 1322 1323 DLOG("setAggressiveness(%x) 0x%x = %u\n", 1324 (uint32_t) options, (uint32_t) type, (uint32_t) value); 1325 1326 request = IONew(AggressivesRequest, 1); 1327 if (!request) 1328 return kIOReturnNoMemory; 1329 1330 memset(request, 0, sizeof(*request)); 1331 request->options = options; 1332 request->dataType = kAggressivesRequestTypeRecord; 1333 request->data.record.type = (uint32_t) type; 1334 request->data.record.value = (uint32_t) value; 1335 1336 AGGRESSIVES_LOCK(); 1337 1338 // Update disk quick spindown flag used by getAggressiveness(). 1339 // Never merge requests with quick spindown flags set. 1340 1341 if (options & kAggressivesOptionQuickSpindownEnable) 1342 gAggressivesState |= kAggressivesStateQuickSpindown; 1343 else if (options & kAggressivesOptionQuickSpindownDisable) 1344 gAggressivesState &= ~kAggressivesStateQuickSpindown; 1345 else 1346 { 1347 // Coalesce requests with identical aggressives types. 1348 // Deal with callers that calls us too "aggressively". 1349 1350 queue_iterate(&aggressivesQueue, entry, AggressivesRequest *, chain) 1351 { 1352 if ((entry->dataType == kAggressivesRequestTypeRecord) && 1353 (entry->data.record.type == type) && 1354 ((entry->options & kAggressivesOptionQuickSpindownMask) == 0)) 1355 { 1356 entry->data.record.value = value; 1357 found = true; 1358 break; 1359 } 1360 } 1361 } 1362 1363 if (!found) 1364 { 1365 queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain); 1366 } 1367 1368 AGGRESSIVES_UNLOCK(); 1369 1370 if (found) 1371 IODelete(request, AggressivesRequest, 1); 1372 1373 if (options & kAggressivesOptionSynchronous) 1374 handleAggressivesRequests(); // not truly synchronous 1375 else 1376 thread_call_enter(aggressivesThreadCall); 1377 1378 return kIOReturnSuccess; 1379} 1380 1381//****************************************************************************** 1382// getAggressiveness 1383// 1384// Override IOService::setAggressiveness() 1385// Fetch the aggressiveness factor with the given type. 1386//****************************************************************************** 1387 1388IOReturn IOPMrootDomain::getAggressiveness ( 1389 unsigned long type, 1390 unsigned long * outLevel ) 1391{ 1392 uint32_t value = 0; 1393 int source = 0; 1394 1395 if (!outLevel) 1396 return kIOReturnBadArgument; 1397 1398 AGGRESSIVES_LOCK(); 1399 1400 // Disk quick spindown in effect, report value = 1 1401 1402 if ((gAggressivesState & kAggressivesStateQuickSpindown) && 1403 (type == kPMMinutesToSpinDown)) 1404 { 1405 value = kAggressivesMinValue; 1406 source = 1; 1407 } 1408 1409 // Consult the pending request queue. 1410 1411 if (!source) 1412 { 1413 AggressivesRequest * entry; 1414 1415 queue_iterate(&aggressivesQueue, entry, AggressivesRequest *, chain) 1416 { 1417 if ((entry->dataType == kAggressivesRequestTypeRecord) && 1418 (entry->data.record.type == type) && 1419 ((entry->options & kAggressivesOptionQuickSpindownMask) == 0)) 1420 { 1421 value = entry->data.record.value; 1422 source = 2; 1423 break; 1424 } 1425 } 1426 } 1427 1428 // Consult the backend records. 1429 1430 if (!source && aggressivesData) 1431 { 1432 AggressivesRecord * record; 1433 int i, count; 1434 1435 count = aggressivesData->getLength() / sizeof(AggressivesRecord); 1436 record = (AggressivesRecord *) aggressivesData->getBytesNoCopy(); 1437 1438 for (i = 0; i < count; i++, record++) 1439 { 1440 if (record->type == type) 1441 { 1442 value = record->value; 1443 source = 3; 1444 break; 1445 } 1446 } 1447 } 1448 1449 AGGRESSIVES_UNLOCK(); 1450 1451 if (source) 1452 { 1453 DLOG("getAggressiveness(%d) 0x%x = %u\n", 1454 source, (uint32_t) type, value); 1455 *outLevel = (unsigned long) value; 1456 return kIOReturnSuccess; 1457 } 1458 else 1459 { 1460 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type); 1461 *outLevel = 0; // default return = 0, driver may not check for error 1462 return kIOReturnInvalid; 1463 } 1464} 1465 1466//****************************************************************************** 1467// joinAggressiveness 1468// 1469// Request from IOService to join future aggressiveness broadcasts. 1470//****************************************************************************** 1471 1472IOReturn IOPMrootDomain::joinAggressiveness( 1473 IOService * service ) 1474{ 1475 AggressivesRequest * request; 1476 1477 if (!service || (service == this)) 1478 return kIOReturnBadArgument; 1479 1480 DLOG("joinAggressiveness %s %p\n", service->getName(), OBFUSCATE(service)); 1481 1482 request = IONew(AggressivesRequest, 1); 1483 if (!request) 1484 return kIOReturnNoMemory; 1485 1486 service->retain(); // released by synchronizeAggressives() 1487 1488 memset(request, 0, sizeof(*request)); 1489 request->dataType = kAggressivesRequestTypeService; 1490 request->data.service = service; 1491 1492 AGGRESSIVES_LOCK(); 1493 queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain); 1494 AGGRESSIVES_UNLOCK(); 1495 1496 thread_call_enter(aggressivesThreadCall); 1497 1498 return kIOReturnSuccess; 1499} 1500 1501//****************************************************************************** 1502// handleAggressivesRequests 1503// 1504// Backend thread processes all incoming aggressiveness requests in the queue. 1505//****************************************************************************** 1506 1507static void 1508handleAggressivesFunction( 1509 thread_call_param_t param1, 1510 thread_call_param_t param2 ) 1511{ 1512 if (param1) 1513 { 1514 ((IOPMrootDomain *) param1)->handleAggressivesRequests(); 1515 } 1516} 1517 1518void IOPMrootDomain::handleAggressivesRequests( void ) 1519{ 1520 AggressivesRecord * start; 1521 AggressivesRecord * record; 1522 AggressivesRequest * request; 1523 queue_head_t joinedQueue; 1524 int i, count; 1525 bool broadcast; 1526 bool found; 1527 bool pingSelf = false; 1528 1529 AGGRESSIVES_LOCK(); 1530 1531 if ((gAggressivesState & kAggressivesStateBusy) || !aggressivesData || 1532 queue_empty(&aggressivesQueue)) 1533 goto unlock_done; 1534 1535 gAggressivesState |= kAggressivesStateBusy; 1536 count = aggressivesData->getLength() / sizeof(AggressivesRecord); 1537 start = (AggressivesRecord *) aggressivesData->getBytesNoCopy(); 1538 1539 do 1540 { 1541 broadcast = false; 1542 queue_init(&joinedQueue); 1543 1544 do 1545 { 1546 // Remove request from the incoming queue in FIFO order. 1547 queue_remove_first(&aggressivesQueue, request, AggressivesRequest *, chain); 1548 switch (request->dataType) 1549 { 1550 case kAggressivesRequestTypeRecord: 1551 // Update existing record if found. 1552 found = false; 1553 for (i = 0, record = start; i < count; i++, record++) 1554 { 1555 if (record->type == request->data.record.type) 1556 { 1557 found = true; 1558 1559 if (request->options & kAggressivesOptionQuickSpindownEnable) 1560 { 1561 if ((record->flags & kAggressivesRecordFlagMinValue) == 0) 1562 { 1563 broadcast = true; 1564 record->flags |= (kAggressivesRecordFlagMinValue | 1565 kAggressivesRecordFlagModified); 1566 DLOG("disk spindown accelerated, was %u min\n", 1567 record->value); 1568 } 1569 } 1570 else if (request->options & kAggressivesOptionQuickSpindownDisable) 1571 { 1572 if (record->flags & kAggressivesRecordFlagMinValue) 1573 { 1574 broadcast = true; 1575 record->flags |= kAggressivesRecordFlagModified; 1576 record->flags &= ~kAggressivesRecordFlagMinValue; 1577 DLOG("disk spindown restored to %u min\n", 1578 record->value); 1579 } 1580 } 1581 else if (record->value != request->data.record.value) 1582 { 1583 record->value = request->data.record.value; 1584 if ((record->flags & kAggressivesRecordFlagMinValue) == 0) 1585 { 1586 broadcast = true; 1587 record->flags |= kAggressivesRecordFlagModified; 1588 } 1589 } 1590 break; 1591 } 1592 } 1593 1594 // No matching record, append a new record. 1595 if (!found && 1596 ((request->options & kAggressivesOptionQuickSpindownDisable) == 0)) 1597 { 1598 AggressivesRecord newRecord; 1599 1600 newRecord.flags = kAggressivesRecordFlagModified; 1601 newRecord.type = request->data.record.type; 1602 newRecord.value = request->data.record.value; 1603 if (request->options & kAggressivesOptionQuickSpindownEnable) 1604 { 1605 newRecord.flags |= kAggressivesRecordFlagMinValue; 1606 DLOG("disk spindown accelerated\n"); 1607 } 1608 1609 aggressivesData->appendBytes(&newRecord, sizeof(newRecord)); 1610 1611 // OSData may have switched to another (larger) buffer. 1612 count = aggressivesData->getLength() / sizeof(AggressivesRecord); 1613 start = (AggressivesRecord *) aggressivesData->getBytesNoCopy(); 1614 broadcast = true; 1615 } 1616 1617 // Finished processing the request, release it. 1618 IODelete(request, AggressivesRequest, 1); 1619 break; 1620 1621 case kAggressivesRequestTypeService: 1622 // synchronizeAggressives() will free request. 1623 queue_enter(&joinedQueue, request, AggressivesRequest *, chain); 1624 break; 1625 1626 default: 1627 panic("bad aggressives request type %x\n", request->dataType); 1628 break; 1629 } 1630 } while (!queue_empty(&aggressivesQueue)); 1631 1632 // Release the lock to perform work, with busy flag set. 1633 if (!queue_empty(&joinedQueue) || broadcast) 1634 { 1635 AGGRESSIVES_UNLOCK(); 1636 if (!queue_empty(&joinedQueue)) 1637 synchronizeAggressives(&joinedQueue, start, count); 1638 if (broadcast) 1639 broadcastAggressives(start, count); 1640 AGGRESSIVES_LOCK(); 1641 } 1642 1643 // Remove the modified flag from all records. 1644 for (i = 0, record = start; i < count; i++, record++) 1645 { 1646 if ((record->flags & kAggressivesRecordFlagModified) && 1647 ((record->type == kPMMinutesToDim) || 1648 (record->type == kPMMinutesToSleep))) 1649 pingSelf = true; 1650 1651 record->flags &= ~kAggressivesRecordFlagModified; 1652 } 1653 1654 // Check the incoming queue again since new entries may have been 1655 // added while lock was released above. 1656 1657 } while (!queue_empty(&aggressivesQueue)); 1658 1659 gAggressivesState &= ~kAggressivesStateBusy; 1660 1661unlock_done: 1662 AGGRESSIVES_UNLOCK(); 1663 1664 // Root domain is interested in system and display sleep slider changes. 1665 // Submit a power event to handle those changes on the PM work loop. 1666 1667 if (pingSelf && pmPowerStateQueue) { 1668 pmPowerStateQueue->submitPowerEvent( 1669 kPowerEventPolicyStimulus, 1670 (void *) kStimulusAggressivenessChanged ); 1671 } 1672} 1673 1674//****************************************************************************** 1675// synchronizeAggressives 1676// 1677// Push all known aggressiveness records to one or more IOService. 1678//****************************************************************************** 1679 1680void IOPMrootDomain::synchronizeAggressives( 1681 queue_head_t * joinedQueue, 1682 const AggressivesRecord * array, 1683 int count ) 1684{ 1685 IOService * service; 1686 AggressivesRequest * request; 1687 const AggressivesRecord * record; 1688 IOPMDriverCallEntry callEntry; 1689 uint32_t value; 1690 int i; 1691 1692 while (!queue_empty(joinedQueue)) 1693 { 1694 queue_remove_first(joinedQueue, request, AggressivesRequest *, chain); 1695 if (request->dataType == kAggressivesRequestTypeService) 1696 service = request->data.service; 1697 else 1698 service = 0; 1699 1700 IODelete(request, AggressivesRequest, 1); 1701 request = 0; 1702 1703 if (service) 1704 { 1705 if (service->assertPMDriverCall(&callEntry)) 1706 { 1707 for (i = 0, record = array; i < count; i++, record++) 1708 { 1709 value = record->value; 1710 if (record->flags & kAggressivesRecordFlagMinValue) 1711 value = kAggressivesMinValue; 1712 1713 _LOG("synchronizeAggressives 0x%x = %u to %s\n", 1714 record->type, value, service->getName()); 1715 service->setAggressiveness(record->type, value); 1716 } 1717 service->deassertPMDriverCall(&callEntry); 1718 } 1719 service->release(); // retained by joinAggressiveness() 1720 } 1721 } 1722} 1723 1724//****************************************************************************** 1725// broadcastAggressives 1726// 1727// Traverse PM tree and call setAggressiveness() for records that have changed. 1728//****************************************************************************** 1729 1730void IOPMrootDomain::broadcastAggressives( 1731 const AggressivesRecord * array, 1732 int count ) 1733{ 1734 IORegistryIterator * iter; 1735 IORegistryEntry * entry; 1736 IOPowerConnection * connect; 1737 IOService * service; 1738 const AggressivesRecord * record; 1739 IOPMDriverCallEntry callEntry; 1740 uint32_t value; 1741 int i; 1742 1743 iter = IORegistryIterator::iterateOver( 1744 this, gIOPowerPlane, kIORegistryIterateRecursively); 1745 if (iter) 1746 { 1747 do 1748 { 1749 iter->reset(); 1750 while ((entry = iter->getNextObject())) 1751 { 1752 connect = OSDynamicCast(IOPowerConnection, entry); 1753 if (!connect || !connect->getReadyFlag()) 1754 continue; 1755 1756 if ((service = (IOService *) connect->copyChildEntry(gIOPowerPlane))) 1757 { 1758 if (service->assertPMDriverCall(&callEntry)) 1759 { 1760 for (i = 0, record = array; i < count; i++, record++) 1761 { 1762 if (record->flags & kAggressivesRecordFlagModified) 1763 { 1764 value = record->value; 1765 if (record->flags & kAggressivesRecordFlagMinValue) 1766 value = kAggressivesMinValue; 1767 _LOG("broadcastAggressives %x = %u to %s\n", 1768 record->type, value, service->getName()); 1769 service->setAggressiveness(record->type, value); 1770 } 1771 } 1772 service->deassertPMDriverCall(&callEntry); 1773 } 1774 service->release(); 1775 } 1776 } 1777 } 1778 while (!entry && !iter->isValid()); 1779 iter->release(); 1780 } 1781} 1782 1783// MARK: - 1784// MARK: System Sleep 1785 1786//****************************************************************************** 1787// startIdleSleepTimer 1788// 1789//****************************************************************************** 1790 1791void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds ) 1792{ 1793 AbsoluteTime deadline; 1794 1795 ASSERT_GATED(); 1796 if (inSeconds) 1797 { 1798 clock_interval_to_deadline(inSeconds, kSecondScale, &deadline); 1799 thread_call_enter_delayed(extraSleepTimer, deadline); 1800 idleSleepTimerPending = true; 1801 } 1802 else 1803 { 1804 thread_call_enter(extraSleepTimer); 1805 } 1806 DLOG("idle timer set for %u seconds\n", inSeconds); 1807} 1808 1809//****************************************************************************** 1810// cancelIdleSleepTimer 1811// 1812//****************************************************************************** 1813 1814void IOPMrootDomain::cancelIdleSleepTimer( void ) 1815{ 1816 ASSERT_GATED(); 1817 if (idleSleepTimerPending) 1818 { 1819 DLOG("idle timer cancelled\n"); 1820 thread_call_cancel(extraSleepTimer); 1821 idleSleepTimerPending = false; 1822 } 1823} 1824 1825//****************************************************************************** 1826// idleSleepTimerExpired 1827// 1828//****************************************************************************** 1829 1830static void idleSleepTimerExpired( 1831 thread_call_param_t us, thread_call_param_t ) 1832{ 1833 ((IOPMrootDomain *)us)->handleSleepTimerExpiration(); 1834} 1835 1836//****************************************************************************** 1837// handleSleepTimerExpiration 1838// 1839// The time between the sleep idle timeout and the next longest one has elapsed. 1840// It's time to sleep. Start that by removing the clamp that's holding us awake. 1841//****************************************************************************** 1842 1843void IOPMrootDomain::handleSleepTimerExpiration( void ) 1844{ 1845 if (!getPMworkloop()->inGate()) 1846 { 1847 getPMworkloop()->runAction( 1848 OSMemberFunctionCast(IOWorkLoop::Action, this, 1849 &IOPMrootDomain::handleSleepTimerExpiration), 1850 this); 1851 return; 1852 } 1853 1854 AbsoluteTime time; 1855 1856 DLOG("sleep timer expired\n"); 1857 ASSERT_GATED(); 1858 1859 idleSleepTimerPending = false; 1860 1861 clock_get_uptime(&time); 1862 if ((AbsoluteTime_to_scalar(&time) > autoWakeStart) && 1863 (AbsoluteTime_to_scalar(&time) < autoWakeEnd)) 1864 { 1865 thread_call_enter_delayed(extraSleepTimer, *((AbsoluteTime *) &autoWakeEnd)); 1866 return; 1867 } 1868 1869 setQuickSpinDownTimeout(); 1870 adjustPowerState(true); 1871} 1872 1873//****************************************************************************** 1874// getTimeToIdleSleep 1875// 1876// Returns number of seconds left before going into idle sleep. 1877// Caller has to make sure that idle sleep is allowed at the time of calling 1878// this function 1879//****************************************************************************** 1880 1881uint32_t IOPMrootDomain::getTimeToIdleSleep( void ) 1882{ 1883 1884 AbsoluteTime now, lastActivityTime; 1885 uint64_t nanos; 1886 uint32_t minutesSinceUserInactive = 0; 1887 uint32_t sleepDelay = 0; 1888 1889 if (sleepSlider == 0) 1890 return 0xffffffff; 1891 1892 if (userActivityTime) 1893 lastActivityTime = userActivityTime; 1894 else 1895 lastActivityTime = userBecameInactiveTime; 1896 1897 clock_get_uptime(&now); 1898 if (CMP_ABSOLUTETIME(&now, &lastActivityTime) > 0) 1899 { 1900 SUB_ABSOLUTETIME(&now, &lastActivityTime); 1901 absolutetime_to_nanoseconds(now, &nanos); 1902 minutesSinceUserInactive = nanos / (60000000000ULL); 1903 1904 if (minutesSinceUserInactive >= sleepSlider) 1905 sleepDelay = 0; 1906 else 1907 sleepDelay = sleepSlider - minutesSinceUserInactive; 1908 } 1909 else 1910 { 1911 sleepDelay = sleepSlider; 1912 } 1913 1914 DLOG("user inactive %u min, time to idle sleep %u min\n", 1915 minutesSinceUserInactive, sleepDelay); 1916 1917 return (sleepDelay * 60); 1918} 1919 1920//****************************************************************************** 1921// setQuickSpinDownTimeout 1922// 1923//****************************************************************************** 1924 1925void IOPMrootDomain::setQuickSpinDownTimeout( void ) 1926{ 1927 ASSERT_GATED(); 1928 setAggressiveness( 1929 kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownEnable ); 1930} 1931 1932//****************************************************************************** 1933// restoreUserSpinDownTimeout 1934// 1935//****************************************************************************** 1936 1937void IOPMrootDomain::restoreUserSpinDownTimeout( void ) 1938{ 1939 ASSERT_GATED(); 1940 setAggressiveness( 1941 kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownDisable ); 1942} 1943 1944//****************************************************************************** 1945// sleepSystem 1946// 1947//****************************************************************************** 1948 1949/* public */ 1950IOReturn IOPMrootDomain::sleepSystem( void ) 1951{ 1952 return sleepSystemOptions(NULL); 1953} 1954 1955/* private */ 1956IOReturn IOPMrootDomain::sleepSystemOptions( OSDictionary *options ) 1957{ 1958 OSObject *obj = NULL; 1959 OSString *reason = NULL; 1960 /* sleepSystem is a public function, and may be called by any kernel driver. 1961 * And that's bad - drivers should sleep the system by calling 1962 * receivePowerNotification() instead. Drivers should not use sleepSystem. 1963 * 1964 * Note that user space app calls to IOPMSleepSystem() will also travel 1965 * this code path and thus be correctly identified as software sleeps. 1966 */ 1967 1968 if (options && options->getObject("OSSwitch")) 1969 { 1970 // Log specific sleep cause for OS Switch hibernation 1971 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate); 1972 } 1973 1974 if (options && (obj = options->getObject("Sleep Reason"))) 1975 { 1976 reason = OSDynamicCast(OSString, obj); 1977 if (reason && reason->isEqualTo(kIOPMDarkWakeThermalEmergencyKey)) 1978 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency); 1979 } 1980 1981 return privateSleepSystem( kIOPMSleepReasonSoftware); 1982} 1983 1984/* private */ 1985IOReturn IOPMrootDomain::privateSleepSystem( uint32_t sleepReason ) 1986{ 1987 /* Called from both gated and non-gated context */ 1988 1989 if (!checkSystemSleepEnabled() || !pmPowerStateQueue) 1990 { 1991 return kIOReturnNotPermitted; 1992 } 1993 1994 pmPowerStateQueue->submitPowerEvent( 1995 kPowerEventPolicyStimulus, 1996 (void *) kStimulusDemandSystemSleep, 1997 sleepReason); 1998 1999 return kIOReturnSuccess; 2000} 2001 2002//****************************************************************************** 2003// powerChangeDone 2004// 2005// This overrides powerChangeDone in IOService. 2006//****************************************************************************** 2007 2008void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState ) 2009{ 2010 ASSERT_GATED(); 2011 DLOG("PowerChangeDone: %u->%u\n", 2012 (uint32_t) previousPowerState, (uint32_t) getPowerState()); 2013 2014 switch ( getPowerState() ) 2015 { 2016 case SLEEP_STATE: { 2017 if (previousPowerState != ON_STATE) 2018 break; 2019 2020 acceptSystemWakeEvents(true); 2021 2022 // re-enable this timer for next sleep 2023 cancelIdleSleepTimer(); 2024 2025 clock_sec_t secs; 2026 clock_usec_t microsecs; 2027 clock_get_calendar_microtime(&secs, µsecs); 2028 logtime(secs); 2029 gIOLastSleepTime.tv_sec = secs; 2030 gIOLastSleepTime.tv_usec = microsecs; 2031 gIOLastWakeTime.tv_sec = 0; 2032 gIOLastWakeTime.tv_usec = 0; 2033 2034#if HIBERNATION 2035 LOG("System %sSleep\n", gIOHibernateState ? "Safe" : ""); 2036 2037 IOHibernateSystemHasSlept(); 2038 2039 evaluateSystemSleepPolicyFinal(); 2040#else 2041 LOG("System Sleep\n"); 2042#endif 2043 2044 ((IOService *)this)->stop_watchdog_timer(); //14456299 2045 getPlatform()->sleepKernel(); 2046 2047 // The CPU(s) are off at this point, 2048 // Code will resume execution here upon wake. 2049 2050 clock_get_uptime(&systemWakeTime); 2051 _highestCapability = 0; 2052 2053 ((IOService *)this)->start_watchdog_timer(); //14456299 2054#if HIBERNATION 2055 IOHibernateSystemWake(); 2056#endif 2057 2058 // sleep transition complete 2059 gSleepOrShutdownPending = 0; 2060 2061 // trip the reset of the calendar clock 2062 clock_wakeup_calendar(); 2063 2064#if HIBERNATION 2065 LOG("System %sWake\n", gIOHibernateState ? "SafeSleep " : ""); 2066#endif 2067 2068 // log system wake 2069 PMDebug(kPMLogSystemWake, 0, 0); 2070 lowBatteryCondition = false; 2071 lastSleepReason = 0; 2072 2073 _lastDebugWakeSeconds = _debugWakeSeconds; 2074 _debugWakeSeconds = 0; 2075 _scheduledAlarms = 0; 2076 2077#ifndef __LP64__ 2078 systemWake(); 2079#endif 2080 2081#if defined(__i386__) || defined(__x86_64__) 2082 wranglerTickled = false; 2083 graphicsSuppressed = false; 2084 darkWakePostTickle = false; 2085 darkWakeHibernateError = false; 2086 darkWakeToSleepASAP = true; 2087 logGraphicsClamp = true; 2088 sleepTimerMaintenance = false; 2089 sleepToStandby = false; 2090 wranglerTickleLatched = false; 2091 userWasActive = false; 2092 fullWakeReason = kFullWakeReasonNone; 2093 2094 OSString * wakeType = OSDynamicCast( 2095 OSString, getProperty(kIOPMRootDomainWakeTypeKey)); 2096 OSString * wakeReason = OSDynamicCast( 2097 OSString, getProperty(kIOPMRootDomainWakeReasonKey)); 2098 2099 if (wakeReason && (wakeReason->getLength() >= 2) && 2100 gWakeReasonString[0] == '\0') 2101 { 2102 // Until the platform driver can claim its wake reasons 2103 strlcat(gWakeReasonString, wakeReason->getCStringNoCopy(), 2104 sizeof(gWakeReasonString)); 2105 } 2106 2107 if (wakeType && wakeType->isEqualTo(kIOPMrootDomainWakeTypeLowBattery)) 2108 { 2109 lowBatteryCondition = true; 2110 darkWakeMaintenance = true; 2111 } 2112 else if ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) != 0) 2113 { 2114 OSNumber * hibOptions = OSDynamicCast( 2115 OSNumber, getProperty(kIOHibernateOptionsKey)); 2116 2117 if (hibernateAborted || ((hibOptions && 2118 !(hibOptions->unsigned32BitValue() & kIOHibernateOptionDarkWake)))) 2119 { 2120 // Hibernate aborted, or EFI brought up graphics 2121 wranglerTickled = true; 2122 DLOG("hibernation aborted %d, options 0x%x\n", 2123 hibernateAborted, 2124 hibOptions ? hibOptions->unsigned32BitValue() : 0); 2125 } 2126 else 2127 if (wakeType && ( 2128 wakeType->isEqualTo(kIOPMRootDomainWakeTypeUser) || 2129 wakeType->isEqualTo(kIOPMRootDomainWakeTypeAlarm))) 2130 { 2131 // User wake or RTC alarm 2132 wranglerTickled = true; 2133 } 2134 else 2135 if (wakeType && 2136 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer)) 2137 { 2138 // SMC standby timer trumps SleepX 2139 darkWakeMaintenance = true; 2140 sleepTimerMaintenance = true; 2141 } 2142 else 2143 if ((_lastDebugWakeSeconds != 0) && 2144 ((gDarkWakeFlags & kDarkWakeFlagAlarmIsDark) == 0)) 2145 { 2146 // SleepX before maintenance 2147 wranglerTickled = true; 2148 } 2149 else 2150 if (wakeType && 2151 wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance)) 2152 { 2153 darkWakeMaintenance = true; 2154 } 2155 else 2156 if (wakeType && 2157 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepService)) 2158 { 2159 darkWakeMaintenance = true; 2160 darkWakeSleepService = true; 2161 if (kIOHibernateStateWakingFromHibernate == gIOHibernateState) { 2162 sleepToStandby = true; 2163 } 2164 } 2165 else 2166 if (wakeType && 2167 wakeType->isEqualTo(kIOPMRootDomainWakeTypeHibernateError)) 2168 { 2169 darkWakeMaintenance = true; 2170 darkWakeHibernateError = true; 2171 } 2172 else 2173 { 2174 // Unidentified wake source, resume to full wake if debug 2175 // alarm is pending. 2176 2177 if (_lastDebugWakeSeconds && 2178 (!wakeReason || wakeReason->isEqualTo(""))) 2179 wranglerTickled = true; 2180 } 2181 } 2182 else 2183 { 2184 if (wakeType && 2185 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer)) 2186 { 2187 darkWakeMaintenance = true; 2188 sleepTimerMaintenance = true; 2189 } 2190 else if (hibernateAborted || !wakeType || 2191 !wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance) || 2192 !wakeReason || !wakeReason->isEqualTo("RTC")) 2193 { 2194 // Post a HID tickle immediately - except for RTC maintenance wake. 2195 wranglerTickled = true; 2196 } 2197 else 2198 { 2199 darkWakeMaintenance = true; 2200 } 2201 } 2202 2203 if (wranglerTickled) 2204 { 2205 darkWakeToSleepASAP = false; 2206 fullWakeReason = kFullWakeReasonLocalUser; 2207 reportUserInput(); 2208 } 2209 else if (!darkWakeMaintenance) 2210 { 2211 // Early/late tickle for non-maintenance wake. 2212 if (((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) == 2213 kDarkWakeFlagHIDTickleEarly) || 2214 ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) == 2215 kDarkWakeFlagHIDTickleLate)) 2216 { 2217 darkWakePostTickle = true; 2218 } 2219 } 2220#else /* !__i386__ && !__x86_64__ */ 2221 // stay awake for at least 30 seconds 2222 wranglerTickled = true; 2223 fullWakeReason = kFullWakeReasonLocalUser; 2224 startIdleSleepTimer(30); 2225#endif 2226 sleepCnt++; 2227 2228 changePowerStateToPriv(ON_STATE); 2229 } break; 2230 2231 } 2232} 2233 2234//****************************************************************************** 2235// requestPowerDomainState 2236// 2237// Extend implementation in IOService. Running on PM work loop thread. 2238//****************************************************************************** 2239 2240IOReturn IOPMrootDomain::requestPowerDomainState ( 2241 IOPMPowerFlags childDesire, 2242 IOPowerConnection * childConnection, 2243 unsigned long specification ) 2244{ 2245 // Idle and system sleep prevention flags affects driver desire. 2246 // Children desire are irrelevant so they are cleared. 2247 2248 return super::requestPowerDomainState(0, childConnection, specification); 2249} 2250 2251//****************************************************************************** 2252// updatePreventIdleSleepList 2253// 2254// Called by IOService on PM work loop. 2255// Returns true if PM policy recognized the driver's desire to prevent idle 2256// sleep and updated the list of idle sleep preventers. Returns false otherwise 2257//****************************************************************************** 2258 2259bool IOPMrootDomain::updatePreventIdleSleepList( 2260 IOService * service, bool addNotRemove ) 2261{ 2262 unsigned int oldCount, newCount; 2263 2264 ASSERT_GATED(); 2265 2266#if defined(__i386__) || defined(__x86_64__) 2267 // Disregard disk I/O (besides the display wrangler) as a factor preventing 2268 // idle sleep, except in the case of legacy disk I/O 2269 if ((service != wrangler) && (service != this)) 2270 { 2271 return false; 2272 } 2273#endif 2274 2275 oldCount = preventIdleSleepList->getCount(); 2276 if (addNotRemove) 2277 { 2278 preventIdleSleepList->setObject(service); 2279 DLOG("prevent idle sleep list: %s+ (%u)\n", 2280 service->getName(), preventIdleSleepList->getCount()); 2281 } 2282 else if (preventIdleSleepList->member(service)) 2283 { 2284 preventIdleSleepList->removeObject(service); 2285 DLOG("prevent idle sleep list: %s- (%u)\n", 2286 service->getName(), preventIdleSleepList->getCount()); 2287 } 2288 newCount = preventIdleSleepList->getCount(); 2289 2290 if ((oldCount == 0) && (newCount != 0)) 2291 { 2292 // Driver added to empty prevent list. 2293 // Update the driver desire to prevent idle sleep. 2294 // Driver desire does not prevent demand sleep. 2295 2296 changePowerStateTo(ON_STATE); 2297 } 2298 else if ((oldCount != 0) && (newCount == 0)) 2299 { 2300 // Last driver removed from prevent list. 2301 // Drop the driver clamp to allow idle sleep. 2302 2303 changePowerStateTo(SLEEP_STATE); 2304 evaluatePolicy( kStimulusNoIdleSleepPreventers ); 2305 } 2306 2307#if defined(__i386__) || defined(__x86_64__) 2308 if (addNotRemove && (service == wrangler) && !checkSystemCanSustainFullWake()) 2309 { 2310 return false; // do not idle-cancel 2311 } 2312#endif 2313 2314 return true; 2315} 2316 2317//****************************************************************************** 2318// preventSystemSleepListUpdate 2319// 2320// Called by IOService on PM work loop. 2321//****************************************************************************** 2322 2323void IOPMrootDomain::updatePreventSystemSleepList( 2324 IOService * service, bool addNotRemove ) 2325{ 2326 unsigned int oldCount; 2327 2328 ASSERT_GATED(); 2329 if (this == service) 2330 return; 2331 2332 oldCount = preventSystemSleepList->getCount(); 2333 if (addNotRemove) 2334 { 2335 preventSystemSleepList->setObject(service); 2336 DLOG("prevent system sleep list: %s+ (%u)\n", 2337 service->getName(), preventSystemSleepList->getCount()); 2338 } 2339 else if (preventSystemSleepList->member(service)) 2340 { 2341 preventSystemSleepList->removeObject(service); 2342 DLOG("prevent system sleep list: %s- (%u)\n", 2343 service->getName(), preventSystemSleepList->getCount()); 2344 2345 if ((oldCount != 0) && (preventSystemSleepList->getCount() == 0)) 2346 { 2347 // Lost all system sleep preventers. 2348 // Send stimulus if system sleep was blocked, and is in dark wake. 2349 evaluatePolicy( kStimulusDarkWakeEvaluate ); 2350 } 2351 } 2352} 2353 2354//****************************************************************************** 2355// tellChangeDown 2356// 2357// Override the superclass implementation to send a different message type. 2358//****************************************************************************** 2359 2360bool IOPMrootDomain::tellChangeDown( unsigned long stateNum ) 2361{ 2362 DLOG("tellChangeDown %u->%u\n", 2363 (uint32_t) getPowerState(), (uint32_t) stateNum); 2364 2365 if (SLEEP_STATE == stateNum) 2366 { 2367 // Legacy apps were already told in the full->dark transition 2368 if (!ignoreTellChangeDown) 2369 tracePoint( kIOPMTracePointSleepApplications ); 2370 else 2371 tracePoint( kIOPMTracePointSleepPriorityClients ); 2372 } 2373 2374 if ((SLEEP_STATE == stateNum) && !ignoreTellChangeDown) 2375 { 2376 userActivityAtSleep = userActivityCount; 2377 hibernateAborted = false; 2378 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep); 2379 2380 // Direct callout into OSKext so it can disable kext unloads 2381 // during sleep/wake to prevent deadlocks. 2382 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep ); 2383 2384 IOService::updateConsoleUsers(NULL, kIOMessageSystemWillSleep); 2385 2386 // Two change downs are sent by IOServicePM. Ignore the 2nd. 2387 // But tellClientsWithResponse() must be called for both. 2388 ignoreTellChangeDown = true; 2389 } 2390 2391 return super::tellClientsWithResponse( kIOMessageSystemWillSleep ); 2392} 2393 2394//****************************************************************************** 2395// askChangeDown 2396// 2397// Override the superclass implementation to send a different message type. 2398// This must be idle sleep since we don't ask during any other power change. 2399//****************************************************************************** 2400 2401bool IOPMrootDomain::askChangeDown( unsigned long stateNum ) 2402{ 2403 DLOG("askChangeDown %u->%u\n", 2404 (uint32_t) getPowerState(), (uint32_t) stateNum); 2405 2406 // Don't log for dark wake entry 2407 if (kSystemTransitionSleep == _systemTransitionType) 2408 tracePoint( kIOPMTracePointSleepApplications ); 2409 2410 return super::tellClientsWithResponse( kIOMessageCanSystemSleep ); 2411} 2412 2413//****************************************************************************** 2414// askChangeDownDone 2415// 2416// An opportunity for root domain to cancel the power transition, 2417// possibily due to an assertion created by powerd in response to 2418// kIOMessageCanSystemSleep. 2419// 2420// Idle sleep: 2421// full -> dark wake transition 2422// 1. Notify apps and powerd with kIOMessageCanSystemSleep 2423// 2. askChangeDownDone() 2424// dark -> sleep transition 2425// 1. Notify powerd with kIOMessageCanSystemSleep 2426// 2. askChangeDownDone() 2427// 2428// Demand sleep: 2429// full -> dark wake transition 2430// 1. Notify powerd with kIOMessageCanSystemSleep 2431// 2. askChangeDownDone() 2432// dark -> sleep transition 2433// 1. Notify powerd with kIOMessageCanSystemSleep 2434// 2. askChangeDownDone() 2435//****************************************************************************** 2436 2437void IOPMrootDomain::askChangeDownDone( 2438 IOPMPowerChangeFlags * inOutChangeFlags, bool * cancel ) 2439{ 2440 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n", 2441 *inOutChangeFlags, *cancel, 2442 _systemTransitionType, 2443 _currentCapability, _pendingCapability); 2444 2445 if ((false == *cancel) && (kSystemTransitionSleep == _systemTransitionType)) 2446 { 2447 // Dark->Sleep transition. 2448 // Check if there are any deny sleep assertions. 2449 // lastSleepReason already set by handleOurPowerChangeStart() 2450 2451 if (!checkSystemCanSleep(lastSleepReason)) 2452 { 2453 // Cancel dark wake to sleep transition. 2454 // Must re-scan assertions upon entering dark wake. 2455 2456 *cancel = true; 2457 DLOG("cancel dark->sleep\n"); 2458 } 2459 } 2460} 2461 2462//****************************************************************************** 2463// systemDidNotSleep 2464// 2465// Work common to both canceled or aborted sleep. 2466//****************************************************************************** 2467 2468void IOPMrootDomain::systemDidNotSleep( void ) 2469{ 2470 if (!wrangler) 2471 { 2472 if (idleSeconds) 2473 { 2474 // stay awake for at least idleSeconds 2475 startIdleSleepTimer(idleSeconds); 2476 } 2477 } 2478 else 2479 { 2480 if (sleepSlider && !userIsActive) 2481 { 2482 // Manually start the idle sleep timer besides waiting for 2483 // the user to become inactive. 2484 startIdleSleepTimer( kIdleSleepRetryInterval ); 2485 } 2486 } 2487 2488 preventTransitionToUserActive(false); 2489 IOService::setAdvisoryTickleEnable( true ); 2490} 2491 2492//****************************************************************************** 2493// tellNoChangeDown 2494// 2495// Notify registered applications and kernel clients that we are not dropping 2496// power. 2497// 2498// We override the superclass implementation so we can send a different message 2499// type to the client or application being notified. 2500// 2501// This must be a vetoed idle sleep, since no other power change can be vetoed. 2502//****************************************************************************** 2503 2504void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum ) 2505{ 2506 DLOG("tellNoChangeDown %u->%u\n", 2507 (uint32_t) getPowerState(), (uint32_t) stateNum); 2508 2509 // Sleep canceled, clear the sleep trace point. 2510 tracePoint(kIOPMTracePointSystemUp); 2511 2512 systemDidNotSleep(); 2513 return tellClients( kIOMessageSystemWillNotSleep ); 2514} 2515 2516//****************************************************************************** 2517// tellChangeUp 2518// 2519// Notify registered applications and kernel clients that we are raising power. 2520// 2521// We override the superclass implementation so we can send a different message 2522// type to the client or application being notified. 2523//****************************************************************************** 2524 2525void IOPMrootDomain::tellChangeUp( unsigned long stateNum ) 2526{ 2527 2528 DLOG("tellChangeUp %u->%u\n", 2529 (uint32_t) getPowerState(), (uint32_t) stateNum); 2530 2531 ignoreTellChangeDown = false; 2532 2533 if ( stateNum == ON_STATE ) 2534 { 2535 // Direct callout into OSKext so it can disable kext unloads 2536 // during sleep/wake to prevent deadlocks. 2537 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn ); 2538 2539 // Notify platform that sleep was cancelled or resumed. 2540 getPlatform()->callPlatformFunction( 2541 sleepMessagePEFunction, false, 2542 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn, 2543 NULL, NULL, NULL); 2544 2545 if (getPowerState() == ON_STATE) 2546 { 2547 // this is a quick wake from aborted sleep 2548 systemDidNotSleep(); 2549 tellClients( kIOMessageSystemWillPowerOn ); 2550 } 2551 2552 2553 tracePoint( kIOPMTracePointWakeApplications ); 2554 tellClients( kIOMessageSystemHasPoweredOn ); 2555 } 2556} 2557 2558//****************************************************************************** 2559// sysPowerDownHandler 2560// 2561// Perform a vfs sync before system sleep. 2562//****************************************************************************** 2563 2564IOReturn IOPMrootDomain::sysPowerDownHandler( 2565 void * target, void * refCon, 2566 UInt32 messageType, IOService * service, 2567 void * messageArgs, vm_size_t argSize ) 2568{ 2569 IOReturn ret = 0; 2570 2571 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType)); 2572 2573 if (!gRootDomain) 2574 return kIOReturnUnsupported; 2575 2576 if (messageType == kIOMessageSystemWillSleep) 2577 { 2578#if HIBERNATION 2579 uint32_t mem_only = 0; 2580 IOPowerStateChangeNotification *notify = 2581 (IOPowerStateChangeNotification *)messageArgs; 2582 2583 PE_parse_boot_argn("swd_mem_only", &mem_only, sizeof(mem_only)); 2584 if ((mem_only != 1) && (gRootDomain->sleepWakeDebugIsWdogEnabled())) 2585 { 2586 notify->returnValue = 30 * 1000 * 1000; 2587 thread_call_enter1( 2588 gRootDomain->hibDebugSetupEntry, 2589 (thread_call_param_t)(uintptr_t) notify->powerRef); 2590 } 2591#endif 2592 } 2593 else if (messageType == kIOMessageSystemCapabilityChange) 2594 { 2595 IOPMSystemCapabilityChangeParameters * params = 2596 (IOPMSystemCapabilityChangeParameters *) messageArgs; 2597 2598 // Interested applications have been notified of an impending power 2599 // change and have acked (when applicable). 2600 // This is our chance to save whatever state we can before powering 2601 // down. 2602 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c, 2603 // via callout 2604 2605 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n", 2606 params->fromCapabilities, params->toCapabilities, 2607 params->changeFlags); 2608 2609 if ((params->changeFlags & kIOPMSystemCapabilityWillChange) && 2610 (params->fromCapabilities & kIOPMSystemCapabilityCPU) && 2611 (params->toCapabilities & kIOPMSystemCapabilityCPU) == 0) 2612 { 2613 // We will ack within 20 seconds 2614 params->maxWaitForReply = 20 * 1000 * 1000; 2615#if HIBERNATION 2616 gRootDomain->evaluateSystemSleepPolicyEarly(); 2617 2618 // add in time we could spend freeing pages 2619 if (gRootDomain->hibernateMode && !gRootDomain->hibernateDisabled) 2620 { 2621 params->maxWaitForReply = kCapabilityClientMaxWait; 2622 } 2623 DLOG("sysPowerDownHandler max wait %d s\n", 2624 (int) (params->maxWaitForReply / 1000 / 1000)); 2625#endif 2626 2627 // Notify platform that sleep has begun, after the early 2628 // sleep policy evaluation. 2629 getPlatform()->callPlatformFunction( 2630 sleepMessagePEFunction, false, 2631 (void *)(uintptr_t) kIOMessageSystemWillSleep, 2632 NULL, NULL, NULL); 2633 2634 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) ) 2635 { 2636 // Purposely delay the ack and hope that shutdown occurs quickly. 2637 // Another option is not to schedule the thread and wait for 2638 // ack timeout... 2639 AbsoluteTime deadline; 2640 clock_interval_to_deadline( 30, kSecondScale, &deadline ); 2641 thread_call_enter1_delayed( 2642 gRootDomain->diskSyncCalloutEntry, 2643 (thread_call_param_t)(uintptr_t) params->notifyRef, 2644 deadline ); 2645 } 2646 else 2647 thread_call_enter1( 2648 gRootDomain->diskSyncCalloutEntry, 2649 (thread_call_param_t)(uintptr_t) params->notifyRef); 2650 } 2651 else 2652 if ((params->changeFlags & kIOPMSystemCapabilityDidChange) && 2653 (params->toCapabilities & kIOPMSystemCapabilityCPU) && 2654 (params->fromCapabilities & kIOPMSystemCapabilityCPU) == 0) 2655 { 2656#if HIBERNATION 2657 // We will ack within 110 seconds 2658 params->maxWaitForReply = 110 * 1000 * 1000; 2659 2660 thread_call_enter1( 2661 gRootDomain->diskSyncCalloutEntry, 2662 (thread_call_param_t)(uintptr_t) params->notifyRef); 2663#endif 2664 } 2665 ret = kIOReturnSuccess; 2666 } 2667 2668 return ret; 2669} 2670 2671//****************************************************************************** 2672// handleQueueSleepWakeUUID 2673// 2674// Called from IOPMrootDomain when we're initiating a sleep, 2675// or indirectly from PM configd when PM decides to clear the UUID. 2676// PM clears the UUID several minutes after successful wake from sleep, 2677// so that we might associate App spindumps with the immediately previous 2678// sleep/wake. 2679// 2680// @param obj has a retain on it. We're responsible for releasing that retain. 2681//****************************************************************************** 2682 2683void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject *obj) 2684{ 2685 OSString *str = NULL; 2686 2687 if (kOSBooleanFalse == obj) 2688 { 2689 handlePublishSleepWakeUUID(NULL); 2690 } 2691 else if ((str = OSDynamicCast(OSString, obj))) 2692 { 2693 // This branch caches the UUID for an upcoming sleep/wake 2694 if (queuedSleepWakeUUIDString) { 2695 queuedSleepWakeUUIDString->release(); 2696 queuedSleepWakeUUIDString = NULL; 2697 } 2698 queuedSleepWakeUUIDString = str; 2699 queuedSleepWakeUUIDString->retain(); 2700 2701 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString->getCStringNoCopy()); 2702 } 2703 2704 if (obj) { 2705 obj->release(); 2706 } 2707 return; 2708 2709} 2710//****************************************************************************** 2711// handlePublishSleepWakeUUID 2712// 2713// Called from IOPMrootDomain when we're initiating a sleep, 2714// or indirectly from PM configd when PM decides to clear the UUID. 2715// PM clears the UUID several minutes after successful wake from sleep, 2716// so that we might associate App spindumps with the immediately previous 2717// sleep/wake. 2718//****************************************************************************** 2719 2720void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish ) 2721{ 2722 ASSERT_GATED(); 2723 2724 /* 2725 * Clear the current UUID 2726 */ 2727 if (gSleepWakeUUIDIsSet) 2728 { 2729 DLOG("SleepWake UUID cleared\n"); 2730 2731 gSleepWakeUUIDIsSet = false; 2732 2733 removeProperty(kIOPMSleepWakeUUIDKey); 2734 messageClients(kIOPMMessageSleepWakeUUIDChange, kIOPMMessageSleepWakeUUIDCleared); 2735 } 2736 2737 /* 2738 * Optionally, publish a new UUID 2739 */ 2740 if (queuedSleepWakeUUIDString && shouldPublish) { 2741 2742 OSString *publishThisUUID = NULL; 2743 2744 publishThisUUID = queuedSleepWakeUUIDString; 2745 publishThisUUID->retain(); 2746 2747 if (publishThisUUID) 2748 { 2749 setProperty(kIOPMSleepWakeUUIDKey, publishThisUUID); 2750 publishThisUUID->release(); 2751 } 2752 2753 gSleepWakeUUIDIsSet = true; 2754 messageClients(kIOPMMessageSleepWakeUUIDChange, kIOPMMessageSleepWakeUUIDSet); 2755 2756 queuedSleepWakeUUIDString->release(); 2757 queuedSleepWakeUUIDString = NULL; 2758 } 2759} 2760 2761//****************************************************************************** 2762// initializeBootSessionUUID 2763// 2764// Initialize the boot session uuid at boot up and sets it into registry. 2765//****************************************************************************** 2766 2767void IOPMrootDomain::initializeBootSessionUUID(void) 2768{ 2769 uuid_t new_uuid; 2770 uuid_string_t new_uuid_string; 2771 2772 uuid_generate(new_uuid); 2773 uuid_unparse_upper(new_uuid, new_uuid_string); 2774 memcpy(bootsessionuuid_string, new_uuid_string, sizeof(uuid_string_t)); 2775 2776 setProperty(kIOPMBootSessionUUIDKey, new_uuid_string); 2777} 2778 2779//****************************************************************************** 2780// changePowerStateTo & changePowerStateToPriv 2781// 2782// Override of these methods for logging purposes. 2783//****************************************************************************** 2784 2785IOReturn IOPMrootDomain::changePowerStateTo( unsigned long ordinal ) 2786{ 2787 DLOG("changePowerStateTo(%lu)\n", ordinal); 2788 2789 if ((ordinal != ON_STATE) && (ordinal != SLEEP_STATE)) 2790 return kIOReturnUnsupported; 2791 2792 return super::changePowerStateTo(ordinal); 2793} 2794 2795IOReturn IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal ) 2796{ 2797 DLOG("changePowerStateToPriv(%lu)\n", ordinal); 2798 2799 if ((ordinal != ON_STATE) && (ordinal != SLEEP_STATE)) 2800 return kIOReturnUnsupported; 2801 2802 return super::changePowerStateToPriv(ordinal); 2803} 2804 2805//****************************************************************************** 2806// activity detect 2807// 2808//****************************************************************************** 2809 2810bool IOPMrootDomain::activitySinceSleep(void) 2811{ 2812 return (userActivityCount != userActivityAtSleep); 2813} 2814 2815bool IOPMrootDomain::abortHibernation(void) 2816{ 2817 bool ret = activitySinceSleep(); 2818 2819 if (ret && !hibernateAborted && checkSystemCanSustainFullWake()) 2820 { 2821 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount, userActivityAtSleep); 2822 hibernateAborted = true; 2823 } 2824 return (ret); 2825} 2826 2827extern "C" int 2828hibernate_should_abort(void) 2829{ 2830 if (gRootDomain) 2831 return (gRootDomain->abortHibernation()); 2832 else 2833 return (0); 2834} 2835 2836//****************************************************************************** 2837// willNotifyPowerChildren 2838// 2839// Called after all interested drivers have all acknowledged the power change, 2840// but before any power children is informed. Dispatched though a thread call, 2841// so it is safe to perform work that might block on a sleeping disk. PM state 2842// machine (not thread) will block w/o timeout until this function returns. 2843//****************************************************************************** 2844 2845void IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState ) 2846{ 2847#if HIBERNATION 2848 if (SLEEP_STATE == newPowerState) 2849 { 2850 IOHibernateSystemSleep(); 2851 IOHibernateIOKitSleep(); 2852 } 2853#endif 2854} 2855 2856//****************************************************************************** 2857// sleepOnClamshellClosed 2858// 2859// contains the logic to determine if the system should sleep when the clamshell 2860// is closed. 2861//****************************************************************************** 2862 2863bool IOPMrootDomain::shouldSleepOnClamshellClosed( void ) 2864{ 2865 if (!clamshellExists) 2866 return false; 2867 2868 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n", 2869 clamshellClosed, clamshellDisabled, desktopMode, acAdaptorConnected, clamshellSleepDisabled); 2870 2871 return ( !clamshellDisabled && !(desktopMode && acAdaptorConnected) && !clamshellSleepDisabled ); 2872} 2873 2874void IOPMrootDomain::sendClientClamshellNotification( void ) 2875{ 2876 /* Only broadcast clamshell alert if clamshell exists. */ 2877 if (!clamshellExists) 2878 return; 2879 2880 setProperty(kAppleClamshellStateKey, 2881 clamshellClosed ? kOSBooleanTrue : kOSBooleanFalse); 2882 2883 setProperty(kAppleClamshellCausesSleepKey, 2884 shouldSleepOnClamshellClosed() ? kOSBooleanTrue : kOSBooleanFalse); 2885 2886 /* Argument to message is a bitfiel of 2887 * ( kClamshellStateBit | kClamshellSleepBit ) 2888 */ 2889 messageClients(kIOPMMessageClamshellStateChange, 2890 (void *)(uintptr_t) ( (clamshellClosed ? kClamshellStateBit : 0) 2891 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit : 0)) ); 2892} 2893 2894//****************************************************************************** 2895// getSleepSupported 2896// 2897// Deprecated 2898//****************************************************************************** 2899 2900IOOptionBits IOPMrootDomain::getSleepSupported( void ) 2901{ 2902 return( platformSleepSupport ); 2903} 2904 2905//****************************************************************************** 2906// setSleepSupported 2907// 2908// Deprecated 2909//****************************************************************************** 2910 2911void IOPMrootDomain::setSleepSupported( IOOptionBits flags ) 2912{ 2913 DLOG("setSleepSupported(%x)\n", (uint32_t) flags); 2914 OSBitOrAtomic(flags, &platformSleepSupport); 2915} 2916 2917//****************************************************************************** 2918// setDisableClamShellSleep 2919// 2920//****************************************************************************** 2921 2922void IOPMrootDomain::setDisableClamShellSleep( bool val ) 2923{ 2924 if (gIOPMWorkLoop->inGate() == false) { 2925 2926 gIOPMWorkLoop->runAction( 2927 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::setDisableClamShellSleep), 2928 (OSObject *)this, 2929 (void *)val); 2930 2931 return; 2932 } 2933 else { 2934 DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val); 2935 if ( clamshellSleepDisabled != val ) 2936 { 2937 clamshellSleepDisabled = val; 2938 // If clamshellSleepDisabled is reset to 0, reevaluate if 2939 // system need to go to sleep due to clamshell state 2940 if ( !clamshellSleepDisabled && clamshellClosed) 2941 handlePowerNotification(kLocalEvalClamshellCommand); 2942 } 2943 } 2944} 2945 2946//****************************************************************************** 2947// wakeFromDoze 2948// 2949// Deprecated. 2950//****************************************************************************** 2951 2952void IOPMrootDomain::wakeFromDoze( void ) 2953{ 2954 // Preserve symbol for familes (IOUSBFamily and IOGraphics) 2955} 2956 2957// MARK: - 2958// MARK: Features 2959 2960//****************************************************************************** 2961// publishFeature 2962// 2963// Adds a new feature to the supported features dictionary 2964//****************************************************************************** 2965 2966void IOPMrootDomain::publishFeature( const char * feature ) 2967{ 2968 publishFeature(feature, kRD_AllPowerSources, NULL); 2969} 2970 2971//****************************************************************************** 2972// publishFeature (with supported power source specified) 2973// 2974// Adds a new feature to the supported features dictionary 2975//****************************************************************************** 2976 2977void IOPMrootDomain::publishFeature( 2978 const char *feature, 2979 uint32_t supportedWhere, 2980 uint32_t *uniqueFeatureID) 2981{ 2982 static uint16_t next_feature_id = 500; 2983 2984 OSNumber *new_feature_data = NULL; 2985 OSNumber *existing_feature = NULL; 2986 OSArray *existing_feature_arr = NULL; 2987 OSObject *osObj = NULL; 2988 uint32_t feature_value = 0; 2989 2990 supportedWhere &= kRD_AllPowerSources; // mask off any craziness! 2991 2992 if(!supportedWhere) { 2993 // Feature isn't supported anywhere! 2994 return; 2995 } 2996 2997 if(next_feature_id > 5000) { 2998 // Far, far too many features! 2999 return; 3000 } 3001 3002 if(featuresDictLock) IOLockLock(featuresDictLock); 3003 3004 OSDictionary *features = 3005 (OSDictionary *) getProperty(kRootDomainSupportedFeatures); 3006 3007 // Create new features dict if necessary 3008 if ( features && OSDynamicCast(OSDictionary, features)) { 3009 features = OSDictionary::withDictionary(features); 3010 } else { 3011 features = OSDictionary::withCapacity(1); 3012 } 3013 3014 // Create OSNumber to track new feature 3015 3016 next_feature_id += 1; 3017 if( uniqueFeatureID ) { 3018 // We don't really mind if the calling kext didn't give us a place 3019 // to stash their unique id. Many kexts don't plan to unload, and thus 3020 // have no need to remove themselves later. 3021 *uniqueFeatureID = next_feature_id; 3022 } 3023 3024 feature_value = (uint32_t)next_feature_id; 3025 feature_value <<= 16; 3026 feature_value += supportedWhere; 3027 3028 new_feature_data = OSNumber::withNumber( 3029 (unsigned long long)feature_value, 32); 3030 3031 // Does features object already exist? 3032 if( (osObj = features->getObject(feature)) ) 3033 { 3034 if(( existing_feature = OSDynamicCast(OSNumber, osObj) )) 3035 { 3036 // We need to create an OSArray to hold the now 2 elements. 3037 existing_feature_arr = OSArray::withObjects( 3038 (const OSObject **)&existing_feature, 1, 2); 3039 } else if(( existing_feature_arr = OSDynamicCast(OSArray, osObj) )) 3040 { 3041 // Add object to existing array 3042 existing_feature_arr = OSArray::withArray( 3043 existing_feature_arr, 3044 existing_feature_arr->getCount() + 1); 3045 } 3046 3047 if (existing_feature_arr) 3048 { 3049 existing_feature_arr->setObject(new_feature_data); 3050 features->setObject(feature, existing_feature_arr); 3051 existing_feature_arr->release(); 3052 existing_feature_arr = 0; 3053 } 3054 } else { 3055 // The easy case: no previously existing features listed. We simply 3056 // set the OSNumber at key 'feature' and we're on our way. 3057 features->setObject(feature, new_feature_data); 3058 } 3059 3060 new_feature_data->release(); 3061 3062 setProperty(kRootDomainSupportedFeatures, features); 3063 3064 features->release(); 3065 3066 if(featuresDictLock) IOLockUnlock(featuresDictLock); 3067 3068 // Notify EnergySaver and all those in user space so they might 3069 // re-populate their feature specific UI 3070 if(pmPowerStateQueue) { 3071 pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged ); 3072 } 3073} 3074 3075//****************************************************************************** 3076// removePublishedFeature 3077// 3078// Removes previously published feature 3079//****************************************************************************** 3080 3081IOReturn IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID ) 3082{ 3083 IOReturn ret = kIOReturnError; 3084 uint32_t feature_value = 0; 3085 uint16_t feature_id = 0; 3086 bool madeAChange = false; 3087 3088 OSSymbol *dictKey = NULL; 3089 OSCollectionIterator *dictIterator = NULL; 3090 OSArray *arrayMember = NULL; 3091 OSNumber *numberMember = NULL; 3092 OSObject *osObj = NULL; 3093 OSNumber *osNum = NULL; 3094 OSArray *arrayMemberCopy; 3095 3096 if (kBadPMFeatureID == removeFeatureID) 3097 return kIOReturnNotFound; 3098 3099 if(featuresDictLock) IOLockLock(featuresDictLock); 3100 3101 OSDictionary *features = 3102 (OSDictionary *) getProperty(kRootDomainSupportedFeatures); 3103 3104 if ( features && OSDynamicCast(OSDictionary, features) ) 3105 { 3106 // Any modifications to the dictionary are made to the copy to prevent 3107 // races & crashes with userland clients. Dictionary updated 3108 // automically later. 3109 features = OSDictionary::withDictionary(features); 3110 } else { 3111 features = NULL; 3112 ret = kIOReturnNotFound; 3113 goto exit; 3114 } 3115 3116 // We iterate 'features' dictionary looking for an entry tagged 3117 // with 'removeFeatureID'. If found, we remove it from our tracking 3118 // structures and notify the OS via a general interest message. 3119 3120 dictIterator = OSCollectionIterator::withCollection(features); 3121 if(!dictIterator) { 3122 goto exit; 3123 } 3124 3125 while( (dictKey = OSDynamicCast(OSSymbol, dictIterator->getNextObject())) ) 3126 { 3127 osObj = features->getObject(dictKey); 3128 3129 // Each Feature is either tracked by an OSNumber 3130 if( osObj && (numberMember = OSDynamicCast(OSNumber, osObj)) ) 3131 { 3132 feature_value = numberMember->unsigned32BitValue(); 3133 feature_id = (uint16_t)(feature_value >> 16); 3134 3135 if( feature_id == (uint16_t)removeFeatureID ) 3136 { 3137 // Remove this node 3138 features->removeObject(dictKey); 3139 madeAChange = true; 3140 break; 3141 } 3142 3143 // Or tracked by an OSArray of OSNumbers 3144 } else if( osObj && (arrayMember = OSDynamicCast(OSArray, osObj)) ) 3145 { 3146 unsigned int arrayCount = arrayMember->getCount(); 3147 3148 for(unsigned int i=0; i<arrayCount; i++) 3149 { 3150 osNum = OSDynamicCast(OSNumber, arrayMember->getObject(i)); 3151 if(!osNum) { 3152 continue; 3153 } 3154 3155 feature_value = osNum->unsigned32BitValue(); 3156 feature_id = (uint16_t)(feature_value >> 16); 3157 3158 if( feature_id == (uint16_t)removeFeatureID ) 3159 { 3160 // Remove this node 3161 if( 1 == arrayCount ) { 3162 // If the array only contains one element, remove 3163 // the whole thing. 3164 features->removeObject(dictKey); 3165 } else { 3166 // Otherwise remove the element from a copy of the array. 3167 arrayMemberCopy = OSArray::withArray(arrayMember); 3168 if (arrayMemberCopy) 3169 { 3170 arrayMemberCopy->removeObject(i); 3171 features->setObject(dictKey, arrayMemberCopy); 3172 arrayMemberCopy->release(); 3173 } 3174 } 3175 3176 madeAChange = true; 3177 break; 3178 } 3179 } 3180 } 3181 } 3182 3183 dictIterator->release(); 3184 3185 if( madeAChange ) 3186 { 3187 ret = kIOReturnSuccess; 3188 3189 setProperty(kRootDomainSupportedFeatures, features); 3190 3191 // Notify EnergySaver and all those in user space so they might 3192 // re-populate their feature specific UI 3193 if(pmPowerStateQueue) { 3194 pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged ); 3195 } 3196 } else { 3197 ret = kIOReturnNotFound; 3198 } 3199 3200exit: 3201 if(features) features->release(); 3202 if(featuresDictLock) IOLockUnlock(featuresDictLock); 3203 return ret; 3204} 3205 3206//****************************************************************************** 3207// publishPMSetting (private) 3208// 3209// Should only be called by PMSettingObject to publish a PM Setting as a 3210// supported feature. 3211//****************************************************************************** 3212 3213void IOPMrootDomain::publishPMSetting( 3214 const OSSymbol * feature, uint32_t where, uint32_t * featureID ) 3215{ 3216 if (noPublishPMSettings && 3217 (noPublishPMSettings->getNextIndexOfObject(feature, 0) != (unsigned int)-1)) 3218 { 3219 // Setting found in noPublishPMSettings array 3220 *featureID = kBadPMFeatureID; 3221 return; 3222 } 3223 3224 publishFeature( 3225 feature->getCStringNoCopy(), where, featureID); 3226} 3227 3228//****************************************************************************** 3229// setPMSetting (private) 3230// 3231// Internal helper to relay PM settings changes from user space to individual 3232// drivers. Should be called only by IOPMrootDomain::setProperties. 3233//****************************************************************************** 3234 3235IOReturn IOPMrootDomain::setPMSetting( 3236 const OSSymbol *type, 3237 OSObject *object ) 3238{ 3239 PMSettingCallEntry *entries = 0; 3240 OSArray *chosen = 0; 3241 const OSArray *array; 3242 PMSettingObject *pmso; 3243 thread_t thisThread; 3244 int i, j, count, capacity; 3245 3246 if (NULL == type) 3247 return kIOReturnBadArgument; 3248 3249 PMSETTING_LOCK(); 3250 3251 // Update settings dict so changes are visible from copyPMSetting(). 3252 fPMSettingsDict->setObject(type, object); 3253 3254 // Prep all PMSetting objects with the given 'type' for callout. 3255 array = (const OSArray *) settingsCallbacks->getObject(type); 3256 if (!array || ((capacity = array->getCount()) == 0)) 3257 goto unlock_exit; 3258 3259 // Array to retain PMSetting objects targeted for callout. 3260 chosen = OSArray::withCapacity(capacity); 3261 if (!chosen) 3262 goto unlock_exit; // error 3263 3264 entries = IONew(PMSettingCallEntry, capacity); 3265 if (!entries) 3266 goto unlock_exit; // error 3267 memset(entries, 0, sizeof(PMSettingCallEntry) * capacity); 3268 3269 thisThread = current_thread(); 3270 3271 for (i = 0, j = 0; i<capacity; i++) 3272 { 3273 pmso = (PMSettingObject *) array->getObject(i); 3274 if (pmso->disabled) 3275 continue; 3276 entries[j].thread = thisThread; 3277 queue_enter(&pmso->calloutQueue, &entries[j], PMSettingCallEntry *, link); 3278 chosen->setObject(pmso); 3279 j++; 3280 } 3281 count = j; 3282 if (!count) 3283 goto unlock_exit; 3284 3285 PMSETTING_UNLOCK(); 3286 3287 // Call each pmso in the chosen array. 3288 for (i=0; i<count; i++) 3289 { 3290 pmso = (PMSettingObject *) chosen->getObject(i); 3291 pmso->dispatchPMSetting(type, object); 3292 } 3293 3294 PMSETTING_LOCK(); 3295 for (i=0; i<count; i++) 3296 { 3297 pmso = (PMSettingObject *) chosen->getObject(i); 3298 queue_remove(&pmso->calloutQueue, &entries[i], PMSettingCallEntry *, link); 3299 if (pmso->waitThread) 3300 { 3301 PMSETTING_WAKEUP(pmso); 3302 } 3303 } 3304unlock_exit: 3305 PMSETTING_UNLOCK(); 3306 3307 if (chosen) chosen->release(); 3308 if (entries) IODelete(entries, PMSettingCallEntry, capacity); 3309 3310 return kIOReturnSuccess; 3311} 3312 3313//****************************************************************************** 3314// copyPMSetting (public) 3315// 3316// Allows kexts to safely read setting values, without being subscribed to 3317// notifications. 3318//****************************************************************************** 3319 3320OSObject * IOPMrootDomain::copyPMSetting( 3321 OSSymbol *whichSetting) 3322{ 3323 OSObject *obj = NULL; 3324 3325 if(!whichSetting) return NULL; 3326 3327 PMSETTING_LOCK(); 3328 obj = fPMSettingsDict->getObject(whichSetting); 3329 if(obj) { 3330 obj->retain(); 3331 } 3332 PMSETTING_UNLOCK(); 3333 3334 return obj; 3335} 3336 3337//****************************************************************************** 3338// registerPMSettingController (public) 3339// 3340// direct wrapper to registerPMSettingController with uint32_t power source arg 3341//****************************************************************************** 3342 3343IOReturn IOPMrootDomain::registerPMSettingController( 3344 const OSSymbol * settings[], 3345 IOPMSettingControllerCallback func, 3346 OSObject *target, 3347 uintptr_t refcon, 3348 OSObject **handle) 3349{ 3350 return registerPMSettingController( 3351 settings, 3352 (kIOPMSupportedOnAC | kIOPMSupportedOnBatt | kIOPMSupportedOnUPS), 3353 func, target, refcon, handle); 3354} 3355 3356//****************************************************************************** 3357// registerPMSettingController (public) 3358// 3359// Kexts may register for notifications when a particular setting is changed. 3360// A list of settings is available in IOPM.h. 3361// Arguments: 3362// * settings - An OSArray containing OSSymbols. Caller should populate this 3363// array with a list of settings caller wants notifications from. 3364// * func - A C function callback of the type IOPMSettingControllerCallback 3365// * target - caller may provide an OSObject *, which PM will pass as an 3366// target to calls to "func" 3367// * refcon - caller may provide an void *, which PM will pass as an 3368// argument to calls to "func" 3369// * handle - This is a return argument. We will populate this pointer upon 3370// call success. Hold onto this and pass this argument to 3371// IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext 3372// Returns: 3373// kIOReturnSuccess on success 3374//****************************************************************************** 3375 3376IOReturn IOPMrootDomain::registerPMSettingController( 3377 const OSSymbol * settings[], 3378 uint32_t supportedPowerSources, 3379 IOPMSettingControllerCallback func, 3380 OSObject *target, 3381 uintptr_t refcon, 3382 OSObject **handle) 3383{ 3384 PMSettingObject *pmso = NULL; 3385 OSObject *pmsh = NULL; 3386 OSArray *list = NULL; 3387 int i; 3388 3389 if (NULL == settings || 3390 NULL == func || 3391 NULL == handle) 3392 { 3393 return kIOReturnBadArgument; 3394 } 3395 3396 pmso = PMSettingObject::pmSettingObject( 3397 (IOPMrootDomain *) this, func, target, 3398 refcon, supportedPowerSources, settings, &pmsh); 3399 3400 if (!pmso) { 3401 *handle = NULL; 3402 return kIOReturnInternalError; 3403 } 3404 3405 PMSETTING_LOCK(); 3406 for (i=0; settings[i]; i++) 3407 { 3408 list = (OSArray *) settingsCallbacks->getObject(settings[i]); 3409 if (!list) { 3410 // New array of callbacks for this setting 3411 list = OSArray::withCapacity(1); 3412 settingsCallbacks->setObject(settings[i], list); 3413 list->release(); 3414 } 3415 3416 // Add caller to the callback list 3417 list->setObject(pmso); 3418 } 3419 PMSETTING_UNLOCK(); 3420 3421 // Return handle to the caller, the setting object is private. 3422 *handle = pmsh; 3423 3424 return kIOReturnSuccess; 3425} 3426 3427//****************************************************************************** 3428// deregisterPMSettingObject (private) 3429// 3430// Only called from PMSettingObject. 3431//****************************************************************************** 3432 3433void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject * pmso ) 3434{ 3435 thread_t thisThread = current_thread(); 3436 PMSettingCallEntry *callEntry; 3437 OSCollectionIterator *iter; 3438 OSSymbol *sym; 3439 OSArray *array; 3440 int index; 3441 bool wait; 3442 3443 PMSETTING_LOCK(); 3444 3445 pmso->disabled = true; 3446 3447 // Wait for all callout threads to finish. 3448 do { 3449 wait = false; 3450 queue_iterate(&pmso->calloutQueue, callEntry, PMSettingCallEntry *, link) 3451 { 3452 if (callEntry->thread != thisThread) 3453 { 3454 wait = true; 3455 break; 3456 } 3457 } 3458 if (wait) 3459 { 3460 assert(0 == pmso->waitThread); 3461 pmso->waitThread = thisThread; 3462 PMSETTING_WAIT(pmso); 3463 pmso->waitThread = 0; 3464 } 3465 } while (wait); 3466 3467 // Search each PM settings array in the kernel. 3468 iter = OSCollectionIterator::withCollection(settingsCallbacks); 3469 if (iter) 3470 { 3471 while ((sym = OSDynamicCast(OSSymbol, iter->getNextObject()))) 3472 { 3473 array = (OSArray *) settingsCallbacks->getObject(sym); 3474 index = array->getNextIndexOfObject(pmso, 0); 3475 if (-1 != index) { 3476 array->removeObject(index); 3477 } 3478 } 3479 iter->release(); 3480 } 3481 3482 PMSETTING_UNLOCK(); 3483 3484 pmso->release(); 3485} 3486 3487//****************************************************************************** 3488// informCPUStateChange 3489// 3490// Call into PM CPU code so that CPU power savings may dynamically adjust for 3491// running on battery, with the lid closed, etc. 3492// 3493// informCPUStateChange is a no-op on non x86 systems 3494// only x86 has explicit support in the IntelCPUPowerManagement kext 3495//****************************************************************************** 3496 3497void IOPMrootDomain::informCPUStateChange( 3498 uint32_t type, 3499 uint32_t value ) 3500{ 3501#if defined(__i386__) || defined(__x86_64__) 3502 3503 pmioctlVariableInfo_t varInfoStruct; 3504 int pmCPUret = 0; 3505 const char *varNameStr = NULL; 3506 int32_t *varIndex = NULL; 3507 3508 if (kInformAC == type) { 3509 varNameStr = kIOPMRootDomainBatPowerCString; 3510 varIndex = &idxPMCPULimitedPower; 3511 } else if (kInformLid == type) { 3512 varNameStr = kIOPMRootDomainLidCloseCString; 3513 varIndex = &idxPMCPUClamshell; 3514 } else { 3515 return; 3516 } 3517 3518 // Set the new value! 3519 // pmCPUControl will assign us a new ID if one doesn't exist yet 3520 bzero(&varInfoStruct, sizeof(pmioctlVariableInfo_t)); 3521 varInfoStruct.varID = *varIndex; 3522 varInfoStruct.varType = vBool; 3523 varInfoStruct.varInitValue = value; 3524 varInfoStruct.varCurValue = value; 3525 strncpy( (char *)varInfoStruct.varName, 3526 (const char *)varNameStr, 3527 strlen(varNameStr) + 1 ); 3528 3529 // Set! 3530 pmCPUret = pmCPUControl( PMIOCSETVARINFO, (void *)&varInfoStruct ); 3531 3532 // pmCPU only assigns numerical id's when a new varName is specified 3533 if ((0 == pmCPUret) 3534 && (*varIndex == kCPUUnknownIndex)) 3535 { 3536 // pmCPUControl has assigned us a new variable ID. 3537 // Let's re-read the structure we just SET to learn that ID. 3538 pmCPUret = pmCPUControl( PMIOCGETVARNAMEINFO, (void *)&varInfoStruct ); 3539 3540 if (0 == pmCPUret) 3541 { 3542 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower 3543 *varIndex = varInfoStruct.varID; 3544 } 3545 } 3546 3547 return; 3548 3549#endif /* __i386__ || __x86_64__ */ 3550} 3551 3552// MARK: - 3553// MARK: Deep Sleep Policy 3554 3555#if HIBERNATION 3556 3557//****************************************************************************** 3558// evaluateSystemSleepPolicy 3559//****************************************************************************** 3560 3561#define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy" 3562 3563// Sleep flags 3564enum { 3565 kIOPMSleepFlagHibernate = 0x00000001, 3566 kIOPMSleepFlagSleepTimerEnable = 0x00000002 3567}; 3568 3569struct IOPMSystemSleepPolicyEntry 3570{ 3571 uint32_t factorMask; 3572 uint32_t factorBits; 3573 uint32_t sleepFlags; 3574 uint32_t wakeEvents; 3575} __attribute__((packed)); 3576 3577struct IOPMSystemSleepPolicyTable 3578{ 3579 uint32_t signature; 3580 uint16_t version; 3581 uint16_t entryCount; 3582 IOPMSystemSleepPolicyEntry entries[]; 3583} __attribute__((packed)); 3584 3585enum { 3586 kIOPMSleepAttributeHibernateSetup = 0x00000001, 3587 kIOPMSleepAttributeHibernateSleep = 0x00000002 3588}; 3589 3590static uint32_t 3591getSleepTypeAttributes( uint32_t sleepType ) 3592{ 3593 static const uint32_t sleepTypeAttributes[ kIOPMSleepTypeLast ] = 3594 { 3595 /* invalid */ 0, 3596 /* abort */ 0, 3597 /* normal */ 0, 3598 /* safesleep */ kIOPMSleepAttributeHibernateSetup, 3599 /* hibernate */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep, 3600 /* standby */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep, 3601 /* poweroff */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep, 3602 /* deepidle */ 0 3603 }; 3604 3605 if (sleepType >= kIOPMSleepTypeLast) 3606 return 0; 3607 3608 return sleepTypeAttributes[sleepType]; 3609} 3610 3611bool IOPMrootDomain::evaluateSystemSleepPolicy( 3612 IOPMSystemSleepParameters * params, int sleepPhase, uint32_t * hibMode ) 3613{ 3614 const IOPMSystemSleepPolicyTable * pt; 3615 OSObject * prop = 0; 3616 OSData * policyData; 3617 uint64_t currentFactors = 0; 3618 uint32_t standbyDelay = 0; 3619 uint32_t powerOffDelay = 0; 3620 uint32_t powerOffTimer = 0; 3621 uint32_t mismatch; 3622 bool standbyEnabled; 3623 bool powerOffEnabled; 3624 bool found = false; 3625 3626 // Get platform's sleep policy table 3627 if (!gSleepPolicyHandler) 3628 { 3629 prop = getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey); 3630 if (!prop) goto done; 3631 } 3632 3633 // Fetch additional settings 3634 standbyEnabled = (getSleepOption(kIOPMDeepSleepDelayKey, &standbyDelay) 3635 && (getProperty(kIOPMDeepSleepEnabledKey) == kOSBooleanTrue)); 3636 powerOffEnabled = (getSleepOption(kIOPMAutoPowerOffDelayKey, &powerOffDelay) 3637 && (getProperty(kIOPMAutoPowerOffEnabledKey) == kOSBooleanTrue)); 3638 if (!getSleepOption(kIOPMAutoPowerOffTimerKey, &powerOffTimer)) 3639 powerOffTimer = powerOffDelay; 3640 3641 DLOG("phase %d, standby %d delay %u, poweroff %d delay %u timer %u, hibernate 0x%x\n", 3642 sleepPhase, standbyEnabled, standbyDelay, 3643 powerOffEnabled, powerOffDelay, powerOffTimer, *hibMode); 3644 3645 // pmset level overrides 3646 if ((*hibMode & kIOHibernateModeOn) == 0) 3647 { 3648 if (!gSleepPolicyHandler) 3649 { 3650 standbyEnabled = false; 3651 powerOffEnabled = false; 3652 } 3653 } 3654 else if (!(*hibMode & kIOHibernateModeSleep)) 3655 { 3656 // Force hibernate (i.e. mode 25) 3657 // If standby is enabled, force standy. 3658 // If poweroff is enabled, force poweroff. 3659 if (standbyEnabled) 3660 currentFactors |= kIOPMSleepFactorStandbyForced; 3661 else if (powerOffEnabled) 3662 currentFactors |= kIOPMSleepFactorAutoPowerOffForced; 3663 else 3664 currentFactors |= kIOPMSleepFactorHibernateForced; 3665 } 3666 3667 // Current factors based on environment and assertions 3668 if (sleepTimerMaintenance) 3669 currentFactors |= kIOPMSleepFactorSleepTimerWake; 3670 if (standbyEnabled && sleepToStandby && !gSleepPolicyHandler) 3671 currentFactors |= kIOPMSleepFactorSleepTimerWake; 3672 if (!clamshellClosed) 3673 currentFactors |= kIOPMSleepFactorLidOpen; 3674 if (acAdaptorConnected) 3675 currentFactors |= kIOPMSleepFactorACPower; 3676 if (lowBatteryCondition) 3677 currentFactors |= kIOPMSleepFactorBatteryLow; 3678 if (!standbyDelay) 3679 currentFactors |= kIOPMSleepFactorStandbyNoDelay; 3680 if (!standbyEnabled) 3681 currentFactors |= kIOPMSleepFactorStandbyDisabled; 3682 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit) != 3683 kIOPMDriverAssertionLevelOff) 3684 currentFactors |= kIOPMSleepFactorUSBExternalDevice; 3685 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit) != 3686 kIOPMDriverAssertionLevelOff) 3687 currentFactors |= kIOPMSleepFactorBluetoothHIDDevice; 3688 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit) != 3689 kIOPMDriverAssertionLevelOff) 3690 currentFactors |= kIOPMSleepFactorExternalMediaMounted; 3691 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5) != 3692 kIOPMDriverAssertionLevelOff) 3693 currentFactors |= kIOPMSleepFactorThunderboltDevice; 3694 if (_scheduledAlarms != 0) 3695 currentFactors |= kIOPMSleepFactorRTCAlarmScheduled; 3696 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit) != 3697 kIOPMDriverAssertionLevelOff) 3698 currentFactors |= kIOPMSleepFactorMagicPacketWakeEnabled; 3699#define TCPKEEPALIVE 1 3700#if TCPKEEPALIVE 3701 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit) != 3702 kIOPMDriverAssertionLevelOff) 3703 currentFactors |= kIOPMSleepFactorNetworkKeepAliveActive; 3704#endif 3705 if (!powerOffEnabled) 3706 currentFactors |= kIOPMSleepFactorAutoPowerOffDisabled; 3707 if (desktopMode) 3708 currentFactors |= kIOPMSleepFactorExternalDisplay; 3709 if (userWasActive) 3710 currentFactors |= kIOPMSleepFactorLocalUserActivity; 3711 if (darkWakeHibernateError && !CAP_HIGHEST(kIOPMSystemCapabilityGraphics)) 3712 currentFactors |= kIOPMSleepFactorHibernateFailed; 3713 3714 DLOG("sleep factors 0x%llx\n", currentFactors); 3715 3716 if (gSleepPolicyHandler) 3717 { 3718 uint32_t savedHibernateMode; 3719 IOReturn result; 3720 3721 if (!gSleepPolicyVars) 3722 { 3723 gSleepPolicyVars = IONew(IOPMSystemSleepPolicyVariables, 1); 3724 if (!gSleepPolicyVars) 3725 goto done; 3726 bzero(gSleepPolicyVars, sizeof(*gSleepPolicyVars)); 3727 } 3728 gSleepPolicyVars->signature = kIOPMSystemSleepPolicySignature; 3729 gSleepPolicyVars->version = kIOPMSystemSleepPolicyVersion; 3730 gSleepPolicyVars->currentCapability = _currentCapability; 3731 gSleepPolicyVars->highestCapability = _highestCapability; 3732 gSleepPolicyVars->sleepFactors = currentFactors; 3733 gSleepPolicyVars->sleepReason = lastSleepReason; 3734 gSleepPolicyVars->sleepPhase = sleepPhase; 3735 gSleepPolicyVars->standbyDelay = standbyDelay; 3736 gSleepPolicyVars->poweroffDelay = powerOffDelay; 3737 gSleepPolicyVars->scheduledAlarms = _scheduledAlarms | _userScheduledAlarm; 3738 gSleepPolicyVars->poweroffTimer = powerOffTimer; 3739 3740 if (kIOPMSleepPhase0 == sleepPhase) 3741 { 3742 // preserve hibernateMode 3743 savedHibernateMode = gSleepPolicyVars->hibernateMode; 3744 gSleepPolicyVars->hibernateMode = *hibMode; 3745 } 3746 else if (kIOPMSleepPhase1 == sleepPhase) 3747 { 3748 // use original hibernateMode for phase2 3749 gSleepPolicyVars->hibernateMode = *hibMode; 3750 } 3751 3752 result = gSleepPolicyHandler(gSleepPolicyTarget, gSleepPolicyVars, params); 3753 3754 if (kIOPMSleepPhase0 == sleepPhase) 3755 { 3756 // restore hibernateMode 3757 gSleepPolicyVars->hibernateMode = savedHibernateMode; 3758 } 3759 3760 if ((result != kIOReturnSuccess) || 3761 (kIOPMSleepTypeInvalid == params->sleepType) || 3762 (params->sleepType >= kIOPMSleepTypeLast) || 3763 (kIOPMSystemSleepParametersVersion != params->version)) 3764 { 3765 MSG("sleep policy handler error\n"); 3766 goto done; 3767 } 3768 3769 if ((getSleepTypeAttributes(params->sleepType) & 3770 kIOPMSleepAttributeHibernateSetup) && 3771 ((*hibMode & kIOHibernateModeOn) == 0)) 3772 { 3773 *hibMode |= (kIOHibernateModeOn | kIOHibernateModeSleep); 3774 } 3775 3776 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n", 3777 params->version, params->sleepType, params->sleepFlags, 3778 params->ecWakeEvents, params->ecWakeTimer, params->ecPoweroffTimer); 3779 found = true; 3780 goto done; 3781 } 3782 3783 // Policy table is meaningless without standby enabled 3784 if (!standbyEnabled) 3785 goto done; 3786 3787 // Validate the sleep policy table 3788 policyData = OSDynamicCast(OSData, prop); 3789 if (!policyData || (policyData->getLength() <= sizeof(IOPMSystemSleepPolicyTable))) 3790 goto done; 3791 3792 pt = (const IOPMSystemSleepPolicyTable *) policyData->getBytesNoCopy(); 3793 if ((pt->signature != kIOPMSystemSleepPolicySignature) || 3794 (pt->version != 1) || (0 == pt->entryCount)) 3795 goto done; 3796 3797 if (((policyData->getLength() - sizeof(IOPMSystemSleepPolicyTable)) != 3798 (sizeof(IOPMSystemSleepPolicyEntry) * pt->entryCount))) 3799 goto done; 3800 3801 for (uint32_t i = 0; i < pt->entryCount; i++) 3802 { 3803 const IOPMSystemSleepPolicyEntry * entry = &pt->entries[i]; 3804 mismatch = (((uint32_t)currentFactors ^ entry->factorBits) & entry->factorMask); 3805 3806 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n", 3807 entry->factorMask, entry->factorBits, 3808 entry->sleepFlags, entry->wakeEvents, mismatch); 3809 if (mismatch) 3810 continue; 3811 3812 DLOG("^ found match\n"); 3813 found = true; 3814 3815 params->version = kIOPMSystemSleepParametersVersion; 3816 params->reserved1 = 1; 3817 if (entry->sleepFlags & kIOPMSleepFlagHibernate) 3818 params->sleepType = kIOPMSleepTypeStandby; 3819 else 3820 params->sleepType = kIOPMSleepTypeNormalSleep; 3821 3822 params->ecWakeEvents = entry->wakeEvents; 3823 if (entry->sleepFlags & kIOPMSleepFlagSleepTimerEnable) 3824 { 3825 if (kIOPMSleepPhase2 == sleepPhase) 3826 { 3827 clock_sec_t now_secs = gIOLastSleepTime.tv_sec; 3828 3829 if (!_standbyTimerResetSeconds || 3830 (now_secs <= _standbyTimerResetSeconds)) 3831 { 3832 // Reset standby timer adjustment 3833 _standbyTimerResetSeconds = now_secs; 3834 DLOG("standby delay %u, reset %u\n", 3835 standbyDelay, (uint32_t) _standbyTimerResetSeconds); 3836 } 3837 else if (standbyDelay) 3838 { 3839 // Shorten the standby delay timer 3840 clock_sec_t elapsed = now_secs - _standbyTimerResetSeconds; 3841 if (standbyDelay > elapsed) 3842 standbyDelay -= elapsed; 3843 else 3844 standbyDelay = 1; // must be > 0 3845 3846 DLOG("standby delay %u, elapsed %u\n", 3847 standbyDelay, (uint32_t) elapsed); 3848 } 3849 } 3850 params->ecWakeTimer = standbyDelay; 3851 } 3852 else if (kIOPMSleepPhase2 == sleepPhase) 3853 { 3854 // A sleep that does not enable the sleep timer will reset 3855 // the standby delay adjustment. 3856 _standbyTimerResetSeconds = 0; 3857 } 3858 break; 3859 } 3860 3861done: 3862 if (prop) 3863 prop->release(); 3864 3865 return found; 3866} 3867 3868static IOPMSystemSleepParameters gEarlySystemSleepParams; 3869 3870void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void ) 3871{ 3872 // Evaluate early (priority interest phase), before drivers sleep. 3873 3874 DLOG("%s\n", __FUNCTION__); 3875 removeProperty(kIOPMSystemSleepParametersKey); 3876 3877 // Full wake resets the standby timer delay adjustment 3878 if (_highestCapability & kIOPMSystemCapabilityGraphics) 3879 _standbyTimerResetSeconds = 0; 3880 3881 hibernateDisabled = false; 3882 hibernateMode = 0; 3883 getSleepOption(kIOHibernateModeKey, &hibernateMode); 3884 3885 // Save for late evaluation if sleep is aborted 3886 bzero(&gEarlySystemSleepParams, sizeof(gEarlySystemSleepParams)); 3887 3888 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams, kIOPMSleepPhase1, 3889 &hibernateMode)) 3890 { 3891 if (!hibernateRetry && 3892 ((getSleepTypeAttributes(gEarlySystemSleepParams.sleepType) & 3893 kIOPMSleepAttributeHibernateSetup) == 0)) 3894 { 3895 // skip hibernate setup 3896 hibernateDisabled = true; 3897 } 3898 } 3899 3900 // Publish IOPMSystemSleepType 3901 uint32_t sleepType = gEarlySystemSleepParams.sleepType; 3902 if (sleepType == kIOPMSleepTypeInvalid) 3903 { 3904 // no sleep policy 3905 sleepType = kIOPMSleepTypeNormalSleep; 3906 if (hibernateMode & kIOHibernateModeOn) 3907 sleepType = (hibernateMode & kIOHibernateModeSleep) ? 3908 kIOPMSleepTypeSafeSleep : kIOPMSleepTypeHibernate; 3909 } 3910 else if ((sleepType == kIOPMSleepTypeStandby) && 3911 (gEarlySystemSleepParams.ecPoweroffTimer)) 3912 { 3913 // report the lowest possible sleep state 3914 sleepType = kIOPMSleepTypePowerOff; 3915 } 3916 3917 setProperty(kIOPMSystemSleepTypeKey, sleepType, 32); 3918} 3919 3920void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void ) 3921{ 3922 IOPMSystemSleepParameters params; 3923 OSData * paramsData; 3924 3925 // Evaluate sleep policy after sleeping drivers but before platform sleep. 3926 3927 DLOG("%s\n", __FUNCTION__); 3928 3929 bzero(¶ms, sizeof(params)); 3930 if (evaluateSystemSleepPolicy(¶ms, kIOPMSleepPhase2, &hibernateMode)) 3931 { 3932 if ((hibernateDisabled || hibernateAborted) && 3933 (getSleepTypeAttributes(params.sleepType) & 3934 kIOPMSleepAttributeHibernateSetup)) 3935 { 3936 // Final evaluation picked a state requiring hibernation, 3937 // but hibernate setup was skipped. Arm a short sleep using 3938 // the early non-hibernate sleep parameters. 3939 // Set hibernateRetry flag to force hibernate setup on the 3940 // next sleep. 3941 3942 bcopy(&gEarlySystemSleepParams, ¶ms, sizeof(params)); 3943 params.sleepType = kIOPMSleepTypeAbortedSleep; 3944 params.ecWakeTimer = 1; 3945 hibernateRetry = true; 3946 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d\n", 3947 params.ecWakeTimer, hibernateDisabled, hibernateAborted); 3948 } 3949 else 3950 { 3951 hibernateRetry = false; 3952 } 3953 3954 paramsData = OSData::withBytes(¶ms, sizeof(params)); 3955 if (paramsData) 3956 { 3957 setProperty(kIOPMSystemSleepParametersKey, paramsData); 3958 paramsData->release(); 3959 } 3960 3961 if (getSleepTypeAttributes(params.sleepType) & 3962 kIOPMSleepAttributeHibernateSleep) 3963 { 3964 // Disable sleep to force hibernation 3965 gIOHibernateMode &= ~kIOHibernateModeSleep; 3966 } 3967 } 3968} 3969 3970bool IOPMrootDomain::getHibernateSettings( 3971 uint32_t * hibernateModePtr, 3972 uint32_t * hibernateFreeRatio, 3973 uint32_t * hibernateFreeTime ) 3974{ 3975 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly() 3976 // has updated the hibernateDisabled flag. 3977 3978 bool ok = getSleepOption(kIOHibernateModeKey, hibernateModePtr); 3979 getSleepOption(kIOHibernateFreeRatioKey, hibernateFreeRatio); 3980 getSleepOption(kIOHibernateFreeTimeKey, hibernateFreeTime); 3981 if (hibernateDisabled) 3982 *hibernateModePtr = 0; 3983 else if (gSleepPolicyHandler) 3984 *hibernateModePtr = hibernateMode; 3985 DLOG("hibernateMode 0x%x\n", *hibernateModePtr); 3986 return ok; 3987} 3988 3989bool IOPMrootDomain::getSleepOption( const char * key, uint32_t * option ) 3990{ 3991 OSObject * optionsProp; 3992 OSDictionary * optionsDict; 3993 OSObject * obj = 0; 3994 OSNumber * num; 3995 bool ok = false; 3996 3997 optionsProp = copyProperty(kRootDomainSleepOptionsKey); 3998 optionsDict = OSDynamicCast(OSDictionary, optionsProp); 3999 4000 if (optionsDict) 4001 { 4002 obj = optionsDict->getObject(key); 4003 if (obj) obj->retain(); 4004 } 4005 if (!obj) 4006 { 4007 obj = copyProperty(key); 4008 } 4009 if (obj && (num = OSDynamicCast(OSNumber, obj))) 4010 { 4011 *option = num->unsigned32BitValue(); 4012 ok = true; 4013 } 4014 4015 if (obj) 4016 obj->release(); 4017 if (optionsProp) 4018 optionsProp->release(); 4019 4020 return true; 4021} 4022#endif /* HIBERNATION */ 4023 4024IOReturn IOPMrootDomain::getSystemSleepType( uint32_t * sleepType ) 4025{ 4026#if HIBERNATION 4027 IOPMSystemSleepParameters params; 4028 uint32_t hibMode = 0; 4029 bool ok; 4030 4031 if (gIOPMWorkLoop->inGate() == false) 4032 { 4033 IOReturn ret = gIOPMWorkLoop->runAction( 4034 OSMemberFunctionCast(IOWorkLoop::Action, this, 4035 &IOPMrootDomain::getSystemSleepType), 4036 (OSObject *) this, 4037 (void *) sleepType); 4038 return ret; 4039 } 4040 4041 getSleepOption(kIOHibernateModeKey, &hibMode); 4042 bzero(¶ms, sizeof(params)); 4043 4044 ok = evaluateSystemSleepPolicy(¶ms, kIOPMSleepPhase0, &hibMode); 4045 if (ok) 4046 { 4047 *sleepType = params.sleepType; 4048 return kIOReturnSuccess; 4049 } 4050#endif 4051 4052 return kIOReturnUnsupported; 4053} 4054 4055// MARK: - 4056// MARK: Shutdown and Restart 4057 4058//****************************************************************************** 4059// handlePlatformHaltRestart 4060// 4061//****************************************************************************** 4062 4063struct HaltRestartApplierContext { 4064 IOPMrootDomain * RootDomain; 4065 unsigned long PowerState; 4066 IOPMPowerFlags PowerFlags; 4067 UInt32 MessageType; 4068 UInt32 Counter; 4069}; 4070 4071static void 4072platformHaltRestartApplier( OSObject * object, void * context ) 4073{ 4074 IOPowerStateChangeNotification notify; 4075 HaltRestartApplierContext * ctx; 4076 AbsoluteTime startTime; 4077 UInt32 deltaTime; 4078 4079 ctx = (HaltRestartApplierContext *) context; 4080 4081 memset(¬ify, 0, sizeof(notify)); 4082 notify.powerRef = (void *)(uintptr_t)ctx->Counter; 4083 notify.returnValue = 0; 4084 notify.stateNumber = ctx->PowerState; 4085 notify.stateFlags = ctx->PowerFlags; 4086 4087 clock_get_uptime(&startTime); 4088 ctx->RootDomain->messageClient( ctx->MessageType, object, (void *)¬ify ); 4089 deltaTime = computeDeltaTimeMS(&startTime); 4090 4091 if ((deltaTime > kPMHaltTimeoutMS) || 4092 (gIOKitDebug & kIOLogPMRootDomain)) 4093 { 4094 _IOServiceInterestNotifier * notifier; 4095 notifier = OSDynamicCast(_IOServiceInterestNotifier, object); 4096 4097 // IOService children of IOPMrootDomain are not instrumented. 4098 // Only IORootParent currently falls under that group. 4099 4100 if (notifier) 4101 { 4102 LOG("%s handler %p took %u ms\n", 4103 (ctx->MessageType == kIOMessageSystemWillPowerOff) ? "PowerOff" : 4104 (ctx->MessageType == kIOMessageSystemPagingOff) ? "PagingOff" : "Restart", 4105 OBFUSCATE(notifier->handler), (uint32_t) deltaTime ); 4106 } 4107 } 4108 4109 ctx->Counter++; 4110} 4111 4112void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type ) 4113{ 4114 HaltRestartApplierContext ctx; 4115 AbsoluteTime startTime; 4116 UInt32 deltaTime; 4117 4118 memset(&ctx, 0, sizeof(ctx)); 4119 ctx.RootDomain = this; 4120 4121 clock_get_uptime(&startTime); 4122 switch (pe_type) 4123 { 4124 case kPEHaltCPU: 4125 case kPEUPSDelayHaltCPU: 4126 ctx.PowerState = OFF_STATE; 4127 ctx.MessageType = kIOMessageSystemWillPowerOff; 4128 break; 4129 4130 case kPERestartCPU: 4131 ctx.PowerState = RESTART_STATE; 4132 ctx.MessageType = kIOMessageSystemWillRestart; 4133 break; 4134 4135 case kPEPagingOff: 4136 ctx.PowerState = ON_STATE; 4137 ctx.MessageType = kIOMessageSystemPagingOff; 4138 IOService::updateConsoleUsers(NULL, kIOMessageSystemPagingOff); 4139#if HIBERNATION 4140 IOHibernateSystemRestart(); 4141#endif 4142 break; 4143 4144 default: 4145 return; 4146 } 4147 4148 // Notify legacy clients 4149 applyToInterested(gIOPriorityPowerStateInterest, platformHaltRestartApplier, &ctx); 4150 4151 // For normal shutdown, turn off File Server Mode. 4152 if (kPEHaltCPU == pe_type) 4153 { 4154 const OSSymbol * setting = OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey); 4155 OSNumber * num = OSNumber::withNumber((unsigned long long) 0, 32); 4156 if (setting && num) 4157 { 4158 setPMSetting(setting, num); 4159 setting->release(); 4160 num->release(); 4161 } 4162 } 4163 4164 if (kPEPagingOff != pe_type) 4165 { 4166 // Notify in power tree order 4167 notifySystemShutdown(this, ctx.MessageType); 4168 } 4169 4170 IOCPURunPlatformHaltRestartActions(pe_type); 4171 4172 deltaTime = computeDeltaTimeMS(&startTime); 4173 LOG("%s all drivers took %u ms\n", 4174 (ctx.MessageType == kIOMessageSystemWillPowerOff) ? "PowerOff" : 4175 (ctx.MessageType == kIOMessageSystemPagingOff) ? "PagingOff" : "Restart", 4176 (uint32_t) deltaTime ); 4177} 4178 4179//****************************************************************************** 4180// shutdownSystem 4181// 4182//****************************************************************************** 4183 4184IOReturn IOPMrootDomain::shutdownSystem( void ) 4185{ 4186 return kIOReturnUnsupported; 4187} 4188 4189//****************************************************************************** 4190// restartSystem 4191// 4192//****************************************************************************** 4193 4194IOReturn IOPMrootDomain::restartSystem( void ) 4195{ 4196 return kIOReturnUnsupported; 4197} 4198 4199// MARK: - 4200// MARK: System Capability 4201 4202//****************************************************************************** 4203// tagPowerPlaneService 4204// 4205// Running on PM work loop thread. 4206//****************************************************************************** 4207 4208void IOPMrootDomain::tagPowerPlaneService( 4209 IOService * service, 4210 IOPMActions * actions ) 4211{ 4212 uint32_t flags = 0; 4213 bool isDisplayWrangler; 4214 4215 memset(actions, 0, sizeof(*actions)); 4216 actions->target = this; 4217 4218 if (service == this) 4219 { 4220 actions->actionPowerChangeStart = 4221 OSMemberFunctionCast( 4222 IOPMActionPowerChangeStart, this, 4223 &IOPMrootDomain::handleOurPowerChangeStart); 4224 4225 actions->actionPowerChangeDone = 4226 OSMemberFunctionCast( 4227 IOPMActionPowerChangeDone, this, 4228 &IOPMrootDomain::handleOurPowerChangeDone); 4229 4230 actions->actionPowerChangeOverride = 4231 OSMemberFunctionCast( 4232 IOPMActionPowerChangeOverride, this, 4233 &IOPMrootDomain::overrideOurPowerChange); 4234 return; 4235 } 4236 4237#if !NO_KERNEL_HID 4238 isDisplayWrangler = (0 != service->metaCast("IODisplayWrangler")); 4239 if (isDisplayWrangler) 4240 { 4241 wrangler = service; 4242 } 4243#else 4244 isDisplayWrangler = false; 4245#endif 4246 4247#if defined(__i386__) || defined(__x86_64__) 4248 if (isDisplayWrangler) 4249 flags |= kPMActionsFlagIsDisplayWrangler; 4250 if (service->getProperty("IOPMStrictTreeOrder")) 4251 flags |= kPMActionsFlagIsGraphicsDevice; 4252 if (service->getProperty("IOPMUnattendedWakePowerState")) 4253 flags |= kPMActionsFlagIsAudioDevice; 4254#endif 4255 4256 // Find the power connection object that is a child of the PCI host 4257 // bridge, and has a graphics/audio device attached below. Mark the 4258 // power branch for delayed child notifications. 4259 4260 if (flags) 4261 { 4262 IORegistryEntry * child = service; 4263 IORegistryEntry * parent = child->getParentEntry(gIOPowerPlane); 4264 4265 while (child != this) 4266 { 4267 if ((parent == pciHostBridgeDriver) || 4268 (parent == this)) 4269 { 4270 if (OSDynamicCast(IOPowerConnection, child)) 4271 { 4272 IOPowerConnection * conn = (IOPowerConnection *) child; 4273 conn->delayChildNotification = true; 4274 } 4275 break; 4276 } 4277 child = parent; 4278 parent = child->getParentEntry(gIOPowerPlane); 4279 } 4280 } 4281 4282 if (flags) 4283 { 4284 DLOG("%s tag flags %x\n", service->getName(), flags); 4285 actions->parameter |= flags; 4286 actions->actionPowerChangeOverride = 4287 OSMemberFunctionCast( 4288 IOPMActionPowerChangeOverride, this, 4289 &IOPMrootDomain::overridePowerChangeForUIService); 4290 4291 if (flags & kPMActionsFlagIsDisplayWrangler) 4292 { 4293 actions->actionActivityTickle = 4294 OSMemberFunctionCast( 4295 IOPMActionActivityTickle, this, 4296 &IOPMrootDomain::handleActivityTickleForDisplayWrangler); 4297 4298 actions->actionUpdatePowerClient = 4299 OSMemberFunctionCast( 4300 IOPMActionUpdatePowerClient, this, 4301 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler); 4302 } 4303 return; 4304 } 4305 4306 // Locate the first PCI host bridge for PMTrace. 4307 if (!pciHostBridgeDevice && service->metaCast("IOPCIBridge")) 4308 { 4309 IOService * provider = service->getProvider(); 4310 if (OSDynamicCast(IOPlatformDevice, provider) && 4311 provider->inPlane(gIODTPlane)) 4312 { 4313 pciHostBridgeDevice = provider; 4314 pciHostBridgeDriver = service; 4315 DLOG("PMTrace found PCI host bridge %s->%s\n", 4316 provider->getName(), service->getName()); 4317 } 4318 } 4319 4320 // Tag top-level PCI devices. The order of PMinit() call does not 4321 // change across boots and is used as the PCI bit number. 4322 if (pciHostBridgeDevice && service->metaCast("IOPCIDevice")) 4323 { 4324 // Would prefer to check built-in property, but tagPowerPlaneService() 4325 // is called before pciDevice->registerService(). 4326 IORegistryEntry * parent = service->getParentEntry(gIODTPlane); 4327 if ((parent == pciHostBridgeDevice) && service->getProperty("acpi-device")) 4328 { 4329 int bit = pmTracer->recordTopLevelPCIDevice( service ); 4330 if (bit >= 0) 4331 { 4332 // Save the assigned bit for fast lookup. 4333 actions->parameter |= (bit & kPMActionsPCIBitNumberMask); 4334 4335 actions->actionPowerChangeStart = 4336 OSMemberFunctionCast( 4337 IOPMActionPowerChangeStart, this, 4338 &IOPMrootDomain::handlePowerChangeStartForPCIDevice); 4339 4340 actions->actionPowerChangeDone = 4341 OSMemberFunctionCast( 4342 IOPMActionPowerChangeDone, this, 4343 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice); 4344 } 4345 } 4346 } 4347} 4348 4349//****************************************************************************** 4350// PM actions for root domain 4351//****************************************************************************** 4352 4353void IOPMrootDomain::overrideOurPowerChange( 4354 IOService * service, 4355 IOPMActions * actions, 4356 IOPMPowerStateIndex * inOutPowerState, 4357 IOPMPowerChangeFlags * inOutChangeFlags, 4358 IOPMRequestTag requestTag ) 4359{ 4360 uint32_t powerState = (uint32_t) *inOutPowerState; 4361 uint32_t changeFlags = *inOutChangeFlags; 4362 uint32_t currentPowerState = (uint32_t) getPowerState(); 4363 4364 if (changeFlags & kIOPMParentInitiated) 4365 { 4366 // Root parent is permanently pegged at max power, 4367 // a parent initiated power change is unexpected. 4368 *inOutChangeFlags |= kIOPMNotDone; 4369 return; 4370 } 4371 4372 if (powerState < currentPowerState) 4373 { 4374 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics)) 4375 { 4376 // Root domain is dropping power state ON->SLEEP. 4377 // If system is in full wake, first enter dark wake by 4378 // converting the power drop to a capability change. 4379 // Once in dark wake, transition to sleep state ASAP. 4380 4381 darkWakeToSleepASAP = true; 4382 4383 // Drop graphics and audio capability 4384 _desiredCapability &= ~( 4385 kIOPMSystemCapabilityGraphics | 4386 kIOPMSystemCapabilityAudio ); 4387 4388 // Convert to capability change (ON->ON) 4389 *inOutPowerState = ON_STATE; 4390 *inOutChangeFlags |= kIOPMSynchronize; 4391 4392 // Revert device desire from SLEEP to ON 4393 changePowerStateToPriv(ON_STATE); 4394 } 4395 else 4396 { 4397 // System is in dark wake, ok to drop power state. 4398 // Broadcast root powering down to entire tree. 4399 *inOutChangeFlags |= kIOPMRootChangeDown; 4400 } 4401 } 4402 else if (powerState > currentPowerState) 4403 { 4404 if ((_currentCapability & kIOPMSystemCapabilityCPU) == 0) 4405 { 4406 // Broadcast power up when waking from sleep, but not for the 4407 // initial power change at boot by checking for cpu capability. 4408 *inOutChangeFlags |= kIOPMRootChangeUp; 4409 } 4410 } 4411} 4412 4413void IOPMrootDomain::handleOurPowerChangeStart( 4414 IOService * service, 4415 IOPMActions * actions, 4416 IOPMPowerStateIndex powerState, 4417 IOPMPowerChangeFlags * inOutChangeFlags, 4418 IOPMRequestTag requestTag ) 4419{ 4420 uint32_t changeFlags = *inOutChangeFlags; 4421 uint32_t currentPowerState = (uint32_t) getPowerState(); 4422 uint32_t sleepReason = requestTag ? requestTag : kIOPMSleepReasonIdle; 4423 bool publishSleepReason = false; 4424 4425 _systemTransitionType = kSystemTransitionNone; 4426 _systemMessageClientMask = 0; 4427 capabilityLoss = false; 4428 4429 if (lowBatteryCondition) 4430 { 4431 // Low battery notification may arrive after the initial sleep request 4432 // has been queued. Override the sleep reason so powerd and others can 4433 // treat this as an emergency sleep. 4434 sleepReason = kIOPMSleepReasonLowPower; 4435 } 4436 4437 // 1. Explicit capability change. 4438 4439 if (changeFlags & kIOPMSynchronize) 4440 { 4441 if (powerState == ON_STATE) 4442 { 4443 if (changeFlags & kIOPMSyncNoChildNotify) 4444 _systemTransitionType = kSystemTransitionNewCapClient; 4445 else 4446 _systemTransitionType = kSystemTransitionCapability; 4447 } 4448 } 4449 4450 // 2. Going to sleep (cancellation still possible). 4451 4452 else if (powerState < currentPowerState) 4453 _systemTransitionType = kSystemTransitionSleep; 4454 4455 // 3. Woke from (idle or demand) sleep. 4456 4457 else if (!systemBooting && 4458 (changeFlags & kIOPMSelfInitiated) && 4459 (powerState > currentPowerState)) 4460 { 4461 _systemTransitionType = kSystemTransitionWake; 4462 _desiredCapability = kIOPMSystemCapabilityCPU | 4463 kIOPMSystemCapabilityNetwork; 4464 4465 // Early exit from dark wake to full (e.g. LID open) 4466 if (kFullWakeReasonNone != fullWakeReason) 4467 { 4468 _desiredCapability |= ( 4469 kIOPMSystemCapabilityGraphics | 4470 kIOPMSystemCapabilityAudio ); 4471 } 4472#if HIBERNATION 4473 IOHibernateSetWakeCapabilities(_desiredCapability); 4474#endif 4475 } 4476 4477 // Update pending wake capability at the beginning of every 4478 // state transition (including synchronize). This will become 4479 // the current capability at the end of the transition. 4480 4481 if (kSystemTransitionSleep == _systemTransitionType) 4482 { 4483 _pendingCapability = 0; 4484 capabilityLoss = true; 4485 4486 // Clear previous stats 4487 IOLockLock(pmStatsLock); 4488 if (pmStatsAppResponses) 4489 { 4490 pmStatsAppResponses->release(); 4491 pmStatsAppResponses = OSArray::withCapacity(5); 4492 } 4493 IOLockUnlock(pmStatsLock); 4494 4495 } 4496 else if (kSystemTransitionNewCapClient != _systemTransitionType) 4497 { 4498 _pendingCapability = _desiredCapability | 4499 kIOPMSystemCapabilityCPU | 4500 kIOPMSystemCapabilityNetwork; 4501 4502 if (_pendingCapability & kIOPMSystemCapabilityGraphics) 4503 _pendingCapability |= kIOPMSystemCapabilityAudio; 4504 4505 if ((kSystemTransitionCapability == _systemTransitionType) && 4506 (_pendingCapability == _currentCapability)) 4507 { 4508 // Cancel the PM state change. 4509 _systemTransitionType = kSystemTransitionNone; 4510 *inOutChangeFlags |= kIOPMNotDone; 4511 } 4512 if (__builtin_popcount(_pendingCapability) < 4513 __builtin_popcount(_currentCapability)) 4514 capabilityLoss = true; 4515 } 4516 4517 // 1. Capability change. 4518 4519 if (kSystemTransitionCapability == _systemTransitionType) 4520 { 4521 // Dark to Full transition. 4522 if (CAP_GAIN(kIOPMSystemCapabilityGraphics)) 4523 { 4524 tracePoint( kIOPMTracePointDarkWakeExit ); 4525 4526 willEnterFullWake(); 4527 } 4528 4529 // Full to Dark transition. 4530 if (CAP_LOSS(kIOPMSystemCapabilityGraphics)) 4531 { 4532 tracePoint( kIOPMTracePointDarkWakeEntry ); 4533 *inOutChangeFlags |= kIOPMSyncTellPowerDown; 4534 _systemMessageClientMask = kSystemMessageClientPowerd | 4535 kSystemMessageClientLegacyApp; 4536 4537 4538 // rdar://15971327 4539 // Prevent user active transitions before notifying clients 4540 // that system will sleep. 4541 preventTransitionToUserActive(true); 4542 4543 IOService::setAdvisoryTickleEnable( false ); 4544 4545 // Publish the sleep reason for full to dark wake 4546 publishSleepReason = true; 4547 lastSleepReason = fullToDarkReason = sleepReason; 4548 4549 // Publish a UUID for the Sleep --> Wake cycle 4550 handlePublishSleepWakeUUID(true); 4551 } 4552 } 4553 4554 // 2. System sleep. 4555 4556 else if (kSystemTransitionSleep == _systemTransitionType) 4557 { 4558 // Beginning of a system sleep transition. 4559 // Cancellation is still possible. 4560 tracePoint( kIOPMTracePointSleepStarted, sleepReason ); 4561 4562 _systemMessageClientMask = kSystemMessageClientAll; 4563 if ((_currentCapability & kIOPMSystemCapabilityGraphics) == 0) 4564 _systemMessageClientMask &= ~kSystemMessageClientLegacyApp; 4565 if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0) 4566 _systemMessageClientMask &= ~kSystemMessageClientKernel; 4567 4568 // Record the reason for dark wake back to sleep 4569 // System may not have ever achieved full wake 4570 4571 publishSleepReason = true; 4572 lastSleepReason = sleepReason; 4573 } 4574 4575 // 3. System wake. 4576 4577 else if (kSystemTransitionWake == _systemTransitionType) 4578 { 4579 tracePoint( kIOPMTracePointWakeWillPowerOnClients ); 4580 // Clear stats about sleep 4581 4582 if (_pendingCapability & kIOPMSystemCapabilityGraphics) 4583 { 4584 willEnterFullWake(); 4585 } 4586 else 4587 { 4588 // Message powerd only 4589 _systemMessageClientMask = kSystemMessageClientPowerd; 4590 tellClients(kIOMessageSystemWillPowerOn); 4591 } 4592 } 4593 4594 // The only location where the sleep reason is published. At this point 4595 // sleep can still be cancelled, but sleep reason should be published 4596 // early for logging purposes. 4597 4598 if (publishSleepReason) 4599 { 4600 static const char * IOPMSleepReasons[] = 4601 { 4602 kIOPMClamshellSleepKey, 4603 kIOPMPowerButtonSleepKey, 4604 kIOPMSoftwareSleepKey, 4605 kIOPMOSSwitchHibernationKey, 4606 kIOPMIdleSleepKey, 4607 kIOPMLowPowerSleepKey, 4608 kIOPMThermalEmergencySleepKey, 4609 kIOPMMaintenanceSleepKey, 4610 kIOPMSleepServiceExitKey, 4611 kIOPMDarkWakeThermalEmergencyKey 4612 }; 4613 4614 // Record sleep cause in IORegistry 4615 uint32_t reasonIndex = sleepReason - kIOPMSleepReasonClamshell; 4616 if (reasonIndex < sizeof(IOPMSleepReasons)/sizeof(IOPMSleepReasons[0])) { 4617 DLOG("sleep reason %s\n", IOPMSleepReasons[reasonIndex]); 4618 setProperty(kRootDomainSleepReasonKey, IOPMSleepReasons[reasonIndex]); 4619 } 4620 } 4621 4622 if ((kSystemTransitionNone != _systemTransitionType) && 4623 (kSystemTransitionNewCapClient != _systemTransitionType)) 4624 { 4625 _systemStateGeneration++; 4626 systemDarkWake = false; 4627 4628 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, " 4629 "dcp %x:%x:%x\n", 4630 currentPowerState, (uint32_t) powerState, *inOutChangeFlags, 4631 _systemTransitionType, _systemStateGeneration, 4632 _systemMessageClientMask, 4633 _desiredCapability, _currentCapability, _pendingCapability); 4634 } 4635} 4636 4637void IOPMrootDomain::handleOurPowerChangeDone( 4638 IOService * service, 4639 IOPMActions * actions, 4640 IOPMPowerStateIndex powerState, 4641 IOPMPowerChangeFlags changeFlags, 4642 IOPMRequestTag requestTag __unused ) 4643{ 4644 if (kSystemTransitionNewCapClient == _systemTransitionType) 4645 { 4646 _systemTransitionType = kSystemTransitionNone; 4647 return; 4648 } 4649 4650 if (_systemTransitionType != kSystemTransitionNone) 4651 { 4652 uint32_t currentPowerState = (uint32_t) getPowerState(); 4653 4654 if (changeFlags & kIOPMNotDone) 4655 { 4656 // Power down was cancelled or vetoed. 4657 _pendingCapability = _currentCapability; 4658 lastSleepReason = 0; 4659 4660 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics) && 4661 CAP_CURRENT(kIOPMSystemCapabilityCPU)) 4662 { 4663 pmPowerStateQueue->submitPowerEvent( 4664 kPowerEventPolicyStimulus, 4665 (void *) kStimulusDarkWakeReentry, 4666 _systemStateGeneration ); 4667 } 4668 4669 // Revert device desire to max. 4670 changePowerStateToPriv(ON_STATE); 4671 } 4672 else 4673 { 4674 // Send message on dark wake to full wake promotion. 4675 // tellChangeUp() handles the normal SLEEP->ON case. 4676 4677 if (kSystemTransitionCapability == _systemTransitionType) 4678 { 4679 if (CAP_GAIN(kIOPMSystemCapabilityGraphics)) 4680 { 4681 lastSleepReason = 0; // stop logging wrangler tickles 4682 tellClients(kIOMessageSystemHasPoweredOn); 4683 } 4684 if (CAP_LOSS(kIOPMSystemCapabilityGraphics)) 4685 { 4686 // Going dark, reset full wake state 4687 // userIsActive will be cleared by wrangler powering down 4688 wranglerTickled = false; 4689 fullWakeReason = kFullWakeReasonNone; 4690 } 4691 } 4692 4693 // Reset state after exiting from dark wake. 4694 4695 if (CAP_GAIN(kIOPMSystemCapabilityGraphics) || 4696 CAP_LOSS(kIOPMSystemCapabilityCPU)) 4697 { 4698 darkWakeMaintenance = false; 4699 darkWakeToSleepASAP = false; 4700 pciCantSleepValid = false; 4701 darkWakeSleepService = false; 4702 4703 if (CAP_LOSS(kIOPMSystemCapabilityCPU)) 4704 { 4705 // Remove the influence of display power assertion 4706 // before next system wake. 4707 if (wrangler) wrangler->changePowerStateForRootDomain( 4708 kWranglerPowerStateMin ); 4709 removeProperty(gIOPMUserTriggeredFullWakeKey); 4710 } 4711 } 4712 4713 // Entered dark mode. 4714 4715 if (((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) && 4716 (_pendingCapability & kIOPMSystemCapabilityCPU)) 4717 { 4718 // Queue an evaluation of whether to remain in dark wake, 4719 // and for how long. This serves the purpose of draining 4720 // any assertions from the queue. 4721 4722 pmPowerStateQueue->submitPowerEvent( 4723 kPowerEventPolicyStimulus, 4724 (void *) kStimulusDarkWakeEntry, 4725 _systemStateGeneration ); 4726 } 4727 } 4728 4729 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, " 4730 "dcp %x:%x:%x, dbgtimer %u\n", 4731 currentPowerState, (uint32_t) powerState, changeFlags, 4732 _systemTransitionType, _systemStateGeneration, 4733 _systemMessageClientMask, 4734 _desiredCapability, _currentCapability, _pendingCapability, 4735 _lastDebugWakeSeconds); 4736 4737 if (_pendingCapability & kIOPMSystemCapabilityGraphics) 4738 { 4739 displayWakeCnt++; 4740#if DARK_TO_FULL_EVALUATE_CLAMSHELL 4741 if (clamshellExists && fullWakeThreadCall && 4742 CAP_HIGHEST(kIOPMSystemCapabilityGraphics)) 4743 { 4744 // Not the initial graphics full power, graphics won't 4745 // send a power notification to trigger a lid state 4746 // evaluation. 4747 4748 AbsoluteTime deadline; 4749 clock_interval_to_deadline(45, kSecondScale, &deadline); 4750 thread_call_enter_delayed(fullWakeThreadCall, deadline); 4751 } 4752#endif 4753 } 4754 else if (CAP_GAIN(kIOPMSystemCapabilityCPU)) 4755 darkWakeCnt++; 4756 4757 // Update current system capability. 4758 if (_currentCapability != _pendingCapability) 4759 _currentCapability = _pendingCapability; 4760 4761 // Update highest system capability. 4762 4763 _highestCapability |= _currentCapability; 4764 4765 if (darkWakePostTickle && 4766 (kSystemTransitionWake == _systemTransitionType) && 4767 (gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) == 4768 kDarkWakeFlagHIDTickleLate) 4769 { 4770 darkWakePostTickle = false; 4771 reportUserInput(); 4772 } 4773 4774 // Reset tracepoint at completion of capability change, 4775 // completion of wake transition, and aborted sleep transition. 4776 4777 if ((_systemTransitionType == kSystemTransitionCapability) || 4778 (_systemTransitionType == kSystemTransitionWake) || 4779 ((_systemTransitionType == kSystemTransitionSleep) && 4780 (changeFlags & kIOPMNotDone))) 4781 { 4782 setProperty(kIOPMSystemCapabilitiesKey, _currentCapability, 64); 4783 tracePoint( kIOPMTracePointSystemUp, 0 ); 4784 } 4785 4786 _systemTransitionType = kSystemTransitionNone; 4787 _systemMessageClientMask = 0; 4788 4789 logGraphicsClamp = false; 4790 } 4791} 4792 4793//****************************************************************************** 4794// PM actions for graphics and audio. 4795//****************************************************************************** 4796 4797void IOPMrootDomain::overridePowerChangeForUIService( 4798 IOService * service, 4799 IOPMActions * actions, 4800 IOPMPowerStateIndex * inOutPowerState, 4801 IOPMPowerChangeFlags * inOutChangeFlags ) 4802{ 4803 uint32_t powerState = (uint32_t) *inOutPowerState; 4804 uint32_t changeFlags = (uint32_t) *inOutChangeFlags; 4805 4806 if (kSystemTransitionNone == _systemTransitionType) 4807 { 4808 // Not in midst of a system transition. 4809 // Do not modify power limit enable state. 4810 } 4811 else if ((actions->parameter & kPMActionsFlagLimitPower) == 0) 4812 { 4813 // Activate power limiter. 4814 4815 if ((actions->parameter & kPMActionsFlagIsDisplayWrangler) && 4816 ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) && 4817 (changeFlags & kIOPMSynchronize)) 4818 { 4819 actions->parameter |= kPMActionsFlagLimitPower; 4820 } 4821 else if ((actions->parameter & kPMActionsFlagIsAudioDevice) && 4822 ((gDarkWakeFlags & kDarkWakeFlagAudioNotSuppressed) == 0) && 4823 ((_pendingCapability & kIOPMSystemCapabilityAudio) == 0) && 4824 (changeFlags & kIOPMSynchronize)) 4825 { 4826 actions->parameter |= kPMActionsFlagLimitPower; 4827 } 4828 else if ((actions->parameter & kPMActionsFlagIsGraphicsDevice) && 4829 (_systemTransitionType == kSystemTransitionSleep)) 4830 { 4831 // For graphics devices, arm the limiter when entering 4832 // system sleep. Not when dropping to dark wake. 4833 actions->parameter |= kPMActionsFlagLimitPower; 4834 } 4835 4836 if (actions->parameter & kPMActionsFlagLimitPower) 4837 { 4838 DLOG("+ plimit %s %p\n", 4839 service->getName(), OBFUSCATE(service)); 4840 } 4841 } 4842 else 4843 { 4844 // Remove power limit. 4845 4846 if ((actions->parameter & ( 4847 kPMActionsFlagIsDisplayWrangler | 4848 kPMActionsFlagIsGraphicsDevice )) && 4849 (_pendingCapability & kIOPMSystemCapabilityGraphics)) 4850 { 4851 actions->parameter &= ~kPMActionsFlagLimitPower; 4852 } 4853 else if ((actions->parameter & kPMActionsFlagIsAudioDevice) && 4854 (_pendingCapability & kIOPMSystemCapabilityAudio)) 4855 { 4856 actions->parameter &= ~kPMActionsFlagLimitPower; 4857 } 4858 4859 if ((actions->parameter & kPMActionsFlagLimitPower) == 0) 4860 { 4861 DLOG("- plimit %s %p\n", 4862 service->getName(), OBFUSCATE(service)); 4863 } 4864 } 4865 4866 if (actions->parameter & kPMActionsFlagLimitPower) 4867 { 4868 uint32_t maxPowerState = (uint32_t)(-1); 4869 4870 if (changeFlags & (kIOPMDomainDidChange | kIOPMDomainWillChange)) 4871 { 4872 // Enforce limit for system power/cap transitions. 4873 4874 maxPowerState = 0; 4875 if ((service->getPowerState() > maxPowerState) && 4876 (actions->parameter & kPMActionsFlagIsDisplayWrangler)) 4877 { 4878 maxPowerState++; 4879 4880 // Remove lingering effects of any tickle before entering 4881 // dark wake. It will take a new tickle to return to full 4882 // wake, so the existing tickle state is useless. 4883 4884 if (changeFlags & kIOPMDomainDidChange) 4885 *inOutChangeFlags |= kIOPMExpireIdleTimer; 4886 } 4887 else if (actions->parameter & kPMActionsFlagIsGraphicsDevice) 4888 { 4889 maxPowerState++; 4890 } 4891 } 4892 else 4893 { 4894 // Deny all self-initiated changes when power is limited. 4895 // Wrangler tickle should never defeat the limiter. 4896 4897 maxPowerState = service->getPowerState(); 4898 } 4899 4900 if (powerState > maxPowerState) 4901 { 4902 DLOG("> plimit %s %p (%u->%u, 0x%x)\n", 4903 service->getName(), OBFUSCATE(service), powerState, maxPowerState, 4904 changeFlags); 4905 *inOutPowerState = maxPowerState; 4906 4907 if (darkWakePostTickle && 4908 (actions->parameter & kPMActionsFlagIsDisplayWrangler) && 4909 (changeFlags & kIOPMDomainWillChange) && 4910 ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) == 4911 kDarkWakeFlagHIDTickleEarly)) 4912 { 4913 darkWakePostTickle = false; 4914 reportUserInput(); 4915 } 4916 } 4917 4918 if (!graphicsSuppressed && (changeFlags & kIOPMDomainDidChange)) 4919 { 4920 if (logGraphicsClamp) 4921 { 4922 AbsoluteTime now; 4923 uint64_t nsec; 4924 4925 clock_get_uptime(&now); 4926 SUB_ABSOLUTETIME(&now, &systemWakeTime); 4927 absolutetime_to_nanoseconds(now, &nsec); 4928 if (kIOLogPMRootDomain & gIOKitDebug) 4929 MSG("Graphics suppressed %u ms\n", 4930 ((int)((nsec) / 1000000ULL))); 4931 } 4932 graphicsSuppressed = true; 4933 } 4934 } 4935} 4936 4937void IOPMrootDomain::handleActivityTickleForDisplayWrangler( 4938 IOService * service, 4939 IOPMActions * actions ) 4940{ 4941#if !NO_KERNEL_HID 4942 // Warning: Not running in PM work loop context - don't modify state !!! 4943 // Trap tickle directed to IODisplayWrangler while running with graphics 4944 // capability suppressed. 4945 4946 assert(service == wrangler); 4947 4948 clock_get_uptime(&userActivityTime); 4949 bool aborting = ((lastSleepReason == kIOPMSleepReasonIdle) 4950 || (lastSleepReason == kIOPMSleepReasonMaintenance)); 4951 if (aborting) { 4952 userActivityCount++; 4953 DLOG("display wrangler tickled1 %d lastSleepReason %d\n", 4954 userActivityCount, lastSleepReason); 4955 } 4956 4957 if (!wranglerTickled && 4958 ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0)) 4959 { 4960 DLOG("display wrangler tickled\n"); 4961 if (kIOLogPMRootDomain & gIOKitDebug) 4962 OSReportWithBacktrace("Dark wake display tickle"); 4963 if (pmPowerStateQueue) 4964 { 4965 pmPowerStateQueue->submitPowerEvent( 4966 kPowerEventPolicyStimulus, 4967 (void *) kStimulusDarkWakeActivityTickle, 4968 true /* set wake type */ ); 4969 } 4970 } 4971#endif 4972} 4973 4974void IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler( 4975 IOService * service, 4976 IOPMActions * actions, 4977 const OSSymbol * powerClient, 4978 IOPMPowerStateIndex oldPowerState, 4979 IOPMPowerStateIndex newPowerState ) 4980{ 4981#if !NO_KERNEL_HID 4982 assert(service == wrangler); 4983 4984 // This function implements half of the user active detection 4985 // by monitoring changes to the display wrangler's device desire. 4986 // 4987 // User becomes active when either: 4988 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already 4989 // in max power state. This desire change in absence of a power state 4990 // change is detected within. This handles the case when user becomes 4991 // active while the display is already lit by setDisplayPowerOn(). 4992 // 4993 // 2. Power state change to max, and DeviceDesire is also at max. 4994 // Handled by displayWranglerNotification(). 4995 // 4996 // User becomes inactive when DeviceDesire drops to sleep state or below. 4997 4998 DLOG("wrangler %s (ps %u, %u->%u)\n", 4999 powerClient->getCStringNoCopy(), 5000 (uint32_t) service->getPowerState(), 5001 (uint32_t) oldPowerState, (uint32_t) newPowerState); 5002 5003 if (powerClient == gIOPMPowerClientDevice) 5004 { 5005 if ((newPowerState > oldPowerState) && 5006 (newPowerState == kWranglerPowerStateMax) && 5007 (service->getPowerState() == kWranglerPowerStateMax)) 5008 { 5009 evaluatePolicy( kStimulusEnterUserActiveState ); 5010 } 5011 else 5012 if ((newPowerState < oldPowerState) && 5013 (newPowerState <= kWranglerPowerStateSleep)) 5014 { 5015 evaluatePolicy( kStimulusLeaveUserActiveState ); 5016 } 5017 } 5018#endif 5019} 5020 5021//****************************************************************************** 5022// User active state management 5023//****************************************************************************** 5024 5025void IOPMrootDomain::preventTransitionToUserActive( bool prevent ) 5026{ 5027#if !NO_KERNEL_HID 5028 _preventUserActive = prevent; 5029 if (wrangler && !_preventUserActive) 5030 { 5031 // Allowing transition to user active, but the wrangler may have 5032 // already powered ON in case of sleep cancel/revert. Poll the 5033 // same conditions checked for in displayWranglerNotification() 5034 // to bring the user active state up to date. 5035 5036 if ((wrangler->getPowerState() == kWranglerPowerStateMax) && 5037 (wrangler->getPowerStateForClient(gIOPMPowerClientDevice) == 5038 kWranglerPowerStateMax)) 5039 { 5040 evaluatePolicy( kStimulusEnterUserActiveState ); 5041 } 5042 } 5043#endif 5044} 5045 5046//****************************************************************************** 5047// Approve usage of delayed child notification by PM. 5048//****************************************************************************** 5049 5050bool IOPMrootDomain::shouldDelayChildNotification( 5051 IOService * service ) 5052{ 5053 if (((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) != 0) && 5054 (kFullWakeReasonNone == fullWakeReason) && 5055 (kSystemTransitionWake == _systemTransitionType)) 5056 { 5057 DLOG("%s: delay child notify\n", service->getName()); 5058 return true; 5059 } 5060 return false; 5061} 5062 5063//****************************************************************************** 5064// PM actions for PCI device. 5065//****************************************************************************** 5066 5067void IOPMrootDomain::handlePowerChangeStartForPCIDevice( 5068 IOService * service, 5069 IOPMActions * actions, 5070 IOPMPowerStateIndex powerState, 5071 IOPMPowerChangeFlags * inOutChangeFlags ) 5072{ 5073 pmTracer->tracePCIPowerChange( 5074 PMTraceWorker::kPowerChangeStart, 5075 service, *inOutChangeFlags, 5076 (actions->parameter & kPMActionsPCIBitNumberMask)); 5077} 5078 5079void IOPMrootDomain::handlePowerChangeDoneForPCIDevice( 5080 IOService * service, 5081 IOPMActions * actions, 5082 IOPMPowerStateIndex powerState, 5083 IOPMPowerChangeFlags changeFlags ) 5084{ 5085 pmTracer->tracePCIPowerChange( 5086 PMTraceWorker::kPowerChangeCompleted, 5087 service, changeFlags, 5088 (actions->parameter & kPMActionsPCIBitNumberMask)); 5089} 5090 5091//****************************************************************************** 5092// registerInterest 5093// 5094// Override IOService::registerInterest() to intercept special clients. 5095//****************************************************************************** 5096 5097class IOPMServiceInterestNotifier: public _IOServiceInterestNotifier 5098{ 5099 5100 friend class IOPMrootDomain; 5101 OSDeclareDefaultStructors(IOPMServiceInterestNotifier) 5102 5103protected: 5104 uint32_t ackTimeoutCnt; 5105 5106}; 5107 5108OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier, _IOServiceInterestNotifier) 5109 5110IONotifier * IOPMrootDomain::registerInterest( 5111 const OSSymbol * typeOfInterest, 5112 IOServiceInterestHandler handler, 5113 void * target, void * ref ) 5114{ 5115 IOPMServiceInterestNotifier *notifier = 0; 5116 bool isSystemCapabilityClient; 5117 bool isKernelCapabilityClient; 5118 IOReturn rc = kIOReturnError;; 5119 5120 isSystemCapabilityClient = 5121 typeOfInterest && 5122 typeOfInterest->isEqualTo(kIOPMSystemCapabilityInterest); 5123 5124 isKernelCapabilityClient = 5125 typeOfInterest && 5126 typeOfInterest->isEqualTo(gIOPriorityPowerStateInterest); 5127 5128 if (isSystemCapabilityClient) 5129 typeOfInterest = gIOAppPowerStateInterest; 5130 5131 notifier = new IOPMServiceInterestNotifier; 5132 if (!notifier) return NULL; 5133 5134 if (notifier->init()) { 5135 rc = super::registerInterestForNotifer(notifier, typeOfInterest, handler, target, ref); 5136 } 5137 if (rc != kIOReturnSuccess) { 5138 notifier->release(); 5139 notifier = 0; 5140 } 5141 if (pmPowerStateQueue) 5142 { 5143 notifier->ackTimeoutCnt = 0; 5144 if (isSystemCapabilityClient) 5145 { 5146 notifier->retain(); 5147 if (pmPowerStateQueue->submitPowerEvent( 5148 kPowerEventRegisterSystemCapabilityClient, notifier) == false) 5149 notifier->release(); 5150 } 5151 5152 if (isKernelCapabilityClient) 5153 { 5154 notifier->retain(); 5155 if (pmPowerStateQueue->submitPowerEvent( 5156 kPowerEventRegisterKernelCapabilityClient, notifier) == false) 5157 notifier->release(); 5158 } 5159 } 5160 5161 return notifier; 5162} 5163 5164//****************************************************************************** 5165// systemMessageFilter 5166// 5167//****************************************************************************** 5168 5169bool IOPMrootDomain::systemMessageFilter( 5170 void * object, void * arg1, void * arg2, void * arg3 ) 5171{ 5172 const IOPMInterestContext * context = (const IOPMInterestContext *) arg1; 5173 bool isCapMsg = (context->messageType == kIOMessageSystemCapabilityChange); 5174 bool isCapClient = false; 5175 bool allow = false; 5176 5177 do { 5178 if ((kSystemTransitionNewCapClient == _systemTransitionType) && 5179 (!isCapMsg || !_joinedCapabilityClients || 5180 !_joinedCapabilityClients->containsObject((OSObject *) object))) 5181 break; 5182 5183 // Capability change message for app and kernel clients. 5184 5185 if (isCapMsg) 5186 { 5187 if ((context->notifyType == kNotifyPriority) || 5188 (context->notifyType == kNotifyCapabilityChangePriority)) 5189 isCapClient = true; 5190 5191 if ((context->notifyType == kNotifyCapabilityChangeApps) && 5192 (object == (void *) systemCapabilityNotifier)) 5193 isCapClient = true; 5194 } 5195 5196 if (isCapClient) 5197 { 5198 IOPMSystemCapabilityChangeParameters * capArgs = 5199 (IOPMSystemCapabilityChangeParameters *) arg2; 5200 5201 if (kSystemTransitionNewCapClient == _systemTransitionType) 5202 { 5203 capArgs->fromCapabilities = 0; 5204 capArgs->toCapabilities = _currentCapability; 5205 capArgs->changeFlags = 0; 5206 } 5207 else 5208 { 5209 capArgs->fromCapabilities = _currentCapability; 5210 capArgs->toCapabilities = _pendingCapability; 5211 5212 if (context->isPreChange) 5213 capArgs->changeFlags = kIOPMSystemCapabilityWillChange; 5214 else 5215 capArgs->changeFlags = kIOPMSystemCapabilityDidChange; 5216 } 5217 5218 // Capability change messages only go to the PM configd plugin. 5219 // Wait for response post-change if capabilitiy is increasing. 5220 // Wait for response pre-change if capability is decreasing. 5221 5222 if ((context->notifyType == kNotifyCapabilityChangeApps) && arg3 && 5223 ( (capabilityLoss && context->isPreChange) || 5224 (!capabilityLoss && !context->isPreChange) ) ) 5225 { 5226 // app has not replied yet, wait for it 5227 *((OSObject **) arg3) = kOSBooleanFalse; 5228 } 5229 5230 allow = true; 5231 break; 5232 } 5233 5234 // Capability client will always see kIOMessageCanSystemSleep, 5235 // even for demand sleep. It will also have a chance to veto 5236 // sleep one last time after all clients have responded to 5237 // kIOMessageSystemWillSleep 5238 5239 if ((kIOMessageCanSystemSleep == context->messageType) || 5240 (kIOMessageSystemWillNotSleep == context->messageType)) 5241 { 5242 if (object == (OSObject *) systemCapabilityNotifier) 5243 { 5244 allow = true; 5245 break; 5246 } 5247 5248 // Not idle sleep, don't ask apps. 5249 if (context->changeFlags & kIOPMSkipAskPowerDown) 5250 { 5251 break; 5252 } 5253 } 5254 5255 if (kIOPMMessageLastCallBeforeSleep == context->messageType) 5256 { 5257 if ((object == (OSObject *) systemCapabilityNotifier) && 5258 CAP_HIGHEST(kIOPMSystemCapabilityGraphics) && 5259 (fullToDarkReason == kIOPMSleepReasonIdle)) 5260 allow = true; 5261 break; 5262 } 5263 5264 // Reject capability change messages for legacy clients. 5265 // Reject legacy system sleep messages for capability client. 5266 5267 if (isCapMsg || (object == (OSObject *) systemCapabilityNotifier)) 5268 { 5269 break; 5270 } 5271 5272 // Filter system sleep messages. 5273 5274 if ((context->notifyType == kNotifyApps) && 5275 (_systemMessageClientMask & kSystemMessageClientLegacyApp)) 5276 { 5277 IOPMServiceInterestNotifier *notify; 5278 allow = true; 5279 5280 if ((notify = OSDynamicCast(IOPMServiceInterestNotifier, (OSObject *)object)) 5281 && arg3) { 5282 5283 if (notify->ackTimeoutCnt >= 3) 5284 *((OSObject **) arg3) = kOSBooleanFalse; 5285 else 5286 *((OSObject **) arg3) = kOSBooleanTrue; 5287 } 5288 } 5289 else if ((context->notifyType == kNotifyPriority) && 5290 (_systemMessageClientMask & kSystemMessageClientKernel)) 5291 { 5292 allow = true; 5293 } 5294 } 5295 while (false); 5296 5297 if (allow && isCapMsg && _joinedCapabilityClients) 5298 { 5299 _joinedCapabilityClients->removeObject((OSObject *) object); 5300 if (_joinedCapabilityClients->getCount() == 0) 5301 { 5302 DLOG("destroyed capability client set %p\n", 5303 OBFUSCATE(_joinedCapabilityClients)); 5304 _joinedCapabilityClients->release(); 5305 _joinedCapabilityClients = 0; 5306 } 5307 } 5308 5309 return allow; 5310} 5311 5312//****************************************************************************** 5313// setMaintenanceWakeCalendar 5314// 5315//****************************************************************************** 5316 5317IOReturn IOPMrootDomain::setMaintenanceWakeCalendar( 5318 const IOPMCalendarStruct * calendar ) 5319{ 5320 OSData * data; 5321 IOReturn ret = 0; 5322 5323 if (!calendar) 5324 return kIOReturnBadArgument; 5325 5326 data = OSData::withBytesNoCopy((void *) calendar, sizeof(*calendar)); 5327 if (!data) 5328 return kIOReturnNoMemory; 5329 5330 if (kPMCalendarTypeMaintenance == calendar->selector) { 5331 ret = setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey, data); 5332 if (kIOReturnSuccess == ret) 5333 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake, &_scheduledAlarms); 5334 } else 5335 if (kPMCalendarTypeSleepService == calendar->selector) 5336 { 5337 ret = setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey, data); 5338 if (kIOReturnSuccess == ret) 5339 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake, &_scheduledAlarms); 5340 } 5341 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms); 5342 5343 data->release(); 5344 return ret; 5345} 5346 5347// MARK: - 5348// MARK: Display Wrangler 5349 5350//****************************************************************************** 5351// displayWranglerNotification 5352// 5353// Handle the notification when the IODisplayWrangler changes power state. 5354//****************************************************************************** 5355 5356IOReturn IOPMrootDomain::displayWranglerNotification( 5357 void * target, void * refCon, 5358 UInt32 messageType, IOService * service, 5359 void * messageArgument, vm_size_t argSize ) 5360{ 5361#if !NO_KERNEL_HID 5362 int displayPowerState; 5363 IOPowerStateChangeNotification * params = 5364 (IOPowerStateChangeNotification *) messageArgument; 5365 5366 if ((messageType != kIOMessageDeviceWillPowerOff) && 5367 (messageType != kIOMessageDeviceHasPoweredOn)) 5368 return kIOReturnUnsupported; 5369 5370 ASSERT_GATED(); 5371 if (!gRootDomain) 5372 return kIOReturnUnsupported; 5373 5374 displayPowerState = params->stateNumber; 5375 DLOG("wrangler %s ps %d\n", 5376 getIOMessageString(messageType), displayPowerState); 5377 5378 switch (messageType) { 5379 case kIOMessageDeviceWillPowerOff: 5380 // Display wrangler has dropped power due to display idle 5381 // or force system sleep. 5382 // 5383 // 4 Display ON kWranglerPowerStateMax 5384 // 3 Display Dim kWranglerPowerStateDim 5385 // 2 Display Sleep kWranglerPowerStateSleep 5386 // 1 Not visible to user 5387 // 0 Not visible to user kWranglerPowerStateMin 5388 5389 if (displayPowerState <= kWranglerPowerStateSleep) 5390 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerSleep ); 5391 break; 5392 5393 case kIOMessageDeviceHasPoweredOn: 5394 // Display wrangler has powered on due to user activity 5395 // or wake from sleep. 5396 5397 if (kWranglerPowerStateMax == displayPowerState) 5398 { 5399 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerWake ); 5400 5401 // See comment in handleUpdatePowerClientForDisplayWrangler 5402 if (service->getPowerStateForClient(gIOPMPowerClientDevice) == 5403 kWranglerPowerStateMax) 5404 { 5405 gRootDomain->evaluatePolicy( kStimulusEnterUserActiveState ); 5406 } 5407 } 5408 break; 5409 } 5410#endif 5411 return kIOReturnUnsupported; 5412} 5413 5414//****************************************************************************** 5415// displayWranglerMatchPublished 5416// 5417// Receives a notification when the IODisplayWrangler is published. 5418// When it's published we install a power state change handler. 5419//****************************************************************************** 5420 5421bool IOPMrootDomain::displayWranglerMatchPublished( 5422 void * target, 5423 void * refCon, 5424 IOService * newService, 5425 IONotifier * notifier __unused) 5426{ 5427#if !NO_KERNEL_HID 5428 // found the display wrangler, now install a handler 5429 if( !newService->registerInterest( gIOGeneralInterest, 5430 &displayWranglerNotification, target, 0) ) 5431 { 5432 return false; 5433 } 5434#endif 5435 return true; 5436} 5437 5438#if defined(__i386__) || defined(__x86_64__) 5439 5440bool IOPMrootDomain::IONVRAMMatchPublished( 5441 void * target, 5442 void * refCon, 5443 IOService * newService, 5444 IONotifier * notifier) 5445{ 5446 unsigned int len = 0; 5447 IOPMrootDomain *rd = (IOPMrootDomain *)target; 5448 OSNumber *statusCode = NULL; 5449 5450 if (PEReadNVRAMProperty(kIOSleepWakeDebugKey, NULL, &len)) 5451 { 5452 statusCode = OSDynamicCast(OSNumber, rd->getProperty(kIOPMSleepWakeFailureCodeKey)); 5453 if (statusCode != NULL) { 5454 if (statusCode->unsigned64BitValue() != 0) { 5455 rd->swd_flags |= SWD_BOOT_BY_SW_WDOG; 5456 MSG("System was rebooted due to Sleep/Wake failure\n"); 5457 } 5458 else { 5459 rd->swd_flags |= SWD_BOOT_BY_OSX_WDOG; 5460 MSG("System was non-responsive and was rebooted by watchdog\n"); 5461 } 5462 } 5463 5464 rd->swd_logBufMap = rd->sleepWakeDebugRetrieve(); 5465 } 5466 if (notifier) notifier->remove(); 5467 return true; 5468} 5469 5470#else 5471bool IOPMrootDomain::IONVRAMMatchPublished( 5472 void * target, 5473 void * refCon, 5474 IOService * newService, 5475 IONotifier * notifier __unused) 5476{ 5477 return false; 5478} 5479 5480#endif 5481 5482//****************************************************************************** 5483// reportUserInput 5484// 5485//****************************************************************************** 5486 5487void IOPMrootDomain::reportUserInput( void ) 5488{ 5489#if !NO_KERNEL_HID 5490 OSIterator * iter; 5491 5492 if(!wrangler) 5493 { 5494 iter = getMatchingServices(serviceMatching("IODisplayWrangler")); 5495 if(iter) 5496 { 5497 wrangler = (IOService *) iter->getNextObject(); 5498 iter->release(); 5499 } 5500 } 5501 5502 if(wrangler) 5503 wrangler->activityTickle(0,0); 5504#endif 5505} 5506 5507//****************************************************************************** 5508// latchDisplayWranglerTickle 5509//****************************************************************************** 5510 5511bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch ) 5512{ 5513#if !NO_KERNEL_HID 5514 if (latch) 5515 { 5516 if (!(_currentCapability & kIOPMSystemCapabilityGraphics) && 5517 !(_pendingCapability & kIOPMSystemCapabilityGraphics) && 5518 !checkSystemCanSustainFullWake()) 5519 { 5520 // Currently in dark wake, and not transitioning to full wake. 5521 // Full wake is unsustainable, so latch the tickle to prevent 5522 // the display from lighting up momentarily. 5523 wranglerTickleLatched = true; 5524 } 5525 else 5526 { 5527 wranglerTickleLatched = false; 5528 } 5529 } 5530 else if (wranglerTickleLatched && checkSystemCanSustainFullWake()) 5531 { 5532 wranglerTickleLatched = false; 5533 5534 pmPowerStateQueue->submitPowerEvent( 5535 kPowerEventPolicyStimulus, 5536 (void *) kStimulusDarkWakeActivityTickle ); 5537 } 5538 5539 return wranglerTickleLatched; 5540#else 5541 return false; 5542#endif 5543} 5544 5545//****************************************************************************** 5546// setDisplayPowerOn 5547// 5548// For root domain user client 5549//****************************************************************************** 5550 5551void IOPMrootDomain::setDisplayPowerOn( uint32_t options ) 5552{ 5553 if (checkSystemCanSustainFullWake()) 5554 { 5555 pmPowerStateQueue->submitPowerEvent( kPowerEventSetDisplayPowerOn, 5556 (void *) 0, options ); 5557 } 5558} 5559 5560// MARK: - 5561// MARK: Battery 5562 5563//****************************************************************************** 5564// batteryPublished 5565// 5566// Notification on battery class IOPowerSource appearance 5567//****************************************************************************** 5568 5569bool IOPMrootDomain::batteryPublished( 5570 void * target, 5571 void * root_domain, 5572 IOService * resourceService, 5573 IONotifier * notifier __unused ) 5574{ 5575 // rdar://2936060&4435589 5576 // All laptops have dimmable LCD displays 5577 // All laptops have batteries 5578 // So if this machine has a battery, publish the fact that the backlight 5579 // supports dimming. 5580 ((IOPMrootDomain *)root_domain)->publishFeature("DisplayDims"); 5581 5582 return (true); 5583} 5584 5585// MARK: - 5586// MARK: System PM Policy 5587 5588//****************************************************************************** 5589// checkSystemSleepAllowed 5590// 5591//****************************************************************************** 5592 5593bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options, 5594 uint32_t sleepReason ) 5595{ 5596 int err = 0; 5597 5598 // Conditions that prevent idle and demand system sleep. 5599 5600 do { 5601 if (userDisabledAllSleep) 5602 { 5603 err = 1; // 1. user-space sleep kill switch 5604 break; 5605 } 5606 5607 if (systemBooting || systemShutdown || gWillShutdown) 5608 { 5609 err = 2; // 2. restart or shutdown in progress 5610 break; 5611 } 5612 5613 if (options == 0) 5614 break; 5615 5616 // Conditions above pegs the system at full wake. 5617 // Conditions below prevent system sleep but does not prevent 5618 // dark wake, and must be called from gated context. 5619 5620#if !CONFIG_SLEEP 5621 err = 3; // 3. config does not support sleep 5622 break; 5623#endif 5624 5625 if (lowBatteryCondition) 5626 { 5627 break; // always sleep on low battery 5628 } 5629 5630 if (sleepReason == kIOPMSleepReasonDarkWakeThermalEmergency) 5631 { 5632 break; // always sleep on dark wake thermal emergencies 5633 } 5634 5635 if (preventSystemSleepList->getCount() != 0) 5636 { 5637 err = 4; // 4. child prevent system sleep clamp 5638 break; 5639 } 5640 5641 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit ) == 5642 kIOPMDriverAssertionLevelOn) 5643 { 5644 err = 5; // 5. CPU assertion 5645 break; 5646 } 5647 5648 if (pciCantSleepValid) 5649 { 5650 if (pciCantSleepFlag) 5651 err = 6; // 6. PCI card does not support PM (cached) 5652 break; 5653 } 5654 else if (sleepSupportedPEFunction && 5655 CAP_HIGHEST(kIOPMSystemCapabilityGraphics)) 5656 { 5657 IOReturn ret; 5658 OSBitAndAtomic(~kPCICantSleep, &platformSleepSupport); 5659 ret = getPlatform()->callPlatformFunction( 5660 sleepSupportedPEFunction, false, 5661 NULL, NULL, NULL, NULL); 5662 pciCantSleepValid = true; 5663 pciCantSleepFlag = false; 5664 if ((platformSleepSupport & kPCICantSleep) || 5665 ((ret != kIOReturnSuccess) && (ret != kIOReturnUnsupported))) 5666 { 5667 err = 6; // 6. PCI card does not support PM 5668 pciCantSleepFlag = true; 5669 break; 5670 } 5671 } 5672 } 5673 while (false); 5674 5675 if (err) 5676 { 5677 DLOG("System sleep prevented by %d\n", err); 5678 return false; 5679 } 5680 return true; 5681} 5682 5683bool IOPMrootDomain::checkSystemSleepEnabled( void ) 5684{ 5685 return checkSystemSleepAllowed(0, 0); 5686} 5687 5688bool IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason ) 5689{ 5690 ASSERT_GATED(); 5691 return checkSystemSleepAllowed(1, sleepReason); 5692} 5693 5694//****************************************************************************** 5695// checkSystemCanSustainFullWake 5696//****************************************************************************** 5697 5698bool IOPMrootDomain::checkSystemCanSustainFullWake( void ) 5699{ 5700#if !NO_KERNEL_HID 5701 if (lowBatteryCondition) 5702 { 5703 // Low battery wake, or received a low battery notification 5704 // while system is awake. This condition will persist until 5705 // the following wake. 5706 return false; 5707 } 5708 5709 if (clamshellExists && clamshellClosed && !clamshellSleepDisabled) 5710 { 5711 // Graphics state is unknown and external display might not be probed. 5712 // Do not incorporate state that requires graphics to be in max power 5713 // such as desktopMode or clamshellDisabled. 5714 5715 if (!acAdaptorConnected) 5716 { 5717 DLOG("full wake check: no AC\n"); 5718 return false; 5719 } 5720 } 5721#endif 5722 return true; 5723} 5724 5725//****************************************************************************** 5726// adjustPowerState 5727// 5728// Conditions that affect our wake/sleep decision has changed. 5729// If conditions dictate that the system must remain awake, clamp power 5730// state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP 5731// is TRUE, then remove the power clamp and allow the power state to drop 5732// to SLEEP_STATE. 5733//****************************************************************************** 5734 5735void IOPMrootDomain::adjustPowerState( bool sleepASAP ) 5736{ 5737 DLOG("adjustPowerState ps %u, asap %d, slider %ld\n", 5738 (uint32_t) getPowerState(), sleepASAP, sleepSlider); 5739 5740 ASSERT_GATED(); 5741 5742 if ((sleepSlider == 0) || !checkSystemSleepEnabled()) 5743 { 5744 changePowerStateToPriv(ON_STATE); 5745 } 5746 else if ( sleepASAP ) 5747 { 5748 changePowerStateToPriv(SLEEP_STATE); 5749 } 5750} 5751 5752//****************************************************************************** 5753// dispatchPowerEvent 5754// 5755// IOPMPowerStateQueue callback function. Running on PM work loop thread. 5756//****************************************************************************** 5757 5758void IOPMrootDomain::dispatchPowerEvent( 5759 uint32_t event, void * arg0, uint64_t arg1 ) 5760{ 5761 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1); 5762 ASSERT_GATED(); 5763 5764 switch (event) 5765 { 5766 case kPowerEventFeatureChanged: 5767 messageClients(kIOPMMessageFeatureChange, this); 5768 break; 5769 5770 case kPowerEventReceivedPowerNotification: 5771 handlePowerNotification( (UInt32)(uintptr_t) arg0 ); 5772 break; 5773 5774 case kPowerEventSystemBootCompleted: 5775 if (systemBooting) 5776 { 5777 systemBooting = false; 5778 5779 if (lowBatteryCondition) 5780 { 5781 privateSleepSystem (kIOPMSleepReasonLowPower); 5782 5783 // The rest is unnecessary since the system is expected 5784 // to sleep immediately. The following wake will update 5785 // everything. 5786 break; 5787 } 5788 5789 if (swd_flags & SWD_VALID_LOGS) { 5790 if (swd_flags & SWD_LOGS_IN_MEM) { 5791 sleepWakeDebugDumpFromMem(swd_logBufMap); 5792 swd_logBufMap->release(); 5793 swd_logBufMap = 0; 5794 } 5795 else if (swd_flags & SWD_LOGS_IN_FILE) 5796 sleepWakeDebugDumpFromFile(); 5797 } 5798 else if (swd_flags & (SWD_BOOT_BY_SW_WDOG|SWD_BOOT_BY_OSX_WDOG)) { 5799 // If logs are invalid, write the failure code 5800 sleepWakeDebugDumpFromMem(NULL); 5801 } 5802 // If lid is closed, re-send lid closed notification 5803 // now that booting is complete. 5804 if ( clamshellClosed ) 5805 { 5806 handlePowerNotification(kLocalEvalClamshellCommand); 5807 } 5808 evaluatePolicy( kStimulusAllowSystemSleepChanged ); 5809 5810 } 5811 break; 5812 5813 case kPowerEventSystemShutdown: 5814 if (kOSBooleanTrue == (OSBoolean *) arg0) 5815 { 5816 /* We set systemShutdown = true during shutdown 5817 to prevent sleep at unexpected times while loginwindow is trying 5818 to shutdown apps and while the OS is trying to transition to 5819 complete power of. 5820 5821 Set to true during shutdown, as soon as loginwindow shows 5822 the "shutdown countdown dialog", through individual app 5823 termination, and through black screen kernel shutdown. 5824 */ 5825 systemShutdown = true; 5826 } else { 5827 /* 5828 A shutdown was initiated, but then the shutdown 5829 was cancelled, clearing systemShutdown to false here. 5830 */ 5831 systemShutdown = false; 5832 } 5833 break; 5834 5835 case kPowerEventUserDisabledSleep: 5836 userDisabledAllSleep = (kOSBooleanTrue == (OSBoolean *) arg0); 5837 break; 5838 5839 case kPowerEventRegisterSystemCapabilityClient: 5840 if (systemCapabilityNotifier) 5841 { 5842 systemCapabilityNotifier->release(); 5843 systemCapabilityNotifier = 0; 5844 } 5845 if (arg0) 5846 { 5847 systemCapabilityNotifier = (IONotifier *) arg0; 5848 systemCapabilityNotifier->retain(); 5849 } 5850 /* intentional fall-through */ 5851 5852 case kPowerEventRegisterKernelCapabilityClient: 5853 if (!_joinedCapabilityClients) 5854 _joinedCapabilityClients = OSSet::withCapacity(8); 5855 if (arg0) 5856 { 5857 IONotifier * notify = (IONotifier *) arg0; 5858 if (_joinedCapabilityClients) 5859 { 5860 _joinedCapabilityClients->setObject(notify); 5861 synchronizePowerTree( kIOPMSyncNoChildNotify ); 5862 } 5863 notify->release(); 5864 } 5865 break; 5866 5867 case kPowerEventPolicyStimulus: 5868 if (arg0) 5869 { 5870 int stimulus = (uintptr_t) arg0; 5871 evaluatePolicy( stimulus, (uint32_t) arg1 ); 5872 } 5873 break; 5874 5875 case kPowerEventAssertionCreate: 5876 if (pmAssertions) { 5877 pmAssertions->handleCreateAssertion((OSData *)arg0); 5878 } 5879 break; 5880 5881 5882 case kPowerEventAssertionRelease: 5883 if (pmAssertions) { 5884 pmAssertions->handleReleaseAssertion(arg1); 5885 } 5886 break; 5887 5888 case kPowerEventAssertionSetLevel: 5889 if (pmAssertions) { 5890 pmAssertions->handleSetAssertionLevel(arg1, (IOPMDriverAssertionLevel)(uintptr_t)arg0); 5891 } 5892 break; 5893 5894 case kPowerEventQueueSleepWakeUUID: 5895 handleQueueSleepWakeUUID((OSObject *)arg0); 5896 break; 5897 case kPowerEventPublishSleepWakeUUID: 5898 handlePublishSleepWakeUUID((bool)arg0); 5899 break; 5900 5901 case kPowerEventSetDisplayPowerOn: 5902 if (!wrangler) break; 5903 if (arg1 != 0) 5904 { 5905 // Force wrangler to max power state. If system is in dark wake 5906 // this alone won't raise the wrangler's power state. 5907 5908 wrangler->changePowerStateForRootDomain(kWranglerPowerStateMax); 5909 5910 // System in dark wake, always requesting full wake should 5911 // not have any bad side-effects, even if the request fails. 5912 5913 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics)) 5914 { 5915 setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeNotification); 5916 requestFullWake( kFullWakeReasonDisplayOn ); 5917 } 5918 } 5919 else 5920 { 5921 // Relenquish desire to power up display. 5922 // Must first transition to state 1 since wrangler doesn't 5923 // power off the displays at state 0. At state 0 the root 5924 // domain is removed from the wrangler's power client list. 5925 5926 wrangler->changePowerStateForRootDomain(kWranglerPowerStateMin + 1); 5927 wrangler->changePowerStateForRootDomain(kWranglerPowerStateMin); 5928 } 5929 break; 5930 } 5931} 5932 5933//****************************************************************************** 5934// systemPowerEventOccurred 5935// 5936// The power controller is notifying us of a hardware-related power management 5937// event that we must handle. 5938// 5939// systemPowerEventOccurred covers the same functionality that 5940// receivePowerNotification does; it simply provides a richer API for conveying 5941// more information. 5942//****************************************************************************** 5943 5944IOReturn IOPMrootDomain::systemPowerEventOccurred( 5945 const OSSymbol *event, 5946 uint32_t intValue) 5947{ 5948 IOReturn attempt = kIOReturnSuccess; 5949 OSNumber *newNumber = NULL; 5950 5951 if (!event) 5952 return kIOReturnBadArgument; 5953 5954 newNumber = OSNumber::withNumber(intValue, 8*sizeof(intValue)); 5955 if (!newNumber) 5956 return kIOReturnInternalError; 5957 5958 attempt = systemPowerEventOccurred(event, (OSObject *)newNumber); 5959 5960 newNumber->release(); 5961 5962 return attempt; 5963} 5964 5965IOReturn IOPMrootDomain::systemPowerEventOccurred( 5966 const OSSymbol *event, 5967 OSObject *value) 5968{ 5969 OSDictionary *thermalsDict = NULL; 5970 bool shouldUpdate = true; 5971 5972 if (!event || !value) 5973 return kIOReturnBadArgument; 5974 5975 // LOCK 5976 // We reuse featuresDict Lock because it already exists and guards 5977 // the very infrequently used publish/remove feature mechanism; so there's zero rsk 5978 // of stepping on that lock. 5979 if (featuresDictLock) IOLockLock(featuresDictLock); 5980 5981 thermalsDict = (OSDictionary *)getProperty(kIOPMRootDomainPowerStatusKey); 5982 5983 if (thermalsDict && OSDynamicCast(OSDictionary, thermalsDict)) { 5984 thermalsDict = OSDictionary::withDictionary(thermalsDict); 5985 } else { 5986 thermalsDict = OSDictionary::withCapacity(1); 5987 } 5988 5989 if (!thermalsDict) { 5990 shouldUpdate = false; 5991 goto exit; 5992 } 5993 5994 thermalsDict->setObject (event, value); 5995 5996 setProperty (kIOPMRootDomainPowerStatusKey, thermalsDict); 5997 5998 thermalsDict->release(); 5999 6000exit: 6001 // UNLOCK 6002 if (featuresDictLock) IOLockUnlock(featuresDictLock); 6003 6004 if (shouldUpdate) 6005 messageClients (kIOPMMessageSystemPowerEventOccurred, (void *)NULL); 6006 6007 return kIOReturnSuccess; 6008} 6009 6010//****************************************************************************** 6011// receivePowerNotification 6012// 6013// The power controller is notifying us of a hardware-related power management 6014// event that we must handle. This may be a result of an 'environment' interrupt 6015// from the power mgt micro. 6016//****************************************************************************** 6017 6018IOReturn IOPMrootDomain::receivePowerNotification( UInt32 msg ) 6019{ 6020 pmPowerStateQueue->submitPowerEvent( 6021 kPowerEventReceivedPowerNotification, (void *)(uintptr_t) msg ); 6022 return kIOReturnSuccess; 6023} 6024 6025void IOPMrootDomain::handlePowerNotification( UInt32 msg ) 6026{ 6027 bool eval_clamshell = false; 6028 6029 ASSERT_GATED(); 6030 6031 /* 6032 * Local (IOPMrootDomain only) eval clamshell command 6033 */ 6034 if (msg & kLocalEvalClamshellCommand) 6035 { 6036 eval_clamshell = true; 6037 } 6038 6039 /* 6040 * Overtemp 6041 */ 6042 if (msg & kIOPMOverTemp) 6043 { 6044 MSG("PowerManagement emergency overtemp signal. Going to sleep!"); 6045 privateSleepSystem (kIOPMSleepReasonThermalEmergency); 6046 } 6047 6048 /* 6049 * Sleep if system is in dark wake 6050 */ 6051 if (msg & kIOPMDWOverTemp) 6052 { 6053 DLOG("DarkWake thermal limits message received!\n"); 6054 6055 // Inform cap client that we're going to sleep 6056 messageClients(kIOPMMessageDarkWakeThermalEmergency); 6057 6058 } 6059 6060 /* 6061 * Sleep Now! 6062 */ 6063 if (msg & kIOPMSleepNow) 6064 { 6065 privateSleepSystem (kIOPMSleepReasonSoftware); 6066 } 6067 6068 /* 6069 * Power Emergency 6070 */ 6071 if (msg & kIOPMPowerEmergency) 6072 { 6073 lowBatteryCondition = true; 6074 privateSleepSystem (kIOPMSleepReasonLowPower); 6075 } 6076 6077 /* 6078 * Clamshell OPEN 6079 */ 6080 if (msg & kIOPMClamshellOpened) 6081 { 6082 // Received clamshel open message from clamshell controlling driver 6083 // Update our internal state and tell general interest clients 6084 clamshellClosed = false; 6085 clamshellExists = true; 6086 6087 // Don't issue a hid tickle when lid is open and polled on wake 6088 if (msg & kIOPMSetValue) 6089 { 6090 setProperty(kIOPMRootDomainWakeTypeKey, "Lid Open"); 6091 reportUserInput(); 6092 } 6093 6094 // Tell PMCPU 6095 informCPUStateChange(kInformLid, 0); 6096 6097 // Tell general interest clients 6098 sendClientClamshellNotification(); 6099 6100 bool aborting = ((lastSleepReason == kIOPMSleepReasonClamshell) 6101 || (lastSleepReason == kIOPMSleepReasonIdle) 6102 || (lastSleepReason == kIOPMSleepReasonMaintenance)); 6103 if (aborting) userActivityCount++; 6104 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount, lastSleepReason); 6105 } 6106 6107 /* 6108 * Clamshell CLOSED 6109 * Send the clamshell interest notification since the lid is closing. 6110 */ 6111 if (msg & kIOPMClamshellClosed) 6112 { 6113 // Received clamshel open message from clamshell controlling driver 6114 // Update our internal state and tell general interest clients 6115 clamshellClosed = true; 6116 clamshellExists = true; 6117 6118 // Tell PMCPU 6119 informCPUStateChange(kInformLid, 1); 6120 6121 // Tell general interest clients 6122 sendClientClamshellNotification(); 6123 6124 // And set eval_clamshell = so we can attempt 6125 eval_clamshell = true; 6126 } 6127 6128 /* 6129 * Set Desktop mode (sent from graphics) 6130 * 6131 * -> reevaluate lid state 6132 */ 6133 if (msg & kIOPMSetDesktopMode) 6134 { 6135 desktopMode = (0 != (msg & kIOPMSetValue)); 6136 msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue); 6137 6138 sendClientClamshellNotification(); 6139 6140 // Re-evaluate the lid state 6141 eval_clamshell = true; 6142 } 6143 6144 /* 6145 * AC Adaptor connected 6146 * 6147 * -> reevaluate lid state 6148 */ 6149 if (msg & kIOPMSetACAdaptorConnected) 6150 { 6151 acAdaptorConnected = (0 != (msg & kIOPMSetValue)); 6152 msg &= ~(kIOPMSetACAdaptorConnected | kIOPMSetValue); 6153 6154 // Tell CPU PM 6155 informCPUStateChange(kInformAC, !acAdaptorConnected); 6156 6157 // Tell BSD if AC is connected 6158 // 0 == external power source; 1 == on battery 6159 post_sys_powersource(acAdaptorConnected ? 0:1); 6160 6161 sendClientClamshellNotification(); 6162 6163 // Re-evaluate the lid state 6164 eval_clamshell = true; 6165 6166 // Lack of AC may have latched a display wrangler tickle. 6167 // This mirrors the hardware's USB wake event latch, where a latched 6168 // USB wake event followed by an AC attach will trigger a full wake. 6169 latchDisplayWranglerTickle( false ); 6170 6171#if HIBERNATION 6172 // AC presence will reset the standy timer delay adjustment. 6173 _standbyTimerResetSeconds = 0; 6174#endif 6175 if (!userIsActive) { 6176 // Reset userActivityTime when power supply is changed(rdr 13789330) 6177 clock_get_uptime(&userActivityTime); 6178 } 6179 } 6180 6181 /* 6182 * Enable Clamshell (external display disappear) 6183 * 6184 * -> reevaluate lid state 6185 */ 6186 if (msg & kIOPMEnableClamshell) 6187 { 6188 // Re-evaluate the lid state 6189 // System should sleep on external display disappearance 6190 // in lid closed operation. 6191 if (true == clamshellDisabled) 6192 { 6193 eval_clamshell = true; 6194 } 6195 6196 clamshellDisabled = false; 6197 sendClientClamshellNotification(); 6198 } 6199 6200 /* 6201 * Disable Clamshell (external display appeared) 6202 * We don't bother re-evaluating clamshell state. If the system is awake, 6203 * the lid is probably open. 6204 */ 6205 if (msg & kIOPMDisableClamshell) 6206 { 6207 clamshellDisabled = true; 6208 sendClientClamshellNotification(); 6209 } 6210 6211 /* 6212 * Evaluate clamshell and SLEEP if appropiate 6213 */ 6214 if (eval_clamshell && clamshellClosed) 6215 { 6216 if (shouldSleepOnClamshellClosed()) 6217 privateSleepSystem (kIOPMSleepReasonClamshell); 6218 else 6219 evaluatePolicy( kStimulusDarkWakeEvaluate ); 6220 } 6221 6222 /* 6223 * Power Button 6224 */ 6225 if (msg & kIOPMPowerButton) 6226 { 6227 if (!wranglerAsleep) 6228 { 6229 OSString *pbs = OSString::withCString("DisablePowerButtonSleep"); 6230 // Check that power button sleep is enabled 6231 if( pbs ) { 6232 if( kOSBooleanTrue != getProperty(pbs)) 6233 privateSleepSystem (kIOPMSleepReasonPowerButton); 6234 } 6235 } 6236 else 6237 reportUserInput(); 6238 } 6239} 6240 6241//****************************************************************************** 6242// evaluatePolicy 6243// 6244// Evaluate root-domain policy in response to external changes. 6245//****************************************************************************** 6246 6247void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg ) 6248{ 6249 union { 6250 struct { 6251 int idleSleepEnabled : 1; 6252 int idleSleepDisabled : 1; 6253 int displaySleep : 1; 6254 int sleepDelayChanged : 1; 6255 int evaluateDarkWake : 1; 6256 int adjustPowerState : 1; 6257 int userBecameInactive : 1; 6258 } bit; 6259 uint32_t u32; 6260 } flags; 6261 6262 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg); 6263 6264 ASSERT_GATED(); 6265 flags.u32 = 0; 6266 6267 switch (stimulus) 6268 { 6269 case kStimulusDisplayWranglerSleep: 6270 if (!wranglerAsleep) 6271 { 6272 // first transition to wrangler sleep or lower 6273 wranglerAsleep = true; 6274 flags.bit.displaySleep = true; 6275 } 6276 break; 6277 6278 case kStimulusDisplayWranglerWake: 6279 displayIdleForDemandSleep = false; 6280 wranglerAsleep = false; 6281 break; 6282 6283 case kStimulusEnterUserActiveState: 6284 if (_preventUserActive) 6285 { 6286 DLOG("user active dropped\n"); 6287 break; 6288 } 6289 if (!userIsActive) 6290 { 6291 userIsActive = true; 6292 userWasActive = true; 6293 6294 // Stay awake after dropping demand for display power on 6295 if (kFullWakeReasonDisplayOn == fullWakeReason) 6296 fullWakeReason = fFullWakeReasonDisplayOnAndLocalUser; 6297 6298 setProperty(gIOPMUserIsActiveKey, kOSBooleanTrue); 6299 messageClients(kIOPMMessageUserIsActiveChanged); 6300 } 6301 flags.bit.idleSleepDisabled = true; 6302 break; 6303 6304 case kStimulusLeaveUserActiveState: 6305 if (userIsActive) 6306 { 6307 userIsActive = false; 6308 clock_get_uptime(&userBecameInactiveTime); 6309 flags.bit.userBecameInactive = true; 6310 6311 setProperty(gIOPMUserIsActiveKey, kOSBooleanFalse); 6312 messageClients(kIOPMMessageUserIsActiveChanged); 6313 } 6314 break; 6315 6316 case kStimulusAggressivenessChanged: 6317 { 6318 unsigned long minutesToIdleSleep = 0; 6319 unsigned long minutesToDisplayDim = 0; 6320 unsigned long minutesDelta = 0; 6321 6322 // Fetch latest display and system sleep slider values. 6323 getAggressiveness(kPMMinutesToSleep, &minutesToIdleSleep); 6324 getAggressiveness(kPMMinutesToDim, &minutesToDisplayDim); 6325 DLOG("aggressiveness changed: system %u->%u, display %u\n", 6326 (uint32_t) sleepSlider, 6327 (uint32_t) minutesToIdleSleep, 6328 (uint32_t) minutesToDisplayDim); 6329 6330 DLOG("idle time -> %ld secs (ena %d)\n", 6331 idleSeconds, (minutesToIdleSleep != 0)); 6332 6333 if (0x7fffffff == minutesToIdleSleep) 6334 minutesToIdleSleep = idleSeconds; 6335 6336 // How long to wait before sleeping the system once 6337 // the displays turns off is indicated by 'extraSleepDelay'. 6338 6339 if ( minutesToIdleSleep > minutesToDisplayDim ) 6340 minutesDelta = minutesToIdleSleep - minutesToDisplayDim; 6341 else if ( minutesToIdleSleep == minutesToDisplayDim ) 6342 minutesDelta = 1; 6343 6344 if ((sleepSlider == 0) && (minutesToIdleSleep != 0)) 6345 flags.bit.idleSleepEnabled = true; 6346 6347 if ((sleepSlider != 0) && (minutesToIdleSleep == 0)) 6348 flags.bit.idleSleepDisabled = true; 6349 6350 if (((minutesDelta != extraSleepDelay) || 6351 (userActivityTime != userActivityTime_prev)) && 6352 !flags.bit.idleSleepEnabled && !flags.bit.idleSleepDisabled) 6353 flags.bit.sleepDelayChanged = true; 6354 6355 if (systemDarkWake && !darkWakeToSleepASAP && 6356 (flags.bit.idleSleepEnabled || flags.bit.idleSleepDisabled)) 6357 { 6358 // Reconsider decision to remain in dark wake 6359 flags.bit.evaluateDarkWake = true; 6360 } 6361 6362 sleepSlider = minutesToIdleSleep; 6363 extraSleepDelay = minutesDelta; 6364 userActivityTime_prev = userActivityTime; 6365 } break; 6366 6367 case kStimulusDemandSystemSleep: 6368 displayIdleForDemandSleep = true; 6369 if (wrangler && wranglerIdleSettings) 6370 { 6371 // Request wrangler idle only when demand sleep is triggered 6372 // from full wake. 6373 if(CAP_CURRENT(kIOPMSystemCapabilityGraphics)) 6374 { 6375 wrangler->setProperties(wranglerIdleSettings); 6376 DLOG("Requested wrangler idle\n"); 6377 } 6378 } 6379 // arg = sleepReason 6380 changePowerStateWithOverrideTo( SLEEP_STATE, arg ); 6381 break; 6382 6383 case kStimulusAllowSystemSleepChanged: 6384 flags.bit.adjustPowerState = true; 6385 break; 6386 6387 case kStimulusDarkWakeActivityTickle: 6388 // arg == true implies real and not self generated wrangler tickle. 6389 // Update wake type on PM work loop instead of the tickle thread to 6390 // eliminate the possibility of an early tickle clobbering the wake 6391 // type set by the platform driver. 6392 if (arg == true) 6393 setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeHIDActivity); 6394 6395 if (false == wranglerTickled) 6396 { 6397 if (latchDisplayWranglerTickle(true)) 6398 { 6399 DLOG("latched tickle\n"); 6400 break; 6401 } 6402 6403 wranglerTickled = true; 6404 DLOG("Requesting full wake after dark wake activity tickle\n"); 6405 requestFullWake( kFullWakeReasonLocalUser ); 6406 } 6407 break; 6408 6409 case kStimulusDarkWakeEntry: 6410 case kStimulusDarkWakeReentry: 6411 // Any system transitions since the last dark wake transition 6412 // will invalid the stimulus. 6413 6414 if (arg == _systemStateGeneration) 6415 { 6416 DLOG("dark wake entry\n"); 6417 systemDarkWake = true; 6418 6419 // Keep wranglerAsleep an invariant when wrangler is absent 6420 if (wrangler) 6421 wranglerAsleep = true; 6422 6423 if (kStimulusDarkWakeEntry == stimulus) 6424 { 6425 clock_get_uptime(&userBecameInactiveTime); 6426 flags.bit.evaluateDarkWake = true; 6427 } 6428 6429 // Always accelerate disk spindown while in dark wake, 6430 // even if system does not support/allow sleep. 6431 6432 cancelIdleSleepTimer(); 6433 setQuickSpinDownTimeout(); 6434 } 6435 break; 6436 6437 case kStimulusDarkWakeEvaluate: 6438 if (systemDarkWake) 6439 { 6440 flags.bit.evaluateDarkWake = true; 6441 } 6442 break; 6443 6444 case kStimulusNoIdleSleepPreventers: 6445 flags.bit.adjustPowerState = true; 6446 break; 6447 6448 } /* switch(stimulus) */ 6449 6450 if (flags.bit.evaluateDarkWake && (kFullWakeReasonNone == fullWakeReason)) 6451 { 6452 if (darkWakeToSleepASAP || 6453 (clamshellClosed && !(desktopMode && acAdaptorConnected))) 6454 { 6455 uint32_t newSleepReason; 6456 6457 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics)) 6458 { 6459 // System was previously in full wake. Sleep reason from 6460 // full to dark already recorded in fullToDarkReason. 6461 6462 if (lowBatteryCondition) 6463 newSleepReason = kIOPMSleepReasonLowPower; 6464 else 6465 newSleepReason = fullToDarkReason; 6466 } 6467 else 6468 { 6469 // In dark wake from system sleep. 6470 6471 if (darkWakeSleepService) 6472 newSleepReason = kIOPMSleepReasonSleepServiceExit; 6473 else 6474 newSleepReason = kIOPMSleepReasonMaintenance; 6475 } 6476 6477 if (checkSystemCanSleep(newSleepReason)) 6478 { 6479 privateSleepSystem(newSleepReason); 6480 } 6481 } 6482 else // non-maintenance (network) dark wake 6483 { 6484 if (checkSystemCanSleep(kIOPMSleepReasonIdle)) 6485 { 6486 // Release power clamp, and wait for children idle. 6487 adjustPowerState(true); 6488 } 6489 else 6490 { 6491 changePowerStateToPriv(ON_STATE); 6492 } 6493 } 6494 } 6495 6496 if (systemDarkWake) 6497 { 6498 // The rest are irrelevant while system is in dark wake. 6499 flags.u32 = 0; 6500 } 6501 6502 if ((flags.bit.displaySleep) && 6503 (kFullWakeReasonDisplayOn == fullWakeReason)) 6504 { 6505 // kIOPMSleepReasonMaintenance? 6506 changePowerStateWithOverrideTo( SLEEP_STATE, kIOPMSleepReasonMaintenance ); 6507 } 6508 6509 if (flags.bit.userBecameInactive || flags.bit.sleepDelayChanged) 6510 { 6511 bool cancelQuickSpindown = false; 6512 6513 if (flags.bit.sleepDelayChanged) 6514 { 6515 // Cancel existing idle sleep timer and quick disk spindown. 6516 // New settings will be applied by the idleSleepEnabled flag 6517 // handler below if idle sleep is enabled. 6518 6519 DLOG("extra sleep timer changed\n"); 6520 cancelIdleSleepTimer(); 6521 cancelQuickSpindown = true; 6522 } 6523 else 6524 { 6525 DLOG("user inactive\n"); 6526 } 6527 6528 if (!userIsActive && sleepSlider) 6529 { 6530 startIdleSleepTimer(getTimeToIdleSleep()); 6531 } 6532 6533 if (cancelQuickSpindown) 6534 restoreUserSpinDownTimeout(); 6535 } 6536 6537 if (flags.bit.idleSleepEnabled) 6538 { 6539 DLOG("idle sleep timer enabled\n"); 6540 if (!wrangler) 6541 { 6542 changePowerStateToPriv(ON_STATE); 6543 if (idleSeconds) 6544 { 6545 startIdleSleepTimer( idleSeconds ); 6546 } 6547 } 6548 else 6549 { 6550 // Start idle timer if prefs now allow system sleep 6551 // and user is already inactive. Disk spindown is 6552 // accelerated upon timer expiration. 6553 6554 if (!userIsActive) 6555 { 6556 startIdleSleepTimer(getTimeToIdleSleep()); 6557 } 6558 } 6559 } 6560 6561 if (flags.bit.idleSleepDisabled) 6562 { 6563 DLOG("idle sleep timer disabled\n"); 6564 cancelIdleSleepTimer(); 6565 restoreUserSpinDownTimeout(); 6566 adjustPowerState(); 6567 } 6568 6569 if (flags.bit.adjustPowerState) 6570 { 6571 bool sleepASAP = false; 6572 6573 if (!systemBooting && (preventIdleSleepList->getCount() == 0)) 6574 { 6575 if (!wrangler) 6576 { 6577 changePowerStateToPriv(ON_STATE); 6578 if (idleSeconds) 6579 { 6580 // stay awake for at least idleSeconds 6581 startIdleSleepTimer(idleSeconds); 6582 } 6583 } 6584 else if (!extraSleepDelay && !idleSleepTimerPending && !systemDarkWake) 6585 { 6586 sleepASAP = true; 6587 } 6588 } 6589 6590 adjustPowerState(sleepASAP); 6591 } 6592} 6593 6594//****************************************************************************** 6595// requestFullWake 6596// 6597// Request transition from dark wake to full wake 6598//****************************************************************************** 6599 6600void IOPMrootDomain::requestFullWake( FullWakeReason reason ) 6601{ 6602 uint32_t options = 0; 6603 IOService * pciRoot = 0; 6604 bool promotion = false; 6605 6606 // System must be in dark wake and a valid reason for entering full wake 6607 if ((kFullWakeReasonNone == reason) || 6608 (kFullWakeReasonNone != fullWakeReason) || 6609 (CAP_CURRENT(kIOPMSystemCapabilityGraphics))) 6610 { 6611 return; 6612 } 6613 6614 // Will clear reason upon exit from full wake 6615 fullWakeReason = reason; 6616 6617 _desiredCapability |= (kIOPMSystemCapabilityGraphics | 6618 kIOPMSystemCapabilityAudio); 6619 6620 if ((kSystemTransitionWake == _systemTransitionType) && 6621 !(_pendingCapability & kIOPMSystemCapabilityGraphics) && 6622 !graphicsSuppressed) 6623 { 6624 // Promote to full wake while waking up to dark wake due to tickle. 6625 // PM will hold off notifying the graphics subsystem about system wake 6626 // as late as possible, so if a HID tickle does arrive, graphics can 6627 // power up on this same wake cycle. The latency to power up graphics 6628 // on the next cycle can be huge on some systems. However, once any 6629 // graphics suppression has taken effect, it is too late. All other 6630 // graphics devices must be similarly suppressed. But the delay till 6631 // the following cycle should be short. 6632 6633 _pendingCapability |= (kIOPMSystemCapabilityGraphics | 6634 kIOPMSystemCapabilityAudio); 6635 6636 // Immediately bring up audio and graphics 6637 pciRoot = pciHostBridgeDriver; 6638 willEnterFullWake(); 6639 promotion = true; 6640 } 6641 6642 // Unsafe to cancel once graphics was powered. 6643 // If system woke from dark wake, the return to sleep can 6644 // be cancelled. "awake -> dark -> sleep" transition 6645 // can be canceled also, during the "dark --> sleep" phase 6646 // *prior* to driver power down. 6647 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics) || 6648 _pendingCapability == 0) { 6649 options |= kIOPMSyncCancelPowerDown; 6650 } 6651 6652 synchronizePowerTree(options, pciRoot); 6653 if (kFullWakeReasonLocalUser == fullWakeReason) 6654 { 6655 // IOGraphics doesn't light the display even though graphics is 6656 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104) 6657 // So, do an explicit activity tickle 6658 if (wrangler) 6659 wrangler->activityTickle(0,0); 6660 } 6661 6662 // Log a timestamp for the initial full wake request. 6663 // System may not always honor this full wake request. 6664 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics)) 6665 { 6666 AbsoluteTime now; 6667 uint64_t nsec; 6668 6669 clock_get_uptime(&now); 6670 SUB_ABSOLUTETIME(&now, &systemWakeTime); 6671 absolutetime_to_nanoseconds(now, &nsec); 6672 MSG("full wake %s (reason %u) %u ms\n", 6673 promotion ? "promotion" : "request", 6674 fullWakeReason, ((int)((nsec) / 1000000ULL))); 6675 } 6676} 6677 6678//****************************************************************************** 6679// willEnterFullWake 6680// 6681// System will enter full wake from sleep, from dark wake, or from dark 6682// wake promotion. This function aggregate things that are in common to 6683// all three full wake transitions. 6684// 6685// Assumptions: fullWakeReason was updated 6686//****************************************************************************** 6687 6688void IOPMrootDomain::willEnterFullWake( void ) 6689{ 6690 hibernateRetry = false; 6691 sleepToStandby = false; 6692 sleepTimerMaintenance = false; 6693 6694 _systemMessageClientMask = kSystemMessageClientPowerd | 6695 kSystemMessageClientLegacyApp; 6696 6697 if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0) 6698 { 6699 // Initial graphics full power 6700 _systemMessageClientMask |= kSystemMessageClientKernel; 6701 6702 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics 6703 setProperty(gIOPMUserTriggeredFullWakeKey, 6704 (kFullWakeReasonLocalUser == fullWakeReason) ? 6705 kOSBooleanTrue : kOSBooleanFalse); 6706 } 6707#if HIBERNATION 6708 IOHibernateSetWakeCapabilities(_pendingCapability); 6709#endif 6710 6711 IOService::setAdvisoryTickleEnable( true ); 6712 tellClients(kIOMessageSystemWillPowerOn); 6713 preventTransitionToUserActive(false); 6714} 6715 6716//****************************************************************************** 6717// fullWakeDelayedWork 6718// 6719// System has already entered full wake. Invoked by a delayed thread call. 6720//****************************************************************************** 6721 6722void IOPMrootDomain::fullWakeDelayedWork( void ) 6723{ 6724#if DARK_TO_FULL_EVALUATE_CLAMSHELL 6725 // Not gated, don't modify state 6726 if ((kSystemTransitionNone == _systemTransitionType) && 6727 CAP_CURRENT(kIOPMSystemCapabilityGraphics)) 6728 { 6729 receivePowerNotification( kLocalEvalClamshellCommand ); 6730 } 6731#endif 6732} 6733 6734//****************************************************************************** 6735// evaluateAssertions 6736// 6737//****************************************************************************** 6738void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions, IOPMDriverAssertionType oldAssertions) 6739{ 6740 IOPMDriverAssertionType changedBits = newAssertions ^ oldAssertions; 6741 6742 messageClients(kIOPMMessageDriverAssertionsChanged); 6743 6744 if (changedBits & kIOPMDriverAssertionPreventDisplaySleepBit) { 6745 6746 if (wrangler) { 6747 bool value = (newAssertions & kIOPMDriverAssertionPreventDisplaySleepBit) ? true : false; 6748 6749 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value); 6750 wrangler->setIgnoreIdleTimer( value ); 6751 } 6752 } 6753 6754 if (changedBits & kIOPMDriverAssertionCPUBit) 6755 evaluatePolicy(kStimulusDarkWakeEvaluate); 6756 6757 if (changedBits & kIOPMDriverAssertionReservedBit7) { 6758 bool value = (newAssertions & kIOPMDriverAssertionReservedBit7) ? true : false; 6759 if (value) { 6760 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n"); 6761 updatePreventIdleSleepList(this, true); 6762 } 6763 else { 6764 DLOG("Driver assertion ReservedBit7 dropped\n"); 6765 updatePreventIdleSleepList(this, false); 6766 } 6767 } 6768} 6769 6770// MARK: - 6771// MARK: Statistics 6772 6773//****************************************************************************** 6774// pmStats 6775// 6776//****************************************************************************** 6777 6778void IOPMrootDomain::pmStatsRecordEvent( 6779 int eventIndex, 6780 AbsoluteTime timestamp) 6781{ 6782 bool starting = eventIndex & kIOPMStatsEventStartFlag ? true:false; 6783 bool stopping = eventIndex & kIOPMStatsEventStopFlag ? true:false; 6784 uint64_t delta; 6785 uint64_t nsec; 6786 OSData *publishPMStats = NULL; 6787 6788 eventIndex &= ~(kIOPMStatsEventStartFlag | kIOPMStatsEventStopFlag); 6789 6790 absolutetime_to_nanoseconds(timestamp, &nsec); 6791 6792 switch (eventIndex) { 6793 case kIOPMStatsHibernateImageWrite: 6794 if (starting) 6795 gPMStats.hibWrite.start = nsec; 6796 else if (stopping) 6797 gPMStats.hibWrite.stop = nsec; 6798 6799 if (stopping) { 6800 delta = gPMStats.hibWrite.stop - gPMStats.hibWrite.start; 6801 IOLog("PMStats: Hibernate write took %qd ms\n", delta/1000000ULL); 6802 } 6803 break; 6804 case kIOPMStatsHibernateImageRead: 6805 if (starting) 6806 gPMStats.hibRead.start = nsec; 6807 else if (stopping) 6808 gPMStats.hibRead.stop = nsec; 6809 6810 if (stopping) { 6811 delta = gPMStats.hibRead.stop - gPMStats.hibRead.start; 6812 IOLog("PMStats: Hibernate read took %qd ms\n", delta/1000000ULL); 6813 6814 publishPMStats = OSData::withBytes(&gPMStats, sizeof(gPMStats)); 6815 setProperty(kIOPMSleepStatisticsKey, publishPMStats); 6816 publishPMStats->release(); 6817 bzero(&gPMStats, sizeof(gPMStats)); 6818 } 6819 break; 6820 } 6821} 6822 6823/* 6824 * Appends a record of the application response to 6825 * IOPMrootDomain::pmStatsAppResponses 6826 */ 6827void IOPMrootDomain::pmStatsRecordApplicationResponse( 6828 const OSSymbol *response, 6829 const char *name, 6830 int messageType, 6831 uint32_t delay_ms, 6832 int app_pid, 6833 OSObject *object, 6834 IOPMPowerStateIndex powerState) 6835{ 6836 OSDictionary *responseDescription = NULL; 6837 OSNumber *delayNum = NULL; 6838 OSNumber *powerCaps = NULL; 6839 OSNumber *pidNum = NULL; 6840 OSNumber *msgNum = NULL; 6841 const OSSymbol *appname; 6842 const OSSymbol *sleep = NULL, *wake = NULL; 6843 IOPMServiceInterestNotifier *notify = 0; 6844 6845 if (object && (notify = OSDynamicCast(IOPMServiceInterestNotifier, object))) 6846 { 6847 if (response->isEqualTo(gIOPMStatsApplicationResponseTimedOut)) 6848 notify->ackTimeoutCnt++; 6849 else 6850 notify->ackTimeoutCnt = 0; 6851 6852 } 6853 6854 if (response->isEqualTo(gIOPMStatsApplicationResponsePrompt) || 6855 (_systemTransitionType == kSystemTransitionNone) || (_systemTransitionType == kSystemTransitionNewCapClient)) 6856 return; 6857 6858 6859 responseDescription = OSDictionary::withCapacity(5); 6860 if (responseDescription) 6861 { 6862 if (response) { 6863 responseDescription->setObject(_statsResponseTypeKey, response); 6864 } 6865 6866 msgNum = OSNumber::withNumber(messageType, 32); 6867 if (msgNum) { 6868 responseDescription->setObject(_statsMessageTypeKey, msgNum); 6869 msgNum->release(); 6870 } 6871 6872 if (name && (strlen(name) > 0)) 6873 { 6874 appname = OSSymbol::withCString(name); 6875 if (appname) { 6876 responseDescription->setObject(_statsNameKey, appname); 6877 appname->release(); 6878 } 6879 } 6880 6881 if (app_pid != -1) { 6882 pidNum = OSNumber::withNumber(app_pid, 32); 6883 if (pidNum) { 6884 responseDescription->setObject(_statsPIDKey, pidNum); 6885 pidNum->release(); 6886 } 6887 } 6888 6889 delayNum = OSNumber::withNumber(delay_ms, 32); 6890 if (delayNum) { 6891 responseDescription->setObject(_statsTimeMSKey, delayNum); 6892 delayNum->release(); 6893 } 6894 6895 if (response->isEqualTo(gIOPMStatsDriverPSChangeSlow)) { 6896 powerCaps = OSNumber::withNumber(powerState, 32); 6897 6898#if !defined(__i386__) && !defined(__x86_64__) 6899 IOLog("%s::powerStateChange type(%d) to(%lu) async took %d ms\n", 6900 name, messageType, 6901 powerState, delay_ms); 6902#endif 6903 6904 } 6905 else { 6906 powerCaps = OSNumber::withNumber(_pendingCapability, 32); 6907 } 6908 if (powerCaps) { 6909 responseDescription->setObject(_statsPowerCapsKey, powerCaps); 6910 powerCaps->release(); 6911 } 6912 6913 sleep = OSSymbol::withCString("Sleep"); 6914 wake = OSSymbol::withCString("Wake"); 6915 if (_systemTransitionType == kSystemTransitionSleep) { 6916 responseDescription->setObject(kIOPMStatsSystemTransitionKey, sleep); 6917 } 6918 else if (_systemTransitionType == kSystemTransitionWake) { 6919 responseDescription->setObject(kIOPMStatsSystemTransitionKey, wake); 6920 } 6921 else if (_systemTransitionType == kSystemTransitionCapability) { 6922 if (CAP_LOSS(kIOPMSystemCapabilityGraphics)) 6923 responseDescription->setObject(kIOPMStatsSystemTransitionKey, sleep); 6924 else if (CAP_GAIN(kIOPMSystemCapabilityGraphics)) 6925 responseDescription->setObject(kIOPMStatsSystemTransitionKey, wake); 6926 } 6927 if (sleep) sleep->release(); 6928 if (wake) wake->release(); 6929 6930 6931 6932 IOLockLock(pmStatsLock); 6933 if (pmStatsAppResponses && pmStatsAppResponses->getCount() < 50) { 6934 pmStatsAppResponses->setObject(responseDescription); 6935 } 6936 IOLockUnlock(pmStatsLock); 6937 6938 responseDescription->release(); 6939 } 6940 6941 return; 6942} 6943 6944// MARK: - 6945// MARK: PMTraceWorker 6946 6947//****************************************************************************** 6948// TracePoint support 6949// 6950//****************************************************************************** 6951 6952#define kIOPMRegisterNVRAMTracePointHandlerKey \ 6953 "IOPMRegisterNVRAMTracePointHandler" 6954 6955IOReturn IOPMrootDomain::callPlatformFunction( 6956 const OSSymbol * functionName, 6957 bool waitForFunction, 6958 void * param1, void * param2, 6959 void * param3, void * param4 ) 6960{ 6961 if (pmTracer && functionName && 6962 functionName->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey) && 6963 !pmTracer->tracePointHandler && !pmTracer->tracePointTarget) 6964 { 6965 uint32_t tracePointPhases, tracePointPCI; 6966 uint64_t statusCode; 6967 6968 pmTracer->tracePointHandler = (IOPMTracePointHandler) param1; 6969 pmTracer->tracePointTarget = (void *) param2; 6970 tracePointPCI = (uint32_t)(uintptr_t) param3; 6971 tracePointPhases = (uint32_t)(uintptr_t) param4; 6972 statusCode = (((uint64_t)tracePointPCI) << 32) | tracePointPhases; 6973 if ((tracePointPhases >> 24) != kIOPMTracePointSystemUp) 6974 { 6975 MSG("Sleep failure code 0x%08x 0x%08x\n", 6976 tracePointPCI, tracePointPhases); 6977 } 6978 setProperty(kIOPMSleepWakeFailureCodeKey, statusCode, 64); 6979 pmTracer->tracePointHandler( pmTracer->tracePointTarget, 0, 0 ); 6980 6981 return kIOReturnSuccess; 6982 } 6983#if HIBERNATION 6984 else if (functionName && 6985 functionName->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey)) 6986 { 6987 if (gSleepPolicyHandler) 6988 return kIOReturnExclusiveAccess; 6989 if (!param1) 6990 return kIOReturnBadArgument; 6991 gSleepPolicyHandler = (IOPMSystemSleepPolicyHandler) param1; 6992 gSleepPolicyTarget = (void *) param2; 6993 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue); 6994 return kIOReturnSuccess; 6995 } 6996#endif 6997 6998 return super::callPlatformFunction( 6999 functionName, waitForFunction, param1, param2, param3, param4); 7000} 7001 7002void IOPMrootDomain::tracePoint( uint8_t point ) 7003{ 7004 if (systemBooting) return; 7005 7006 if (kIOPMTracePointWakeCapabilityClients == point) 7007 acceptSystemWakeEvents(false); 7008 7009 PMDebug(kPMLogSleepWakeTracePoint, point, 0); 7010 pmTracer->tracePoint(point); 7011} 7012 7013void IOPMrootDomain::tracePoint( uint8_t point, uint8_t data ) 7014{ 7015 if (systemBooting) return; 7016 7017 PMDebug(kPMLogSleepWakeTracePoint, point, data); 7018 pmTracer->tracePoint(point, data); 7019} 7020 7021void IOPMrootDomain::traceDetail( uint32_t detail ) 7022{ 7023 if (!systemBooting) 7024 pmTracer->traceDetail( detail ); 7025} 7026 7027 7028IOReturn IOPMrootDomain::configureReport(IOReportChannelList *channelList, 7029 IOReportConfigureAction action, 7030 void *result, 7031 void *destination) 7032{ 7033 unsigned cnt; 7034 if (action != kIOReportGetDimensions) goto exit; 7035 7036 for (cnt = 0; cnt < channelList->nchannels; cnt++) { 7037 if ( (channelList->channels[cnt].channel_id == kSleepCntChID) || 7038 (channelList->channels[cnt].channel_id == kDarkWkCntChID) || 7039 (channelList->channels[cnt].channel_id == kUserWkCntChID) ) { 7040 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions, result); 7041 } 7042 } 7043 7044exit: 7045 return super::configureReport(channelList, action, result, destination); 7046} 7047 7048 7049IOReturn IOPMrootDomain::updateReport(IOReportChannelList *channelList, 7050 IOReportUpdateAction action, 7051 void *result, 7052 void *destination) 7053{ 7054 uint32_t size2cpy; 7055 void *data2cpy; 7056 uint8_t buf[SIMPLEREPORT_BUFSIZE]; 7057 IOBufferMemoryDescriptor *dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination); 7058 unsigned cnt; 7059 uint64_t ch_id; 7060 7061 if (action != kIOReportCopyChannelData) goto exit; 7062 7063 for (cnt = 0; cnt < channelList->nchannels; cnt++) { 7064 ch_id = channelList->channels[cnt].channel_id ; 7065 7066 if ((ch_id == kSleepCntChID) || 7067 (ch_id == kDarkWkCntChID) || (ch_id == kUserWkCntChID)) { 7068 SIMPLEREPORT_INIT(buf, sizeof(buf), getRegistryEntryID(), ch_id, kIOReportCategoryPower); 7069 } 7070 else continue; 7071 7072 if (ch_id == kSleepCntChID) 7073 SIMPLEREPORT_SETVALUE(buf, sleepCnt); 7074 else if (ch_id == kDarkWkCntChID) 7075 SIMPLEREPORT_SETVALUE(buf, darkWakeCnt); 7076 else if (ch_id == kUserWkCntChID) 7077 SIMPLEREPORT_SETVALUE(buf, displayWakeCnt); 7078 7079 SIMPLEREPORT_UPDATEPREP(buf, data2cpy, size2cpy); 7080 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData, result); 7081 dest->appendBytes(data2cpy, size2cpy); 7082 } 7083 7084exit: 7085 return super::updateReport(channelList, action, result, destination); 7086} 7087 7088 7089//****************************************************************************** 7090// PMTraceWorker Class 7091// 7092//****************************************************************************** 7093 7094#undef super 7095#define super OSObject 7096OSDefineMetaClassAndStructors(PMTraceWorker, OSObject) 7097 7098#define kPMBestGuessPCIDevicesCount 25 7099#define kPMMaxRTCBitfieldSize 32 7100 7101PMTraceWorker *PMTraceWorker::tracer(IOPMrootDomain *owner) 7102{ 7103 PMTraceWorker *me; 7104 7105 me = OSTypeAlloc( PMTraceWorker ); 7106 if (!me || !me->init()) 7107 { 7108 return NULL; 7109 } 7110 7111 DLOG("PMTraceWorker %p\n", OBFUSCATE(me)); 7112 7113 // Note that we cannot instantiate the PCI device -> bit mappings here, since 7114 // the IODeviceTree has not yet been created by IOPlatformExpert. We create 7115 // this dictionary lazily. 7116 me->owner = owner; 7117 me->pciDeviceBitMappings = NULL; 7118 me->pciMappingLock = IOLockAlloc(); 7119 me->tracePhase = kIOPMTracePointSystemUp; 7120 me->loginWindowPhase = 0; 7121 me->traceData32 = 0; 7122 return me; 7123} 7124 7125void PMTraceWorker::RTC_TRACE(void) 7126{ 7127 if (tracePointHandler && tracePointTarget) 7128 { 7129 uint32_t wordA; 7130 7131 wordA = (tracePhase << 24) | (loginWindowPhase << 16) | 7132 (traceData8 << 8); 7133 7134 tracePointHandler( tracePointTarget, traceData32, wordA ); 7135 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32, wordA); 7136 } 7137} 7138 7139int PMTraceWorker::recordTopLevelPCIDevice(IOService * pciDevice) 7140{ 7141 const OSSymbol * deviceName; 7142 int index = -1; 7143 7144 IOLockLock(pciMappingLock); 7145 7146 if (!pciDeviceBitMappings) 7147 { 7148 pciDeviceBitMappings = OSArray::withCapacity(kPMBestGuessPCIDevicesCount); 7149 if (!pciDeviceBitMappings) 7150 goto exit; 7151 } 7152 7153 // Check for bitmask overflow. 7154 if (pciDeviceBitMappings->getCount() >= kPMMaxRTCBitfieldSize) 7155 goto exit; 7156 7157 if ((deviceName = pciDevice->copyName()) && 7158 (pciDeviceBitMappings->getNextIndexOfObject(deviceName, 0) == (unsigned int)-1) && 7159 pciDeviceBitMappings->setObject(deviceName)) 7160 { 7161 index = pciDeviceBitMappings->getCount() - 1; 7162 _LOG("PMTrace PCI array: set object %s => %d\n", 7163 deviceName->getCStringNoCopy(), index); 7164 } 7165 if (deviceName) 7166 deviceName->release(); 7167 if (!addedToRegistry && (index >= 0)) 7168 addedToRegistry = owner->setProperty("PCITopLevel", this); 7169 7170exit: 7171 IOLockUnlock(pciMappingLock); 7172 return index; 7173} 7174 7175bool PMTraceWorker::serialize(OSSerialize *s) const 7176{ 7177 bool ok = false; 7178 if (pciDeviceBitMappings) 7179 { 7180 IOLockLock(pciMappingLock); 7181 ok = pciDeviceBitMappings->serialize(s); 7182 IOLockUnlock(pciMappingLock); 7183 } 7184 return ok; 7185} 7186 7187void PMTraceWorker::tracePoint(uint8_t phase) 7188{ 7189 // clear trace detail when phase begins 7190 if (tracePhase != phase) 7191 traceData32 = 0; 7192 7193 tracePhase = phase; 7194 7195 DLOG("trace point 0x%02x\n", tracePhase); 7196 RTC_TRACE(); 7197} 7198 7199void PMTraceWorker::tracePoint(uint8_t phase, uint8_t data8) 7200{ 7201 // clear trace detail when phase begins 7202 if (tracePhase != phase) 7203 traceData32 = 0; 7204 7205 tracePhase = phase; 7206 traceData8 = data8; 7207 7208 DLOG("trace point 0x%02x 0x%02x\n", tracePhase, traceData8); 7209 RTC_TRACE(); 7210} 7211 7212void PMTraceWorker::traceDetail(uint32_t detail) 7213{ 7214 if (kIOPMTracePointSleepPriorityClients != tracePhase) 7215 return; 7216 7217 traceData32 = detail; 7218 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase, traceData32); 7219 7220 RTC_TRACE(); 7221} 7222 7223void PMTraceWorker::traceLoginWindowPhase(uint8_t phase) 7224{ 7225 loginWindowPhase = phase; 7226 7227 DLOG("loginwindow tracepoint 0x%02x\n", loginWindowPhase); 7228 RTC_TRACE(); 7229} 7230 7231void PMTraceWorker::tracePCIPowerChange( 7232 change_t type, IOService *service, uint32_t changeFlags, uint32_t bitNum) 7233{ 7234 uint32_t bitMask; 7235 uint32_t expectedFlag; 7236 7237 // Ignore PCI changes outside of system sleep/wake. 7238 if ((kIOPMTracePointSleepPowerPlaneDrivers != tracePhase) && 7239 (kIOPMTracePointWakePowerPlaneDrivers != tracePhase)) 7240 return; 7241 7242 // Only record the WillChange transition when going to sleep, 7243 // and the DidChange on the way up. 7244 changeFlags &= (kIOPMDomainWillChange | kIOPMDomainDidChange); 7245 expectedFlag = (kIOPMTracePointSleepPowerPlaneDrivers == tracePhase) ? 7246 kIOPMDomainWillChange : kIOPMDomainDidChange; 7247 if (changeFlags != expectedFlag) 7248 return; 7249 7250 // Mark this device off in our bitfield 7251 if (bitNum < kPMMaxRTCBitfieldSize) 7252 { 7253 bitMask = (1 << bitNum); 7254 7255 if (kPowerChangeStart == type) 7256 { 7257 traceData32 |= bitMask; 7258 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n", 7259 service->getName(), bitNum, bitMask, traceData32); 7260 } 7261 else 7262 { 7263 traceData32 &= ~bitMask; 7264 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n", 7265 service->getName(), bitNum, bitMask, traceData32); 7266 } 7267 7268 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase, traceData32); 7269 RTC_TRACE(); 7270 } 7271} 7272 7273uint64_t PMTraceWorker::getPMStatusCode( ) 7274{ 7275 return (((uint64_t)traceData32 << 32) | (tracePhase << 24) | 7276 (loginWindowPhase << 16) | (traceData8 << 8)); 7277 7278} 7279 7280// MARK: - 7281// MARK: PMHaltWorker 7282 7283//****************************************************************************** 7284// PMHaltWorker Class 7285// 7286//****************************************************************************** 7287 7288static unsigned int gPMHaltBusyCount; 7289static unsigned int gPMHaltIdleCount; 7290static int gPMHaltDepth; 7291static unsigned long gPMHaltEvent; 7292static IOLock * gPMHaltLock = 0; 7293static OSArray * gPMHaltArray = 0; 7294static const OSSymbol * gPMHaltClientAcknowledgeKey = 0; 7295 7296PMHaltWorker * PMHaltWorker::worker( void ) 7297{ 7298 PMHaltWorker * me; 7299 IOThread thread; 7300 7301 do { 7302 me = OSTypeAlloc( PMHaltWorker ); 7303 if (!me || !me->init()) 7304 break; 7305 7306 me->lock = IOLockAlloc(); 7307 if (!me->lock) 7308 break; 7309 7310 DLOG("PMHaltWorker %p\n", OBFUSCATE(me)); 7311 me->retain(); // thread holds extra retain 7312 if (KERN_SUCCESS != kernel_thread_start(&PMHaltWorker::main, (void *) me, &thread)) 7313 { 7314 me->release(); 7315 break; 7316 } 7317 thread_deallocate(thread); 7318 return me; 7319 7320 } while (false); 7321 7322 if (me) me->release(); 7323 return 0; 7324} 7325 7326void PMHaltWorker::free( void ) 7327{ 7328 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this)); 7329 if (lock) 7330 { 7331 IOLockFree(lock); 7332 lock = 0; 7333 } 7334 return OSObject::free(); 7335} 7336 7337void PMHaltWorker::main( void * arg, wait_result_t waitResult ) 7338{ 7339 PMHaltWorker * me = (PMHaltWorker *) arg; 7340 7341 IOLockLock( gPMHaltLock ); 7342 gPMHaltBusyCount++; 7343 me->depth = gPMHaltDepth; 7344 IOLockUnlock( gPMHaltLock ); 7345 7346 while (me->depth >= 0) 7347 { 7348 PMHaltWorker::work( me ); 7349 7350 IOLockLock( gPMHaltLock ); 7351 if (++gPMHaltIdleCount >= gPMHaltBusyCount) 7352 { 7353 // This is the last thread to finish work on this level, 7354 // inform everyone to start working on next lower level. 7355 gPMHaltDepth--; 7356 me->depth = gPMHaltDepth; 7357 gPMHaltIdleCount = 0; 7358 thread_wakeup((event_t) &gPMHaltIdleCount); 7359 } 7360 else 7361 { 7362 // One or more threads are still working on this level, 7363 // this thread must wait. 7364 me->depth = gPMHaltDepth - 1; 7365 do { 7366 IOLockSleep(gPMHaltLock, &gPMHaltIdleCount, THREAD_UNINT); 7367 } while (me->depth != gPMHaltDepth); 7368 } 7369 IOLockUnlock( gPMHaltLock ); 7370 } 7371 7372 // No more work to do, terminate thread 7373 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me), me->visits); 7374 thread_wakeup( &gPMHaltDepth ); 7375 me->release(); 7376} 7377 7378void PMHaltWorker::work( PMHaltWorker * me ) 7379{ 7380 IOService * service; 7381 OSSet * inner; 7382 AbsoluteTime startTime; 7383 UInt32 deltaTime; 7384 bool timeout; 7385 7386 while (true) 7387 { 7388 service = 0; 7389 timeout = false; 7390 7391 // Claim an unit of work from the shared pool 7392 IOLockLock( gPMHaltLock ); 7393 inner = (OSSet *)gPMHaltArray->getObject(me->depth); 7394 if (inner) 7395 { 7396 service = (IOService *)inner->getAnyObject(); 7397 if (service) 7398 { 7399 service->retain(); 7400 inner->removeObject(service); 7401 } 7402 } 7403 IOLockUnlock( gPMHaltLock ); 7404 if (!service) 7405 break; // no more work at this depth 7406 7407 clock_get_uptime(&startTime); 7408 7409 if (!service->isInactive() && 7410 service->setProperty(gPMHaltClientAcknowledgeKey, me)) 7411 { 7412 IOLockLock(me->lock); 7413 me->startTime = startTime; 7414 me->service = service; 7415 me->timeout = false; 7416 IOLockUnlock(me->lock); 7417 7418 service->systemWillShutdown( gPMHaltEvent ); 7419 7420 // Wait for driver acknowledgement 7421 IOLockLock(me->lock); 7422 while (service->getProperty(gPMHaltClientAcknowledgeKey)) 7423 { 7424 IOLockSleep(me->lock, me, THREAD_UNINT); 7425 } 7426 me->service = 0; 7427 timeout = me->timeout; 7428 IOLockUnlock(me->lock); 7429 } 7430 7431 deltaTime = computeDeltaTimeMS(&startTime); 7432 if ((deltaTime > kPMHaltTimeoutMS) || timeout || 7433 (gIOKitDebug & kIOLogPMRootDomain)) 7434 { 7435 LOG("%s driver %s (%p) took %u ms\n", 7436 (gPMHaltEvent == kIOMessageSystemWillPowerOff) ? 7437 "PowerOff" : "Restart", 7438 service->getName(), OBFUSCATE(service), 7439 (uint32_t) deltaTime ); 7440 } 7441 7442 service->release(); 7443 me->visits++; 7444 } 7445} 7446 7447void PMHaltWorker::checkTimeout( PMHaltWorker * me, AbsoluteTime * now ) 7448{ 7449 UInt64 nano; 7450 AbsoluteTime startTime; 7451 AbsoluteTime endTime; 7452 7453 endTime = *now; 7454 7455 IOLockLock(me->lock); 7456 if (me->service && !me->timeout) 7457 { 7458 startTime = me->startTime; 7459 nano = 0; 7460 if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0) 7461 { 7462 SUB_ABSOLUTETIME(&endTime, &startTime); 7463 absolutetime_to_nanoseconds(endTime, &nano); 7464 } 7465 if (nano > 3000000000ULL) 7466 { 7467 me->timeout = true; 7468 MSG("%s still waiting on %s\n", 7469 (gPMHaltEvent == kIOMessageSystemWillPowerOff) ? 7470 "PowerOff" : "Restart", 7471 me->service->getName()); 7472 } 7473 } 7474 IOLockUnlock(me->lock); 7475} 7476 7477 7478//****************************************************************************** 7479// acknowledgeSystemWillShutdown 7480// 7481// Acknowledgement from drivers that they have prepared for shutdown/restart. 7482//****************************************************************************** 7483 7484void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService * from ) 7485{ 7486 PMHaltWorker * worker; 7487 OSObject * prop; 7488 7489 if (!from) 7490 return; 7491 7492 //DLOG("%s acknowledged\n", from->getName()); 7493 prop = from->copyProperty( gPMHaltClientAcknowledgeKey ); 7494 if (prop) 7495 { 7496 worker = (PMHaltWorker *) prop; 7497 IOLockLock(worker->lock); 7498 from->removeProperty( gPMHaltClientAcknowledgeKey ); 7499 thread_wakeup((event_t) worker); 7500 IOLockUnlock(worker->lock); 7501 worker->release(); 7502 } 7503 else 7504 { 7505 DLOG("%s acknowledged without worker property\n", 7506 from->getName()); 7507 } 7508} 7509 7510 7511//****************************************************************************** 7512// notifySystemShutdown 7513// 7514// Notify all objects in PM tree that system will shutdown or restart 7515//****************************************************************************** 7516 7517static void 7518notifySystemShutdown( IOService * root, unsigned long event ) 7519{ 7520#define PLACEHOLDER ((OSSet *)gPMHaltArray) 7521 IORegistryIterator * iter; 7522 IORegistryEntry * entry; 7523 IOService * node; 7524 OSSet * inner; 7525 PMHaltWorker * workers[kPMHaltMaxWorkers]; 7526 AbsoluteTime deadline; 7527 unsigned int totalNodes = 0; 7528 unsigned int depth; 7529 unsigned int rootDepth; 7530 unsigned int numWorkers; 7531 unsigned int count; 7532 int waitResult; 7533 void * baseFunc; 7534 bool ok; 7535 7536 DLOG("%s event = %lx\n", __FUNCTION__, event); 7537 7538 baseFunc = OSMemberFunctionCast(void *, root, &IOService::systemWillShutdown); 7539 7540 // Iterate the entire PM tree starting from root 7541 7542 rootDepth = root->getDepth( gIOPowerPlane ); 7543 if (!rootDepth) goto done; 7544 7545 // debug - for repeated test runs 7546 while (PMHaltWorker::metaClass->getInstanceCount()) 7547 IOSleep(1); 7548 7549 if (!gPMHaltArray) 7550 { 7551 gPMHaltArray = OSArray::withCapacity(40); 7552 if (!gPMHaltArray) goto done; 7553 } 7554 else // debug 7555 gPMHaltArray->flushCollection(); 7556 7557 if (!gPMHaltLock) 7558 { 7559 gPMHaltLock = IOLockAlloc(); 7560 if (!gPMHaltLock) goto done; 7561 } 7562 7563 if (!gPMHaltClientAcknowledgeKey) 7564 { 7565 gPMHaltClientAcknowledgeKey = 7566 OSSymbol::withCStringNoCopy("PMShutdown"); 7567 if (!gPMHaltClientAcknowledgeKey) goto done; 7568 } 7569 7570 gPMHaltEvent = event; 7571 7572 // Depth-first walk of PM plane 7573 7574 iter = IORegistryIterator::iterateOver( 7575 root, gIOPowerPlane, kIORegistryIterateRecursively); 7576 7577 if (iter) 7578 { 7579 while ((entry = iter->getNextObject())) 7580 { 7581 node = OSDynamicCast(IOService, entry); 7582 if (!node) 7583 continue; 7584 7585 if (baseFunc == 7586 OSMemberFunctionCast(void *, node, &IOService::systemWillShutdown)) 7587 continue; 7588 7589 depth = node->getDepth( gIOPowerPlane ); 7590 if (depth <= rootDepth) 7591 continue; 7592 7593 ok = false; 7594 7595 // adjust to zero based depth 7596 depth -= (rootDepth + 1); 7597 7598 // gPMHaltArray is an array of containers, each container 7599 // refers to nodes with the same depth. 7600 7601 count = gPMHaltArray->getCount(); 7602 while (depth >= count) 7603 { 7604 // expand array and insert placeholders 7605 gPMHaltArray->setObject(PLACEHOLDER); 7606 count++; 7607 } 7608 count = gPMHaltArray->getCount(); 7609 if (depth < count) 7610 { 7611 inner = (OSSet *)gPMHaltArray->getObject(depth); 7612 if (inner == PLACEHOLDER) 7613 { 7614 inner = OSSet::withCapacity(40); 7615 if (inner) 7616 { 7617 gPMHaltArray->replaceObject(depth, inner); 7618 inner->release(); 7619 } 7620 } 7621 7622 // PM nodes that appear more than once in the tree will have 7623 // the same depth, OSSet will refuse to add the node twice. 7624 if (inner) 7625 ok = inner->setObject(node); 7626 } 7627 if (!ok) 7628 DLOG("Skipped PM node %s\n", node->getName()); 7629 } 7630 iter->release(); 7631 } 7632 7633 // debug only 7634 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); i++) 7635 { 7636 count = 0; 7637 if (inner != PLACEHOLDER) 7638 count = inner->getCount(); 7639 DLOG("Nodes at depth %u = %u\n", i, count); 7640 } 7641 7642 // strip placeholders (not all depths are populated) 7643 numWorkers = 0; 7644 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); ) 7645 { 7646 if (inner == PLACEHOLDER) 7647 { 7648 gPMHaltArray->removeObject(i); 7649 continue; 7650 } 7651 count = inner->getCount(); 7652 if (count > numWorkers) 7653 numWorkers = count; 7654 totalNodes += count; 7655 i++; 7656 } 7657 7658 if (gPMHaltArray->getCount() == 0 || !numWorkers) 7659 goto done; 7660 7661 gPMHaltBusyCount = 0; 7662 gPMHaltIdleCount = 0; 7663 gPMHaltDepth = gPMHaltArray->getCount() - 1; 7664 7665 // Create multiple workers (and threads) 7666 7667 if (numWorkers > kPMHaltMaxWorkers) 7668 numWorkers = kPMHaltMaxWorkers; 7669 7670 DLOG("PM nodes %u, maxDepth %u, workers %u\n", 7671 totalNodes, gPMHaltArray->getCount(), numWorkers); 7672 7673 for (unsigned int i = 0; i < numWorkers; i++) 7674 workers[i] = PMHaltWorker::worker(); 7675 7676 // Wait for workers to exhaust all available work 7677 7678 IOLockLock(gPMHaltLock); 7679 while (gPMHaltDepth >= 0) 7680 { 7681 clock_interval_to_deadline(1000, kMillisecondScale, &deadline); 7682 7683 waitResult = IOLockSleepDeadline( 7684 gPMHaltLock, &gPMHaltDepth, deadline, THREAD_UNINT); 7685 if (THREAD_TIMED_OUT == waitResult) 7686 { 7687 AbsoluteTime now; 7688 clock_get_uptime(&now); 7689 7690 IOLockUnlock(gPMHaltLock); 7691 for (unsigned int i = 0 ; i < numWorkers; i++) 7692 { 7693 if (workers[i]) 7694 PMHaltWorker::checkTimeout(workers[i], &now); 7695 } 7696 IOLockLock(gPMHaltLock); 7697 } 7698 } 7699 IOLockUnlock(gPMHaltLock); 7700 7701 // Release all workers 7702 7703 for (unsigned int i = 0; i < numWorkers; i++) 7704 { 7705 if (workers[i]) 7706 workers[i]->release(); 7707 // worker also retained by it's own thread 7708 } 7709 7710done: 7711 DLOG("%s done\n", __FUNCTION__); 7712 return; 7713} 7714 7715// MARK: - 7716// MARK: Kernel Assertion 7717 7718/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 7719 7720IOPMDriverAssertionID IOPMrootDomain::createPMAssertion( 7721 IOPMDriverAssertionType whichAssertionBits, 7722 IOPMDriverAssertionLevel assertionLevel, 7723 IOService *ownerService, 7724 const char *ownerDescription) 7725{ 7726 IOReturn ret; 7727 IOPMDriverAssertionID newAssertion; 7728 7729 if (!pmAssertions) 7730 return 0; 7731 7732 ret = pmAssertions->createAssertion(whichAssertionBits, assertionLevel, ownerService, ownerDescription, &newAssertion); 7733 7734 if (kIOReturnSuccess == ret) 7735 return newAssertion; 7736 else 7737 return 0; 7738} 7739 7740IOReturn IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion) 7741{ 7742 if (!pmAssertions) 7743 return kIOReturnInternalError; 7744 7745 return pmAssertions->releaseAssertion(releaseAssertion); 7746} 7747 7748 7749IOReturn IOPMrootDomain::setPMAssertionLevel( 7750 IOPMDriverAssertionID assertionID, 7751 IOPMDriverAssertionLevel assertionLevel) 7752{ 7753 return pmAssertions->setAssertionLevel(assertionID, assertionLevel); 7754} 7755 7756IOPMDriverAssertionLevel IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion) 7757{ 7758 IOPMDriverAssertionType sysLevels; 7759 7760 if (!pmAssertions || whichAssertion == 0) 7761 return kIOPMDriverAssertionLevelOff; 7762 7763 sysLevels = pmAssertions->getActivatedAssertions(); 7764 7765 // Check that every bit set in argument 'whichAssertion' is asserted 7766 // in the aggregate bits. 7767 if ((sysLevels & whichAssertion) == whichAssertion) 7768 return kIOPMDriverAssertionLevelOn; 7769 else 7770 return kIOPMDriverAssertionLevelOff; 7771} 7772 7773IOReturn IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels) 7774{ 7775 if (!pmAssertions) 7776 return kIOReturnNotFound; 7777 7778 return pmAssertions->setUserAssertionLevels(inLevels); 7779} 7780 7781bool IOPMrootDomain::serializeProperties( OSSerialize * s ) const 7782{ 7783 if (pmAssertions) 7784 { 7785 pmAssertions->publishProperties(); 7786 } 7787 return( IOService::serializeProperties(s) ); 7788} 7789 7790OSObject * IOPMrootDomain::copyProperty( const char * aKey) const 7791{ 7792 OSObject *obj = NULL; 7793 obj = IOService::copyProperty(aKey); 7794 7795 if (obj) return obj; 7796 7797 if (!strncmp(aKey, kIOPMSleepWakeWdogRebootKey, 7798 sizeof(kIOPMSleepWakeWdogRebootKey))) { 7799 if (swd_flags & SWD_BOOT_BY_SW_WDOG) 7800 return OSBoolean::withBoolean(true); 7801 else 7802 return OSBoolean::withBoolean(false); 7803 7804 } 7805 7806 if (!strncmp(aKey, kIOPMSleepWakeWdogLogsValidKey, 7807 sizeof(kIOPMSleepWakeWdogLogsValidKey))) { 7808 if (swd_flags & SWD_VALID_LOGS) 7809 return OSBoolean::withBoolean(true); 7810 else 7811 return OSBoolean::withBoolean(false); 7812 7813 } 7814 7815 /* 7816 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey' 7817 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be 7818 * issued by DisplayWrangler on darkwake. 7819 */ 7820 if (!strcmp(aKey, "DesktopMode")) { 7821 if (desktopMode) 7822 return OSBoolean::withBoolean(true); 7823 else 7824 return OSBoolean::withBoolean(false); 7825 } 7826 if (!strcmp(aKey, "DisplayIdleForDemandSleep")) { 7827 if (displayIdleForDemandSleep) { 7828 return OSBoolean::withBoolean(true); 7829 } 7830 else { 7831 return OSBoolean::withBoolean(false); 7832 } 7833 } 7834 7835 if (!strcmp(aKey, kIOPMDriverWakeEventsKey)) 7836 { 7837 OSArray * array = 0; 7838 WAKEEVENT_LOCK(); 7839 if (_systemWakeEventsArray && _systemWakeEventsArray->getCount()) 7840 array = OSArray::withArray(_systemWakeEventsArray); 7841 WAKEEVENT_UNLOCK(); 7842 return array; 7843 } 7844 7845 if (!strcmp(aKey, kIOPMSleepStatisticsAppsKey)) 7846 { 7847 OSArray * array = 0; 7848 IOLockLock(pmStatsLock); 7849 if (pmStatsAppResponses && pmStatsAppResponses->getCount()) { 7850 array = OSArray::withArray(pmStatsAppResponses); 7851 pmStatsAppResponses->flushCollection(); 7852 } 7853 IOLockUnlock(pmStatsLock); 7854 return array; 7855 } 7856 7857 return NULL; 7858} 7859 7860// MARK: - 7861// MARK: Wake Event Reporting 7862 7863void IOPMrootDomain::copyWakeReasonString( char * outBuf, size_t bufSize ) 7864{ 7865 WAKEEVENT_LOCK(); 7866 strlcpy(outBuf, gWakeReasonString, bufSize); 7867 WAKEEVENT_UNLOCK(); 7868} 7869 7870//****************************************************************************** 7871// acceptSystemWakeEvents 7872// 7873// Private control for the acceptance of driver wake event claims. 7874//****************************************************************************** 7875 7876void IOPMrootDomain::acceptSystemWakeEvents( bool accept ) 7877{ 7878 bool logWakeReason = false; 7879 7880 WAKEEVENT_LOCK(); 7881 if (accept) 7882 { 7883 gWakeReasonString[0] = '\0'; 7884 if (!_systemWakeEventsArray) 7885 _systemWakeEventsArray = OSArray::withCapacity(4); 7886 if ((_acceptSystemWakeEvents = (_systemWakeEventsArray != 0))) 7887 _systemWakeEventsArray->flushCollection(); 7888 } 7889 else 7890 { 7891 _acceptSystemWakeEvents = false; 7892 } 7893 WAKEEVENT_UNLOCK(); 7894 7895 if (logWakeReason) 7896 MSG("system wake events:%s\n", gWakeReasonString); 7897} 7898 7899//****************************************************************************** 7900// claimSystemWakeEvent 7901// 7902// For a driver to claim a device is the source/conduit of a system wake event. 7903//****************************************************************************** 7904 7905void IOPMrootDomain::claimSystemWakeEvent( 7906 IOService * device, 7907 IOOptionBits flags, 7908 const char * reason, 7909 OSObject * details ) 7910{ 7911 const OSSymbol * deviceName = 0; 7912 OSNumber * deviceRegId = 0; 7913 OSNumber * claimTime = 0; 7914 OSData * flagsData = 0; 7915 OSString * reasonString = 0; 7916 OSDictionary * d = 0; 7917 uint64_t timestamp; 7918 bool ok = false; 7919 7920 pmEventTimeStamp(×tamp); 7921 7922 if (!device || !reason) return; 7923 7924 deviceName = device->copyName(gIOServicePlane); 7925 deviceRegId = OSNumber::withNumber(device->getRegistryEntryID(), 64); 7926 claimTime = OSNumber::withNumber(timestamp, 64); 7927 flagsData = OSData::withBytes(&flags, sizeof(flags)); 7928 reasonString = OSString::withCString(reason); 7929 d = OSDictionary::withCapacity(5 + (details ? 1 : 0)); 7930 if (!deviceName || !deviceRegId || !claimTime || !flagsData || !reasonString) 7931 goto done; 7932 7933 d->setObject(gIONameKey, deviceName); 7934 d->setObject(gIORegistryEntryIDKey, deviceRegId); 7935 d->setObject(kIOPMWakeEventTimeKey, claimTime); 7936 d->setObject(kIOPMWakeEventFlagsKey, flagsData); 7937 d->setObject(kIOPMWakeEventReasonKey, reasonString); 7938 if (details) 7939 d->setObject(kIOPMWakeEventDetailsKey, details); 7940 7941 WAKEEVENT_LOCK(); 7942 if (!gWakeReasonSysctlRegistered) 7943 { 7944 // Lazy registration until the platform driver stops registering 7945 // the same name. 7946 gWakeReasonSysctlRegistered = true; 7947 } 7948 if (_acceptSystemWakeEvents) 7949 { 7950 ok = _systemWakeEventsArray->setObject(d); 7951 if (gWakeReasonString[0] != '\0') 7952 strlcat(gWakeReasonString, " ", sizeof(gWakeReasonString)); 7953 strlcat(gWakeReasonString, reason, sizeof(gWakeReasonString)); 7954 } 7955 WAKEEVENT_UNLOCK(); 7956 7957done: 7958 if (deviceName) deviceName->release(); 7959 if (deviceRegId) deviceRegId->release(); 7960 if (claimTime) claimTime->release(); 7961 if (flagsData) flagsData->release(); 7962 if (reasonString) reasonString->release(); 7963 if (d) d->release(); 7964} 7965 7966/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 7967 7968// MARK: - 7969// MARK: PMSettingHandle 7970 7971OSDefineMetaClassAndStructors( PMSettingHandle, OSObject ) 7972 7973void PMSettingHandle::free( void ) 7974{ 7975 if (pmso) 7976 { 7977 pmso->clientHandleFreed(); 7978 pmso->release(); 7979 pmso = 0; 7980 } 7981 7982 OSObject::free(); 7983} 7984 7985// MARK: - 7986// MARK: PMSettingObject 7987 7988#undef super 7989#define super OSObject 7990OSDefineMetaClassAndFinalStructors( PMSettingObject, OSObject ) 7991 7992/* 7993 * Static constructor/initializer for PMSettingObject 7994 */ 7995PMSettingObject *PMSettingObject::pmSettingObject( 7996 IOPMrootDomain *parent_arg, 7997 IOPMSettingControllerCallback handler_arg, 7998 OSObject *target_arg, 7999 uintptr_t refcon_arg, 8000 uint32_t supportedPowerSources, 8001 const OSSymbol * settings[], 8002 OSObject **handle_obj) 8003{ 8004 uint32_t settingCount = 0; 8005 PMSettingObject *pmso = 0; 8006 PMSettingHandle *pmsh = 0; 8007 8008 if ( !parent_arg || !handler_arg || !settings || !handle_obj ) 8009 return NULL; 8010 8011 // count OSSymbol entries in NULL terminated settings array 8012 while (settings[settingCount]) { 8013 settingCount++; 8014 } 8015 if (0 == settingCount) 8016 return NULL; 8017 8018 pmso = new PMSettingObject; 8019 if (!pmso || !pmso->init()) 8020 goto fail; 8021 8022 pmsh = new PMSettingHandle; 8023 if (!pmsh || !pmsh->init()) 8024 goto fail; 8025 8026 queue_init(&pmso->calloutQueue); 8027 pmso->parent = parent_arg; 8028 pmso->func = handler_arg; 8029 pmso->target = target_arg; 8030 pmso->refcon = refcon_arg; 8031 pmso->settingCount = settingCount; 8032 8033 pmso->retain(); // handle holds a retain on pmso 8034 pmsh->pmso = pmso; 8035 pmso->pmsh = pmsh; 8036 8037 pmso->publishedFeatureID = (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount); 8038 if (pmso->publishedFeatureID) { 8039 for (unsigned int i=0; i<settingCount; i++) { 8040 // Since there is now at least one listener to this setting, publish 8041 // PM root domain support for it. 8042 parent_arg->publishPMSetting( settings[i], 8043 supportedPowerSources, &pmso->publishedFeatureID[i] ); 8044 } 8045 } 8046 8047 *handle_obj = pmsh; 8048 return pmso; 8049 8050fail: 8051 if (pmso) pmso->release(); 8052 if (pmsh) pmsh->release(); 8053 return NULL; 8054} 8055 8056void PMSettingObject::free( void ) 8057{ 8058 if (publishedFeatureID) { 8059 for (uint32_t i=0; i<settingCount; i++) { 8060 if (publishedFeatureID[i]) { 8061 parent->removePublishedFeature( publishedFeatureID[i] ); 8062 } 8063 } 8064 8065 IOFree(publishedFeatureID, sizeof(uint32_t) * settingCount); 8066 } 8067 8068 super::free(); 8069} 8070 8071void PMSettingObject::dispatchPMSetting( const OSSymbol * type, OSObject * object ) 8072{ 8073 (*func)(target, type, object, refcon); 8074} 8075 8076void PMSettingObject::clientHandleFreed( void ) 8077{ 8078 parent->deregisterPMSettingObject(this); 8079} 8080 8081// MARK: - 8082// MARK: PMAssertionsTracker 8083 8084//********************************************************************************* 8085//********************************************************************************* 8086//********************************************************************************* 8087// class PMAssertionsTracker Implementation 8088 8089#define kAssertUniqueIDStart 500 8090 8091PMAssertionsTracker *PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain *rootDomain ) 8092{ 8093 PMAssertionsTracker *myself; 8094 8095 myself = new PMAssertionsTracker; 8096 8097 if (myself) { 8098 myself->init(); 8099 myself->owner = rootDomain; 8100 myself->issuingUniqueID = kAssertUniqueIDStart; 8101 myself->assertionsArray = OSArray::withCapacity(5); 8102 myself->assertionsKernel = 0; 8103 myself->assertionsUser = 0; 8104 myself->assertionsCombined = 0; 8105 myself->assertionsArrayLock = IOLockAlloc(); 8106 myself->tabulateProducerCount = myself->tabulateConsumerCount = 0; 8107 8108 if (!myself->assertionsArray || !myself->assertionsArrayLock) 8109 myself = NULL; 8110 } 8111 8112 return myself; 8113} 8114 8115/* tabulate 8116 * - Update assertionsKernel to reflect the state of all 8117 * assertions in the kernel. 8118 * - Update assertionsCombined to reflect both kernel & user space. 8119 */ 8120void PMAssertionsTracker::tabulate(void) 8121{ 8122 int i; 8123 int count; 8124 PMAssertStruct *_a = NULL; 8125 OSData *_d = NULL; 8126 8127 IOPMDriverAssertionType oldKernel = assertionsKernel; 8128 IOPMDriverAssertionType oldCombined = assertionsCombined; 8129 8130 ASSERT_GATED(); 8131 8132 assertionsKernel = 0; 8133 assertionsCombined = 0; 8134 8135 if (!assertionsArray) 8136 return; 8137 8138 if ((count = assertionsArray->getCount())) 8139 { 8140 for (i=0; i<count; i++) 8141 { 8142 _d = OSDynamicCast(OSData, assertionsArray->getObject(i)); 8143 if (_d) 8144 { 8145 _a = (PMAssertStruct *)_d->getBytesNoCopy(); 8146 if (_a && (kIOPMDriverAssertionLevelOn == _a->level)) 8147 assertionsKernel |= _a->assertionBits; 8148 } 8149 } 8150 } 8151 8152 tabulateProducerCount++; 8153 assertionsCombined = assertionsKernel | assertionsUser; 8154 8155 if ((assertionsKernel != oldKernel) || 8156 (assertionsCombined != oldCombined)) 8157 { 8158 owner->evaluateAssertions(assertionsCombined, oldCombined); 8159 } 8160} 8161 8162void PMAssertionsTracker::publishProperties( void ) 8163{ 8164 OSArray *assertionsSummary = NULL; 8165 8166 if (tabulateConsumerCount != tabulateProducerCount) 8167 { 8168 IOLockLock(assertionsArrayLock); 8169 8170 tabulateConsumerCount = tabulateProducerCount; 8171 8172 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed" 8173 */ 8174 assertionsSummary = copyAssertionsArray(); 8175 if (assertionsSummary) 8176 { 8177 owner->setProperty(kIOPMAssertionsDriverDetailedKey, assertionsSummary); 8178 assertionsSummary->release(); 8179 } 8180 else 8181 { 8182 owner->removeProperty(kIOPMAssertionsDriverDetailedKey); 8183 } 8184 8185 /* Publish the IOPMrootDomain property "DriverPMAssertions" 8186 */ 8187 owner->setProperty(kIOPMAssertionsDriverKey, assertionsKernel, 64); 8188 8189 IOLockUnlock(assertionsArrayLock); 8190 } 8191} 8192 8193PMAssertionsTracker::PMAssertStruct *PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id, int *index) 8194{ 8195 PMAssertStruct *_a = NULL; 8196 OSData *_d = NULL; 8197 int found = -1; 8198 int count = 0; 8199 int i = 0; 8200 8201 if (assertionsArray 8202 && (count = assertionsArray->getCount())) 8203 { 8204 for (i=0; i<count; i++) 8205 { 8206 _d = OSDynamicCast(OSData, assertionsArray->getObject(i)); 8207 if (_d) 8208 { 8209 _a = (PMAssertStruct *)_d->getBytesNoCopy(); 8210 if (_a && (_id == _a->id)) { 8211 found = i; 8212 break; 8213 } 8214 } 8215 } 8216 } 8217 8218 if (-1 == found) { 8219 return NULL; 8220 } else { 8221 if (index) 8222 *index = found; 8223 return _a; 8224 } 8225} 8226 8227/* PMAssertionsTracker::handleCreateAssertion 8228 * Perform assertion work on the PM workloop. Do not call directly. 8229 */ 8230IOReturn PMAssertionsTracker::handleCreateAssertion(OSData *newAssertion) 8231{ 8232 ASSERT_GATED(); 8233 8234 if (newAssertion) 8235 { 8236 IOLockLock(assertionsArrayLock); 8237 assertionsArray->setObject(newAssertion); 8238 IOLockUnlock(assertionsArrayLock); 8239 newAssertion->release(); 8240 8241 tabulate(); 8242 } 8243 return kIOReturnSuccess; 8244} 8245 8246/* PMAssertionsTracker::createAssertion 8247 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if 8248 * appropiate. 8249 */ 8250IOReturn PMAssertionsTracker::createAssertion( 8251 IOPMDriverAssertionType which, 8252 IOPMDriverAssertionLevel level, 8253 IOService *serviceID, 8254 const char *whoItIs, 8255 IOPMDriverAssertionID *outID) 8256{ 8257 OSData *dataStore = NULL; 8258 PMAssertStruct track; 8259 8260 // Warning: trillions and trillions of created assertions may overflow the unique ID. 8261 track.id = OSIncrementAtomic64((SInt64*) &issuingUniqueID); 8262 track.level = level; 8263 track.assertionBits = which; 8264 track.ownerString = whoItIs ? OSSymbol::withCString(whoItIs):0; 8265 track.ownerService = serviceID; 8266 track.registryEntryID = serviceID ? serviceID->getRegistryEntryID():0; 8267 track.modifiedTime = 0; 8268 pmEventTimeStamp(&track.createdTime); 8269 8270 dataStore = OSData::withBytes(&track, sizeof(PMAssertStruct)); 8271 if (!dataStore) 8272 { 8273 if (track.ownerString) 8274 track.ownerString->release(); 8275 return kIOReturnNoMemory; 8276 } 8277 8278 *outID = track.id; 8279 8280 if (owner && owner->pmPowerStateQueue) { 8281 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionCreate, (void *)dataStore); 8282 } 8283 8284 return kIOReturnSuccess; 8285} 8286 8287/* PMAssertionsTracker::handleReleaseAssertion 8288 * Runs in PM workloop. Do not call directly. 8289 */ 8290IOReturn PMAssertionsTracker::handleReleaseAssertion( 8291 IOPMDriverAssertionID _id) 8292{ 8293 ASSERT_GATED(); 8294 8295 int index; 8296 PMAssertStruct *assertStruct = detailsForID(_id, &index); 8297 8298 if (!assertStruct) 8299 return kIOReturnNotFound; 8300 8301 IOLockLock(assertionsArrayLock); 8302 if (assertStruct->ownerString) 8303 assertStruct->ownerString->release(); 8304 8305 assertionsArray->removeObject(index); 8306 IOLockUnlock(assertionsArrayLock); 8307 8308 tabulate(); 8309 return kIOReturnSuccess; 8310} 8311 8312/* PMAssertionsTracker::releaseAssertion 8313 * Releases an assertion and affects system behavior if appropiate. 8314 * Actual work happens on PM workloop. 8315 */ 8316IOReturn PMAssertionsTracker::releaseAssertion( 8317 IOPMDriverAssertionID _id) 8318{ 8319 if (owner && owner->pmPowerStateQueue) { 8320 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionRelease, 0, _id); 8321 } 8322 return kIOReturnSuccess; 8323} 8324 8325/* PMAssertionsTracker::handleSetAssertionLevel 8326 * Runs in PM workloop. Do not call directly. 8327 */ 8328IOReturn PMAssertionsTracker::handleSetAssertionLevel( 8329 IOPMDriverAssertionID _id, 8330 IOPMDriverAssertionLevel _level) 8331{ 8332 PMAssertStruct *assertStruct = detailsForID(_id, NULL); 8333 8334 ASSERT_GATED(); 8335 8336 if (!assertStruct) { 8337 return kIOReturnNotFound; 8338 } 8339 8340 IOLockLock(assertionsArrayLock); 8341 pmEventTimeStamp(&assertStruct->modifiedTime); 8342 assertStruct->level = _level; 8343 IOLockUnlock(assertionsArrayLock); 8344 8345 tabulate(); 8346 return kIOReturnSuccess; 8347} 8348 8349/* PMAssertionsTracker::setAssertionLevel 8350 */ 8351IOReturn PMAssertionsTracker::setAssertionLevel( 8352 IOPMDriverAssertionID _id, 8353 IOPMDriverAssertionLevel _level) 8354{ 8355 if (owner && owner->pmPowerStateQueue) { 8356 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionSetLevel, 8357 (void *)(uintptr_t)_level, _id); 8358 } 8359 8360 return kIOReturnSuccess; 8361} 8362 8363IOReturn PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0) 8364{ 8365 IOPMDriverAssertionType new_user_levels = *(IOPMDriverAssertionType *) arg0; 8366 8367 ASSERT_GATED(); 8368 8369 if (new_user_levels != assertionsUser) 8370 { 8371 assertionsUser = new_user_levels; 8372 DLOG("assertionsUser 0x%llx\n", assertionsUser); 8373 } 8374 8375 tabulate(); 8376 return kIOReturnSuccess; 8377} 8378 8379IOReturn PMAssertionsTracker::setUserAssertionLevels( 8380 IOPMDriverAssertionType new_user_levels) 8381{ 8382 if (gIOPMWorkLoop) { 8383 gIOPMWorkLoop->runAction( 8384 OSMemberFunctionCast( 8385 IOWorkLoop::Action, 8386 this, 8387 &PMAssertionsTracker::handleSetUserAssertionLevels), 8388 this, 8389 (void *) &new_user_levels, 0, 0, 0); 8390 } 8391 8392 return kIOReturnSuccess; 8393} 8394 8395 8396OSArray *PMAssertionsTracker::copyAssertionsArray(void) 8397{ 8398 int count; 8399 int i; 8400 OSArray *outArray = NULL; 8401 8402 if (!assertionsArray || 8403 (0 == (count = assertionsArray->getCount())) || 8404 (NULL == (outArray = OSArray::withCapacity(count)))) 8405 { 8406 goto exit; 8407 } 8408 8409 for (i=0; i<count; i++) 8410 { 8411 PMAssertStruct *_a = NULL; 8412 OSData *_d = NULL; 8413 OSDictionary *details = NULL; 8414 8415 _d = OSDynamicCast(OSData, assertionsArray->getObject(i)); 8416 if (_d && (_a = (PMAssertStruct *)_d->getBytesNoCopy())) 8417 { 8418 OSNumber *_n = NULL; 8419 8420 details = OSDictionary::withCapacity(7); 8421 if (!details) 8422 continue; 8423 8424 outArray->setObject(details); 8425 details->release(); 8426 8427 _n = OSNumber::withNumber(_a->id, 64); 8428 if (_n) { 8429 details->setObject(kIOPMDriverAssertionIDKey, _n); 8430 _n->release(); 8431 } 8432 _n = OSNumber::withNumber(_a->createdTime, 64); 8433 if (_n) { 8434 details->setObject(kIOPMDriverAssertionCreatedTimeKey, _n); 8435 _n->release(); 8436 } 8437 _n = OSNumber::withNumber(_a->modifiedTime, 64); 8438 if (_n) { 8439 details->setObject(kIOPMDriverAssertionModifiedTimeKey, _n); 8440 _n->release(); 8441 } 8442 _n = OSNumber::withNumber((uintptr_t)_a->registryEntryID, 64); 8443 if (_n) { 8444 details->setObject(kIOPMDriverAssertionRegistryEntryIDKey, _n); 8445 _n->release(); 8446 } 8447 _n = OSNumber::withNumber(_a->level, 64); 8448 if (_n) { 8449 details->setObject(kIOPMDriverAssertionLevelKey, _n); 8450 _n->release(); 8451 } 8452 _n = OSNumber::withNumber(_a->assertionBits, 64); 8453 if (_n) { 8454 details->setObject(kIOPMDriverAssertionAssertedKey, _n); 8455 _n->release(); 8456 } 8457 8458 if (_a->ownerString) { 8459 details->setObject(kIOPMDriverAssertionOwnerStringKey, _a->ownerString); 8460 } 8461 } 8462 } 8463 8464exit: 8465 return outArray; 8466} 8467 8468IOPMDriverAssertionType PMAssertionsTracker::getActivatedAssertions(void) 8469{ 8470 return assertionsCombined; 8471} 8472 8473IOPMDriverAssertionLevel PMAssertionsTracker::getAssertionLevel( 8474 IOPMDriverAssertionType type) 8475{ 8476 if (type && ((type & assertionsKernel) == assertionsKernel)) 8477 { 8478 return kIOPMDriverAssertionLevelOn; 8479 } else { 8480 return kIOPMDriverAssertionLevelOff; 8481 } 8482} 8483 8484//********************************************************************************* 8485//********************************************************************************* 8486//********************************************************************************* 8487 8488 8489static void pmEventTimeStamp(uint64_t *recordTS) 8490{ 8491 clock_sec_t tsec; 8492 clock_usec_t tusec; 8493 8494 if (!recordTS) 8495 return; 8496 8497 // We assume tsec fits into 32 bits; 32 bits holds enough 8498 // seconds for 136 years since the epoch in 1970. 8499 clock_get_calendar_microtime(&tsec, &tusec); 8500 8501 8502 // Pack the sec & microsec calendar time into a uint64_t, for fun. 8503 *recordTS = 0; 8504 *recordTS |= (uint32_t)tusec; 8505 *recordTS |= ((uint64_t)tsec << 32); 8506 8507 return; 8508} 8509 8510// MARK: - 8511// MARK: IORootParent 8512 8513/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 8514 8515OSDefineMetaClassAndFinalStructors(IORootParent, IOService) 8516 8517// The reason that root domain needs a root parent is to facilitate demand 8518// sleep, since a power change from the root parent cannot be vetoed. 8519// 8520// The above statement is no longer true since root domain now performs 8521// demand sleep using overrides. But root parent remains to avoid changing 8522// the power tree stacking. Root parent is parked at the max power state. 8523 8524 8525static IOPMPowerState patriarchPowerStates[2] = 8526{ 8527 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0}, 8528 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0}, 8529}; 8530 8531void IORootParent::initialize( void ) 8532{ 8533} 8534 8535bool IORootParent::start( IOService * nub ) 8536{ 8537 IOService::start(nub); 8538 attachToParent( getRegistryRoot(), gIOPowerPlane ); 8539 PMinit(); 8540 registerPowerDriver(this, patriarchPowerStates, 2); 8541 makeUsable(); 8542 return true; 8543} 8544 8545void IORootParent::shutDownSystem( void ) 8546{ 8547} 8548 8549void IORootParent::restartSystem( void ) 8550{ 8551} 8552 8553void IORootParent::sleepSystem( void ) 8554{ 8555} 8556 8557void IORootParent::dozeSystem( void ) 8558{ 8559} 8560 8561void IORootParent::sleepToDoze( void ) 8562{ 8563} 8564 8565void IORootParent::wakeSystem( void ) 8566{ 8567} 8568 8569OSObject * IORootParent::copyProperty( const char * aKey) const 8570{ 8571 return (IOService::copyProperty(aKey)); 8572} 8573 8574 8575#if defined(__i386__) || defined(__x86_64__) 8576IOReturn IOPMrootDomain::restartWithStackshot() 8577{ 8578 if ((swd_flags & SWD_WDOG_ENABLED) == 0) 8579 return kIOReturnError; 8580 8581 takeStackshot(true, true); 8582 8583 return kIOReturnSuccess; 8584} 8585 8586void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger) 8587{ 8588 takeStackshot(wdogTrigger, false); 8589} 8590 8591void IOPMrootDomain::takeStackshot(bool wdogTrigger, bool isOSXWatchdog) 8592{ 8593 swd_hdr * hdr = NULL; 8594 addr64_t data[3]; 8595 uint32_t wdog_panic = 0; 8596 int cnt = 0; 8597 pid_t pid = 0; 8598 uint32_t flags; 8599 8600 char * dstAddr; 8601 uint32_t size; 8602 uint32_t bytesRemaining; 8603 unsigned int len; 8604 OSString * UUIDstring = NULL; 8605 uint64_t code; 8606 IOMemoryMap * logBufMap = NULL; 8607 8608 swd_stackshot_hdr *stackshotHdr = NULL; 8609 if ( kIOSleepWakeWdogOff & gIOKitDebug ) 8610 return; 8611 8612 if (wdogTrigger) { 8613 if (PE_parse_boot_argn("swd_panic", &wdog_panic, sizeof(wdog_panic)) && 8614 (wdog_panic == 1)) { 8615 // If boot-arg is set to panic on sleep/wake hang, call panic 8616 panic("Sleep/Wake hang detected\n"); 8617 return; 8618 } 8619 else if (swd_flags & SWD_BOOT_BY_SW_WDOG) { 8620 // If current boot is due to this watch dog trigger restart in previous boot, 8621 // then don't trigger again until at least 1 successful sleep & wake. 8622 sleepCnt = displayWakeCnt = 1; 8623 if (!(sleepCnt && displayWakeCnt)) { 8624 IOLog("Shutting down due to repeated Sleep/Wake failures\n"); 8625 PEHaltRestart(kPEHaltCPU); 8626 return; 8627 } 8628 } 8629 8630 } 8631 8632 if (sleepWakeDebugIsWdogEnabled() == false) 8633 return; 8634 8635 if (swd_buffer == NULL) { 8636 sleepWakeDebugMemAlloc(); 8637 if (swd_buffer == NULL) return; 8638 } 8639 8640 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock)) 8641 return; 8642 8643 8644 hdr = (swd_hdr *)swd_buffer; 8645 memset(hdr->UUID, 0x20, sizeof(hdr->UUID)); 8646 if ((UUIDstring = OSDynamicCast(OSString, getProperty(kIOPMSleepWakeUUIDKey))) != NULL ) { 8647 8648 if (wdogTrigger || (!UUIDstring->isEqualTo(hdr->UUID))) { 8649 const char *str = UUIDstring->getCStringNoCopy(); 8650 snprintf(hdr->UUID, sizeof(hdr->UUID), "UUID: %s", str); 8651 } 8652 else { 8653 DLOG("Data for current UUID already exists\n"); 8654 goto exit; 8655 } 8656 } 8657 8658 dstAddr = (char*)hdr + hdr->spindump_offset; 8659 bytesRemaining = SWD_BUF_SIZE - hdr->spindump_offset; 8660 8661 /* if AppleOSXWatchdog triggered the stackshot, set the flag in the heaer */ 8662 hdr->is_osx_watchdog = isOSXWatchdog; 8663 8664 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining); 8665 8666 while (bytesRemaining > sizeof(swd_stackshot_hdr)) { 8667 8668 stackshotHdr = (swd_stackshot_hdr *)dstAddr; 8669 stackshotHdr->magic = SWD_STACKSHOTHDR_MAGIC; 8670 stackshotHdr->size = 0; 8671 bytesRemaining -= sizeof(swd_stackshot_hdr); 8672 dstAddr += sizeof(swd_stackshot_hdr); 8673 8674 if (isOSXWatchdog) { 8675 pid = -1; 8676 size = bytesRemaining; 8677 flags = STACKSHOT_SAVE_LOADINFO | STACKSHOT_SAVE_KEXT_LOADINFO; 8678 } 8679 else if (cnt == 0) { 8680 /* 8681 * Take stackshot of all process on first sample. Size is restricted 8682 * to SWD_INITIAL_STACK_SIZE 8683 */ 8684 pid = -1; 8685 size = (bytesRemaining > SWD_INITIAL_STACK_SIZE) ? SWD_INITIAL_STACK_SIZE : bytesRemaining; 8686 flags = STACKSHOT_SAVE_LOADINFO | STACKSHOT_SAVE_KEXT_LOADINFO|STACKSHOT_SAVE_KERNEL_FRAMES_ONLY; 8687 } 8688 else { 8689 /* Take sample of kernel threads only */ 8690 pid = 0; 8691 size = bytesRemaining; 8692 flags = 0; 8693 } 8694 8695 stack_snapshot_from_kernel(pid, dstAddr, size, flags, &stackshotHdr->size); 8696 8697 dstAddr += stackshotHdr->size; 8698 bytesRemaining -= stackshotHdr->size; 8699 8700 DLOG("Sample: %d size: %d bytesRemaining: %d\n", cnt, stackshotHdr->size, bytesRemaining); 8701 if ((stackshotHdr->size == 0) || (++cnt == 10)) 8702 break; 8703 IOSleep(10); // 10 ms 8704 } 8705 8706 hdr->spindump_size = (SWD_BUF_SIZE - bytesRemaining - hdr->spindump_offset); 8707 8708 8709 memset(hdr->cps, 0x20, sizeof(hdr->cps)); 8710 snprintf(hdr->cps, sizeof(hdr->cps), "\ncps: %d", ((IOService*)this)->getPowerState()); 8711 code = pmTracer->getPMStatusCode(); 8712 memset(hdr->PMStatusCode, 0x20, sizeof(hdr->PMStatusCode)); 8713 snprintf(hdr->PMStatusCode, sizeof(hdr->PMStatusCode), "\nCode: %08x %08x", 8714 (uint32_t)((code >> 32) & 0xffffffff), (uint32_t)(code & 0xffffffff)); 8715 memset(hdr->reason, 0x20, sizeof(hdr->reason)); 8716 snprintf(hdr->reason, sizeof(hdr->reason), "\nStackshot reason: Watchdog\n\n"); 8717 8718 8719 data[0] = round_page(sizeof(swd_hdr) + hdr->spindump_size); 8720 /* Header & rootdomain log is constantly changing and is not covered by CRC */ 8721 data[1] = hdr->crc = crc32(0, ((char*)swd_buffer+hdr->spindump_offset), hdr->spindump_size); 8722 data[2] = kvtophys((vm_offset_t)swd_buffer); 8723 len = sizeof(addr64_t)*3; 8724 DLOG("bytes: 0x%llx crc:0x%llx paddr:0x%llx\n", 8725 data[0], data[1], data[2]); 8726 8727 if (PEWriteNVRAMProperty(kIOSleepWakeDebugKey, data, len) == false) 8728 { 8729 DLOG("Failed to update nvram boot-args\n"); 8730 goto exit; 8731 } 8732 8733exit: 8734 8735 gRootDomain->swd_lock = 0; 8736 8737 if (wdogTrigger) { 8738 IOLog("Restarting to collect Sleep wake debug logs\n"); 8739 PEHaltRestart(kPERestartCPU); 8740 } 8741 else { 8742 logBufMap = sleepWakeDebugRetrieve(); 8743 if (logBufMap) { 8744 sleepWakeDebugDumpFromMem(logBufMap); 8745 logBufMap->release(); 8746 logBufMap = 0; 8747 } 8748 } 8749} 8750 8751void IOPMrootDomain::sleepWakeDebugMemAlloc( ) 8752{ 8753 vm_size_t size = SWD_BUF_SIZE; 8754 8755 swd_hdr *hdr = NULL; 8756 8757 IOBufferMemoryDescriptor *memDesc = NULL; 8758 8759 8760 if ( kIOSleepWakeWdogOff & gIOKitDebug ) 8761 return; 8762 8763 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock)) 8764 return; 8765 8766 // Try allocating above 4GB. If that fails, try at 2GB 8767 memDesc = IOBufferMemoryDescriptor::inTaskWithPhysicalMask( 8768 kernel_task, kIOMemoryPhysicallyContiguous|kIOMemoryMapperNone, 8769 size, 0xFFFFFFFF00000000ULL); 8770 if (!memDesc) { 8771 memDesc = IOBufferMemoryDescriptor::inTaskWithPhysicalMask( 8772 kernel_task, kIOMemoryPhysicallyContiguous|kIOMemoryMapperNone, 8773 size, 0xFFFFFFFF10000000ULL); 8774 } 8775 8776 if (memDesc == NULL) 8777 { 8778 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n"); 8779 goto exit; 8780 } 8781 8782 8783 hdr = (swd_hdr *)memDesc->getBytesNoCopy(); 8784 memset(hdr, 0, sizeof(swd_hdr)); 8785 8786 hdr->signature = SWD_HDR_SIGNATURE; 8787 hdr->alloc_size = size; 8788 8789 hdr->spindump_offset = sizeof(swd_hdr); 8790 swd_buffer = (void *)hdr; 8791 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr->alloc_size, hdr->spindump_offset); 8792 8793exit: 8794 gRootDomain->swd_lock = 0; 8795} 8796 8797void IOPMrootDomain::sleepWakeDebugEnableWdog() 8798{ 8799 swd_flags |= SWD_WDOG_ENABLED; 8800 if (!swd_buffer) 8801 sleepWakeDebugMemAlloc(); 8802} 8803 8804bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled() 8805{ 8806 return ((swd_flags & SWD_WDOG_ENABLED) && 8807 !systemBooting && !systemShutdown); 8808} 8809 8810errno_t IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int len) 8811{ 8812 struct vnode *vp = NULL; 8813 vfs_context_t ctx = vfs_context_create(vfs_context_current()); 8814 kauth_cred_t cred = vfs_context_ucred(ctx); 8815 struct vnode_attr va; 8816 errno_t error = EIO; 8817 8818 if (vnode_open(name, (O_CREAT | FWRITE | O_NOFOLLOW), 8819 S_IRUSR|S_IRGRP|S_IROTH, VNODE_LOOKUP_NOFOLLOW, &vp, ctx) != 0) 8820 { 8821 IOLog("Failed to open the file %s\n", name); 8822 goto exit; 8823 } 8824 VATTR_INIT(&va); 8825 VATTR_WANTED(&va, va_nlink); 8826 /* Don't dump to non-regular files or files with links. */ 8827 if (vp->v_type != VREG || 8828 vnode_getattr(vp, &va, ctx) || va.va_nlink != 1) { 8829 IOLog("Bailing as this is not a regular file\n"); 8830 goto exit; 8831 } 8832 VATTR_INIT(&va); 8833 VATTR_SET(&va, va_data_size, 0); 8834 vnode_setattr(vp, &va, ctx); 8835 8836 8837 error = vn_rdwr(UIO_WRITE, vp, buf, len, 0, 8838 UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *) 0, vfs_context_proc(ctx)); 8839 if (error != 0) 8840 IOLog("Failed to save sleep wake log. err 0x%x\n", error); 8841 else 8842 DLOG("Saved %d bytes to file %s\n",len, name); 8843 8844exit: 8845 if (vp) vnode_close(vp, FWRITE, ctx); 8846 if (ctx) vfs_context_rele(ctx); 8847 8848 return error; 8849 8850} 8851 8852errno_t IOPMrootDomain::sleepWakeDebugCopyFile( 8853 struct vnode *srcVp, 8854 vfs_context_t srcCtx, 8855 char *tmpBuf, uint64_t tmpBufSize, 8856 uint64_t srcOffset, 8857 const char *dstFname, 8858 uint64_t numBytes, 8859 uint32_t crc) 8860{ 8861 struct vnode *vp = NULL; 8862 vfs_context_t ctx = vfs_context_create(vfs_context_current()); 8863 struct vnode_attr va; 8864 errno_t error = EIO; 8865 uint64_t bytesToRead, bytesToWrite; 8866 uint64_t readFileOffset, writeFileOffset, srcDataOffset; 8867 uint32_t newcrc = 0; 8868 8869 if (vnode_open(dstFname, (O_CREAT | FWRITE | O_NOFOLLOW), 8870 S_IRUSR|S_IRGRP|S_IROTH, VNODE_LOOKUP_NOFOLLOW, &vp, ctx) != 0) 8871 { 8872 DLOG("Failed to open the file %s\n", dstFname); 8873 goto exit; 8874 } 8875 VATTR_INIT(&va); 8876 VATTR_WANTED(&va, va_nlink); 8877 /* Don't dump to non-regular files or files with links. */ 8878 if (vp->v_type != VREG || 8879 vnode_getattr(vp, &va, ctx) || va.va_nlink != 1) { 8880 DLOG("Bailing as this is not a regular file\n"); 8881 goto exit; 8882 } 8883 VATTR_INIT(&va); 8884 VATTR_SET(&va, va_data_size, 0); 8885 vnode_setattr(vp, &va, ctx); 8886 8887 writeFileOffset = 0; 8888 while(numBytes) { 8889 bytesToRead = (round_page(numBytes) > tmpBufSize) ? tmpBufSize : round_page(numBytes); 8890 readFileOffset = trunc_page(srcOffset); 8891 8892 DLOG("Read file (numBytes:0x%llx)\n", bytesToRead); 8893 error = vn_rdwr(UIO_READ, srcVp, tmpBuf, bytesToRead, readFileOffset, 8894 UIO_SYSSPACE, IO_SKIP_ENCRYPTION|IO_SYNC|IO_NODELOCKED|IO_UNIT|IO_NOCACHE, 8895 vfs_context_ucred(srcCtx), (int *) 0, 8896 vfs_context_proc(srcCtx)); 8897 if (error) { 8898 DLOG("Failed to read file(numBytes:0x%llx)\n", bytesToRead); 8899 break; 8900 } 8901 8902 srcDataOffset = (uint64_t)tmpBuf + (srcOffset - readFileOffset); 8903 bytesToWrite = bytesToRead - (srcOffset - readFileOffset); 8904 if (bytesToWrite > numBytes) bytesToWrite = numBytes; 8905 8906 if (crc) { 8907 newcrc = crc32(newcrc, (void *)srcDataOffset, bytesToWrite); 8908 } 8909 error = vn_rdwr(UIO_WRITE, vp, (char *)srcDataOffset, bytesToWrite, writeFileOffset, 8910 UIO_SYSSPACE, IO_SYNC|IO_NODELOCKED|IO_UNIT, 8911 vfs_context_ucred(ctx), (int *) 0, 8912 vfs_context_proc(ctx)); 8913 if (error) { 8914 DLOG("Failed to write file(numBytes:0x%llx)\n", bytesToWrite); 8915 break; 8916 } 8917 8918 writeFileOffset += bytesToWrite; 8919 numBytes -= bytesToWrite; 8920 srcOffset += bytesToWrite; 8921 8922 } 8923 if (crc != newcrc) { 8924 swd_stackshot_hdr *shdr = (swd_stackshot_hdr *)tmpBuf;; 8925 8926 /* Set statckshot size to 0 if crc doesn't match */ 8927 shdr->magic = SWD_STACKSHOTHDR_MAGIC; 8928 shdr->size = 0; 8929 8930 assert(tmpBufSize > sizeof(swd_stackshot_hdr)); 8931 bytesToWrite = round_page(sizeof(swd_stackshot_hdr)); 8932 vn_rdwr(UIO_WRITE, vp, (char *)tmpBuf, bytesToWrite, 0, 8933 UIO_SYSSPACE, IO_SYNC|IO_NODELOCKED|IO_UNIT, 8934 vfs_context_ucred(ctx), (int *) 0, 8935 vfs_context_proc(ctx)); 8936 8937 DLOG("CRC check failed. expected:0x%x actual:0x%x\n", crc, newcrc); 8938 error = EFAULT; 8939 } 8940exit: 8941 if (vp) { 8942 error = vnode_close(vp, FWRITE, ctx); 8943 DLOG("vnode_close returned 0x%x\n", error); 8944 } 8945 if (ctx) vfs_context_rele(ctx); 8946 8947 return error; 8948 8949 8950 8951} 8952 8953void IOPMrootDomain::sleepWakeDebugDumpFromFile( ) 8954{ 8955 8956 int rc; 8957 char hibernateFilename[MAXPATHLEN+1]; 8958 char PMStatusCode[100]; 8959 void *tmpBuf; 8960 swd_hdr *hdr = NULL; 8961 uint32_t stacksSize, logSize; 8962 uint64_t tmpBufSize; 8963 uint64_t hdrOffset, stacksOffset, logOffset; 8964 errno_t error = EIO; 8965 OSObject *obj = NULL; 8966 OSString *str = NULL; 8967 OSNumber *failStat = NULL; 8968 struct vnode *vp = NULL; 8969 vfs_context_t ctx = NULL; 8970 8971 struct vnode_attr va; 8972 IOBufferMemoryDescriptor *tmpBufDesc = NULL; 8973 IOHibernateImageHeader *imageHdr; 8974 8975 DLOG("sleepWakeDebugDumpFromFile\n"); 8976 if ((swd_flags & SWD_LOGS_IN_FILE) == 0) 8977 return; 8978 8979 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock)) 8980 return; 8981 8982 8983 hibernateFilename[0] = 0; 8984 if ((obj = copyProperty(kIOHibernateFileKey))) 8985 { 8986 if ((str = OSDynamicCast(OSString, obj))) 8987 strlcpy(hibernateFilename, str->getCStringNoCopy(), 8988 sizeof(hibernateFilename)); 8989 obj->release(); 8990 } 8991 if (!hibernateFilename[0]) { 8992 DMSG("sleepWakeDebugDumpFromFile: Failed to hib file name\n"); 8993 goto exit; 8994 } 8995 DLOG("sleepWakeDebugDumpFromFile: Hib file name %s\n", hibernateFilename); 8996 8997 /* Allocate a temp buffer to copy data between files */ 8998 tmpBufSize = 2*4096; 8999 tmpBufDesc = IOBufferMemoryDescriptor:: 9000 inTaskWithOptions(kernel_task, kIODirectionOutIn | kIOMemoryMapperNone, 9001 tmpBufSize, PAGE_SIZE); 9002 9003 if (!tmpBufDesc) { 9004 DMSG("sleepWakeDebugDumpFromFile: Fail to allocate temp buf\n"); 9005 goto exit; 9006 } 9007 9008 tmpBuf = tmpBufDesc->getBytesNoCopy(); 9009 9010 ctx = vfs_context_create(vfs_context_current()); 9011 if (vnode_open(hibernateFilename, (FREAD | O_NOFOLLOW), 0, 9012 VNODE_LOOKUP_NOFOLLOW, &vp, ctx) != 0) 9013 { 9014 DMSG("sleepWakeDebugDumpFromFile: Failed to open the hibernate file %s\n", hibernateFilename); 9015 goto exit; 9016 } 9017 VATTR_INIT(&va); 9018 VATTR_WANTED(&va, va_nlink); 9019 VATTR_WANTED(&va, va_data_alloc); 9020 if (vp->v_type != VREG || 9021 vnode_getattr(vp, &va, ctx) || va.va_nlink != 1) { 9022 DMSG("sleepWakeDebugDumpFromFile: Bailing as this is not a regular file\n"); 9023 goto exit; 9024 } 9025 9026 /* Read the sleepimage file header */ 9027 rc = vn_rdwr(UIO_READ, vp, (char *)tmpBuf, round_page(sizeof(IOHibernateImageHeader)), 0, 9028 UIO_SYSSPACE, IO_SKIP_ENCRYPTION|IO_SYNC|IO_NODELOCKED|IO_UNIT|IO_NOCACHE, 9029 vfs_context_ucred(ctx), (int *) 0, 9030 vfs_context_proc(ctx)); 9031 if (rc != 0) { 9032 DMSG("sleepWakeDebugDumpFromFile: Failed to read header size %lu(rc=%d)\n", round_page(sizeof(IOHibernateImageHeader)), rc); 9033 goto exit; 9034 } 9035 9036 imageHdr = ((IOHibernateImageHeader *)tmpBuf); 9037 if (imageHdr->signature != kIOHibernateHeaderDebugDataSignature) { 9038 DMSG("sleepWakeDebugDumpFromFile: File header has unexpected value 0x%x\n", imageHdr->signature); 9039 goto exit; 9040 } 9041 9042 /* Sleep/Wake debug header(swd_hdr) is at the beggining of the second block */ 9043 hdrOffset = imageHdr->deviceBlockSize; 9044 if (hdrOffset + sizeof(swd_hdr) >= va.va_data_alloc) { 9045 DMSG("sleepWakeDebugDumpFromFile: header is crossing file size(0x%llx)\n", va.va_data_alloc); 9046 goto exit; 9047 } 9048 9049 DLOG("Reading swd_hdr len 0x%lx offset 0x%lx\n", round_page(sizeof(swd_hdr)), trunc_page(hdrOffset)); 9050 /* Read the sleep/wake debug header(swd_hdr) */ 9051 rc = vn_rdwr(UIO_READ, vp, (char *)tmpBuf, round_page(sizeof(swd_hdr)), trunc_page(hdrOffset), 9052 UIO_SYSSPACE, IO_SKIP_ENCRYPTION|IO_SYNC|IO_NODELOCKED|IO_UNIT|IO_NOCACHE, 9053 vfs_context_ucred(ctx), (int *) 0, 9054 vfs_context_proc(ctx)); 9055 if (rc != 0) { 9056 DMSG("sleepWakeDebugDumpFromFile: Failed to debug read header size %lu. rc=%d\n", 9057 round_page(sizeof(swd_hdr)), rc); 9058 goto exit; 9059 } 9060 9061 hdr = (swd_hdr *)((char *)tmpBuf + (hdrOffset - trunc_page(hdrOffset))); 9062 if ((hdr->signature != SWD_HDR_SIGNATURE) || (hdr->alloc_size > SWD_BUF_SIZE) || 9063 (hdr->spindump_offset > SWD_BUF_SIZE) || (hdr->spindump_size > SWD_BUF_SIZE)) { 9064 DMSG("sleepWakeDebugDumpFromFile: Invalid data in debug header. sign:0x%x size:0x%x spindump_offset:0x%x spindump_size:0x%x\n", 9065 hdr->signature, hdr->alloc_size, hdr->spindump_offset, hdr->spindump_size); 9066 goto exit; 9067 } 9068 stacksSize = hdr->spindump_size; 9069 9070 /* Get stacks & log offsets in the image file */ 9071 stacksOffset = hdrOffset + hdr->spindump_offset; 9072 logOffset = hdrOffset + offsetof(swd_hdr, UUID); 9073 logSize = sizeof(swd_hdr)-offsetof(swd_hdr, UUID); 9074 9075 error = sleepWakeDebugCopyFile(vp, ctx, (char *)tmpBuf, tmpBufSize, stacksOffset, 9076 getDumpStackFilename(hdr), stacksSize, hdr->crc); 9077 if (error == EFAULT) { 9078 DMSG("sleepWakeDebugDumpFromFile: Stackshot CRC doesn't match\n"); 9079 goto exit; 9080 } 9081 error = sleepWakeDebugCopyFile(vp, ctx, (char *)tmpBuf, tmpBufSize, logOffset, 9082 getDumpLogFilename(hdr), logSize, 0); 9083 if (error) { 9084 DMSG("sleepWakeDebugDumpFromFile: Failed to write the log file(0x%x)\n", error); 9085 goto exit; 9086 } 9087exit: 9088 if (error) { 9089 // Write just the SleepWakeLog.dump with failure code 9090 uint64_t fcode = 0; 9091 const char *fname; 9092 if (swd_flags & SWD_BOOT_BY_SW_WDOG) { 9093 failStat = OSDynamicCast(OSNumber, getProperty(kIOPMSleepWakeFailureCodeKey)); 9094 fcode = failStat->unsigned64BitValue(); 9095 fname = kSleepWakeLogFilename; 9096 } 9097 else { 9098 fname = kAppleOSXWatchdogLogFilename; 9099 } 9100 memset(PMStatusCode, 0x20, sizeof(PMStatusCode)); // Fill with spaces 9101 PMStatusCode[sizeof(PMStatusCode)-1] = 0xa; // And an end-of-line at the end 9102 snprintf(PMStatusCode, sizeof(PMStatusCode)-1, "Code: 0x%llx", fcode); 9103 sleepWakeDebugSaveFile(fname, PMStatusCode, sizeof(PMStatusCode)); 9104 } 9105 gRootDomain->swd_lock = 0; 9106 9107 if (vp) vnode_close(vp, FREAD, ctx); 9108 if (ctx) vfs_context_rele(ctx); 9109 if (tmpBufDesc) tmpBufDesc->release(); 9110 9111} 9112 9113void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap *logBufMap) 9114{ 9115 IOVirtualAddress srcBuf = NULL; 9116 char *stackBuf = NULL, *logOffset = NULL; 9117 int logSize = 0; 9118 9119 errno_t error = EIO; 9120 uint64_t bufSize = 0; 9121 swd_hdr *hdr = NULL; 9122 char PMStatusCode[100]; 9123 OSNumber *failStat = NULL; 9124 9125 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock)) 9126 return; 9127 9128 if ((logBufMap == 0) || ( (srcBuf = logBufMap->getVirtualAddress()) == 0) ) 9129 { 9130 DLOG("Nothing saved to dump to file\n"); 9131 goto exit; 9132 } 9133 9134 hdr = (swd_hdr *)srcBuf; 9135 bufSize = logBufMap->getLength(); 9136 if (bufSize <= sizeof(swd_hdr)) 9137 { 9138 IOLog("SleepWake log buffer contents are invalid\n"); 9139 goto exit; 9140 } 9141 9142 stackBuf = (char*)hdr+hdr->spindump_offset; 9143 9144 error = sleepWakeDebugSaveFile(getDumpStackFilename(hdr), stackBuf, hdr->spindump_size); 9145 if (error) goto exit; 9146 9147 logOffset = (char*)hdr+offsetof(swd_hdr, UUID); 9148 logSize = sizeof(swd_hdr)-offsetof(swd_hdr, UUID); 9149 9150 error = sleepWakeDebugSaveFile(getDumpLogFilename(hdr), logOffset, logSize); 9151 if (error) goto exit; 9152 9153 hdr->spindump_size = 0; 9154 error = 0; 9155 9156exit: 9157 if (error) { 9158 // Write just the SleepWakeLog.dump with failure code 9159 uint64_t fcode = 0; 9160 const char *sname, *lname; 9161 swd_stackshot_hdr shdr; 9162 9163 /* Try writing an empty stacks file */ 9164 shdr.magic = SWD_STACKSHOTHDR_MAGIC; 9165 shdr.size = 0; 9166 9167 9168 if (swd_flags & SWD_BOOT_BY_SW_WDOG) { 9169 failStat = OSDynamicCast(OSNumber, getProperty(kIOPMSleepWakeFailureCodeKey)); 9170 fcode = failStat->unsigned64BitValue(); 9171 lname = kSleepWakeLogFilename; 9172 sname = kSleepWakeStackFilename; 9173 } 9174 else { 9175 lname = kAppleOSXWatchdogLogFilename; 9176 sname= kAppleOSXWatchdogStackFilename; 9177 } 9178 9179 sleepWakeDebugSaveFile(sname, (char*)(&shdr), sizeof(shdr)); 9180 memset(PMStatusCode, 0x20, sizeof(PMStatusCode)); // Fill with spaces 9181 PMStatusCode[sizeof(PMStatusCode)-1] = 0xa; // And an end-of-line at the end 9182 snprintf(PMStatusCode, sizeof(PMStatusCode)-1, "Code: 0x%llx", fcode); 9183 sleepWakeDebugSaveFile(lname, PMStatusCode, sizeof(PMStatusCode)); 9184 } 9185 gRootDomain->swd_lock = 0; 9186} 9187 9188IOMemoryMap *IOPMrootDomain::sleepWakeDebugRetrieve( ) 9189{ 9190 IOVirtualAddress vaddr = NULL; 9191 IOMemoryDescriptor * desc = NULL; 9192 IOMemoryMap * logBufMap = NULL; 9193 9194 uint32_t len; 9195 addr64_t data[3]; 9196 uint64_t bufSize = 0; 9197 uint64_t crc = 0; 9198 uint64_t newcrc = 0; 9199 uint64_t paddr = 0; 9200 swd_hdr *hdr = NULL; 9201 bool ret = false; 9202 char str[20]; 9203 9204 9205 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock)) 9206 return NULL; 9207 9208 if (!PEReadNVRAMProperty(kIOSleepWakeDebugKey, 0, &len)) { 9209 DLOG("No sleepWakeDebug note to read\n"); 9210 goto exit; 9211 } 9212 9213 if (len == strlen("sleepimage")) { 9214 str[0] = 0; 9215 PEReadNVRAMProperty(kIOSleepWakeDebugKey, str, &len); 9216 9217 if (!strncmp((char*)str, "sleepimage", strlen("sleepimage"))) { 9218 DLOG("sleepWakeDebugRetrieve: in file logs\n"); 9219 swd_flags |= SWD_LOGS_IN_FILE|SWD_VALID_LOGS; 9220 goto exit; 9221 } 9222 } 9223 else if (len == sizeof(addr64_t)*3) 9224 PEReadNVRAMProperty(kIOSleepWakeDebugKey, data, &len); 9225 else { 9226 DLOG("Invalid sleepWakeDebug note length(%d)\n", len); 9227 goto exit; 9228 } 9229 9230 9231 9232 DLOG("sleepWakeDebugRetrieve: data[0]:0x%llx data[1]:0x%llx data[2]:0x%llx\n", 9233 data[0], data[1], data[2]); 9234 DLOG("sleepWakeDebugRetrieve: in mem logs\n"); 9235 bufSize = data[0]; 9236 crc = data[1]; 9237 paddr = data[2]; 9238 if ( (bufSize <= sizeof(swd_hdr)) ||(bufSize > SWD_BUF_SIZE) || (crc == 0) ) 9239 { 9240 IOLog("SleepWake log buffer contents are invalid\n"); 9241 return NULL; 9242 } 9243 9244 DLOG("size:0x%llx crc:0x%llx paddr:0x%llx\n", 9245 bufSize, crc, paddr); 9246 9247 9248 desc = IOMemoryDescriptor::withAddressRange( paddr, bufSize, 9249 kIODirectionOutIn | kIOMemoryMapperNone, NULL); 9250 if (desc == NULL) 9251 { 9252 IOLog("Fail to map SleepWake log buffer\n"); 9253 goto exit; 9254 } 9255 9256 logBufMap = desc->map(); 9257 9258 vaddr = logBufMap->getVirtualAddress(); 9259 9260 9261 if ( (logBufMap->getLength() <= sizeof(swd_hdr)) || (vaddr == NULL) ) { 9262 IOLog("Fail to map SleepWake log buffer\n"); 9263 goto exit; 9264 } 9265 9266 hdr = (swd_hdr *)vaddr; 9267 if (hdr->spindump_offset+hdr->spindump_size > bufSize) 9268 { 9269 IOLog("SleepWake log buffer contents are invalid\n"); 9270 goto exit; 9271 } 9272 9273 hdr->crc = crc; 9274 newcrc = crc32(0, (void *)((char*)vaddr+hdr->spindump_offset), 9275 hdr->spindump_size); 9276 if (newcrc != crc) { 9277 IOLog("SleepWake log buffer contents are invalid\n"); 9278 goto exit; 9279 } 9280 9281 ret = true; 9282 swd_flags |= SWD_LOGS_IN_MEM | SWD_VALID_LOGS; 9283 9284 9285exit: 9286 PERemoveNVRAMProperty(kIOSleepWakeDebugKey); 9287 if (!ret) { 9288 if (logBufMap) logBufMap->release(); 9289 logBufMap = 0; 9290 } 9291 if (desc) desc->release(); 9292 gRootDomain->swd_lock = 0; 9293 9294 return logBufMap; 9295} 9296 9297#else 9298 9299void IOPMrootDomain::sleepWakeDebugTrig(bool restart) 9300{ 9301} 9302 9303void IOPMrootDomain::takeStackshot(bool restart, bool isOSXWatchdog) 9304{ 9305#pragma unused(restart) 9306#pragma unused(isOSXWatchdog) 9307} 9308 9309void IOPMrootDomain::sleepWakeDebugMemAlloc( ) 9310{ 9311} 9312void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap *map) 9313{ 9314} 9315errno_t IOPMrootDomain::sleepWakeDebugCopyFile( 9316 struct vnode *srcVp, 9317 vfs_context_t srcCtx, 9318 char *tmpBuf, uint64_t tmpBufSize, 9319 uint64_t srcOffset, 9320 const char *dstFname, 9321 uint64_t numBytes, 9322 uint32_t crc) 9323{ 9324 return EIO; 9325} 9326 9327void IOPMrootDomain::sleepWakeDebugDumpFromFile() 9328{ 9329} 9330 9331IOMemoryMap *IOPMrootDomain::sleepWakeDebugRetrieve( ) 9332{ 9333 return NULL; 9334} 9335 9336void IOPMrootDomain::sleepWakeDebugEnableWdog() 9337{ 9338} 9339 9340bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled() 9341{ 9342 return false; 9343} 9344 9345errno_t IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int len) 9346{ 9347 return 0; 9348} 9349 9350#endif 9351 9352