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