2 * Copyright (c) 1998-2008 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 #include <libkern/c++/OSKext.h>
29 #include <libkern/c++/OSMetaClass.h>
30 #include <libkern/OSAtomic.h>
31 #include <libkern/OSDebug.h>
32 #include <IOKit/IOWorkLoop.h>
33 #include <IOKit/IOCommandGate.h>
34 #include <IOKit/IOPlatformExpert.h>
35 #include <IOKit/IOCPU.h>
36 #include <IOKit/IOKitDebug.h>
37 #include <IOKit/IOTimeStamp.h>
38 #include <IOKit/pwr_mgt/IOPMlog.h>
39 #include <IOKit/pwr_mgt/RootDomain.h>
40 #include <IOKit/pwr_mgt/IOPMPrivate.h>
41 #include <IOKit/IODeviceTreeSupport.h>
42 #include <IOKit/IOMessage.h>
43 #include <IOKit/IOReturn.h>
44 #include <IOKit/IONVRAM.h>
45 #include "RootDomainUserClient.h"
46 #include "IOKit/pwr_mgt/IOPowerConnection.h"
47 #include "IOPMPowerStateQueue.h"
48 #include <IOKit/IOCatalogue.h>
49 #include <IOKit/IOReportMacros.h>
50 #include "IOKitKernelInternal.h"
52 #include <IOKit/IOHibernatePrivate.h>
54 #include <console/video_console.h>
55 #include <sys/syslog.h>
56 #include <sys/sysctl.h>
57 #include <sys/vnode.h>
58 #include <sys/vnode_internal.h>
59 #include <sys/fcntl.h>
62 #include "IOServicePrivate.h" // _IOServiceInterestNotifier
63 #include "IOServicePMPrivate.h"
66 #include <mach/shared_region.h>
67 #include <kern/clock.h>
70 #if defined(__i386__) || defined(__x86_64__)
72 #include "IOPMrootDomainInternal.h"
76 #define kIOPMrootDomainClass "IOPMrootDomain"
77 #define LOG_PREFIX "PMRD: "
81 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
84 do { kprintf(LOG_PREFIX x); } while (false)
86 #define DLOG(x...) do { \
87 if (kIOLogPMRootDomain & gIOKitDebug) \
88 kprintf(LOG_PREFIX x); \
91 #define DMSG(x...) do { \
92 if (kIOLogPMRootDomain & gIOKitDebug) { \
93 kprintf(LOG_PREFIX x); IOLog(x); \
100 #define CHECK_THREAD_CONTEXT
101 #ifdef CHECK_THREAD_CONTEXT
102 static IOWorkLoop
* gIOPMWorkLoop
= 0;
103 #define ASSERT_GATED() \
105 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
106 panic("RootDomain: not inside PM gate"); \
110 #define ASSERT_GATED()
111 #endif /* CHECK_THREAD_CONTEXT */
113 #define CAP_LOSS(c) \
114 (((_pendingCapability & (c)) == 0) && \
115 ((_currentCapability & (c)) != 0))
117 #define CAP_GAIN(c) \
118 (((_currentCapability & (c)) == 0) && \
119 ((_pendingCapability & (c)) != 0))
121 #define CAP_CHANGE(c) \
122 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
124 #define CAP_CURRENT(c) \
125 ((_currentCapability & (c)) != 0)
127 #define CAP_HIGHEST(c) \
128 ((_highestCapability & (c)) != 0)
130 #if defined(__i386__) || defined(__x86_64__)
131 #define DARK_TO_FULL_EVALUATE_CLAMSHELL 1
134 // Event types for IOPMPowerStateQueue::submitPowerEvent()
136 kPowerEventFeatureChanged
= 1, // 1
137 kPowerEventReceivedPowerNotification
, // 2
138 kPowerEventSystemBootCompleted
, // 3
139 kPowerEventSystemShutdown
, // 4
140 kPowerEventUserDisabledSleep
, // 5
141 kPowerEventRegisterSystemCapabilityClient
, // 6
142 kPowerEventRegisterKernelCapabilityClient
, // 7
143 kPowerEventPolicyStimulus
, // 8
144 kPowerEventAssertionCreate
, // 9
145 kPowerEventAssertionRelease
, // 10
146 kPowerEventAssertionSetLevel
, // 11
147 kPowerEventQueueSleepWakeUUID
, // 12
148 kPowerEventPublishSleepWakeUUID
, // 13
149 kPowerEventSetDisplayPowerOn
// 14
152 // For evaluatePolicy()
153 // List of stimuli that affects the root domain policy.
155 kStimulusDisplayWranglerSleep
, // 0
156 kStimulusDisplayWranglerWake
, // 1
157 kStimulusAggressivenessChanged
, // 2
158 kStimulusDemandSystemSleep
, // 3
159 kStimulusAllowSystemSleepChanged
, // 4
160 kStimulusDarkWakeActivityTickle
, // 5
161 kStimulusDarkWakeEntry
, // 6
162 kStimulusDarkWakeReentry
, // 7
163 kStimulusDarkWakeEvaluate
, // 8
164 kStimulusNoIdleSleepPreventers
, // 9
165 kStimulusEnterUserActiveState
, // 10
166 kStimulusLeaveUserActiveState
// 11
170 IOReturn
OSKextSystemSleepOrWake( UInt32
);
172 extern "C" ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
);
173 extern "C" addr64_t
kvtophys(vm_offset_t va
);
174 extern "C" int stack_snapshot_from_kernel(pid_t pid
, void *buf
, uint32_t size
, uint32_t flags
, unsigned *bytesTraced
);
176 static void idleSleepTimerExpired( thread_call_param_t
, thread_call_param_t
);
177 static void notifySystemShutdown( IOService
* root
, uint32_t messageType
);
178 static void handleAggressivesFunction( thread_call_param_t
, thread_call_param_t
);
179 static void pmEventTimeStamp(uint64_t *recordTS
);
181 // "IOPMSetSleepSupported" callPlatformFunction name
182 static const OSSymbol
*sleepSupportedPEFunction
= NULL
;
183 static const OSSymbol
*sleepMessagePEFunction
= NULL
;
185 #define kIOSleepSupportedKey "IOSleepSupported"
186 #define kIOPMSystemCapabilitiesKey "System Capabilities"
188 #define kIORequestWranglerIdleKey "IORequestIdle"
189 #define kDefaultWranglerIdlePeriod 25 // in milliseconds
191 #define kIOSleepWakeDebugKey "Persistent-memory-note"
193 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
194 | kIOPMSupportedOnBatt \
195 | kIOPMSupportedOnUPS)
197 #define kLocalEvalClamshellCommand (1 << 15)
198 #define kIdleSleepRetryInterval (3 * 60)
201 kWranglerPowerStateMin
= 0,
202 kWranglerPowerStateSleep
= 2,
203 kWranglerPowerStateDim
= 3,
204 kWranglerPowerStateMax
= 4
215 #define ON_POWER kIOPMPowerOn
216 #define RESTART_POWER kIOPMRestart
217 #define SLEEP_POWER kIOPMAuxPowerOn
219 static IOPMPowerState ourPowerStates
[NUM_POWER_STATES
] =
221 {1, 0, 0, 0, 0,0,0,0,0,0,0,0},
222 {1, kIOPMRestartCapability
, kIOPMRestart
, RESTART_POWER
, 0,0,0,0,0,0,0,0},
223 {1, kIOPMSleepCapability
, kIOPMSleep
, SLEEP_POWER
, 0,0,0,0,0,0,0,0},
224 {1, kIOPMPowerOn
, kIOPMPowerOn
, ON_POWER
, 0,0,0,0,0,0,0,0}
227 #define kIOPMRootDomainWakeTypeSleepService "SleepService"
228 #define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
229 #define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
230 #define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
231 #define kIOPMRootDomainWakeTypeUser "User"
232 #define kIOPMRootDomainWakeTypeAlarm "Alarm"
233 #define kIOPMRootDomainWakeTypeNetwork "Network"
234 #define kIOPMRootDomainWakeTypeHIDActivity "HID Activity"
235 #define kIOPMRootDomainWakeTypeNotification "Notification"
236 #define kIOPMRootDomainWakeTypeHibernateError "HibernateError"
238 // Special interest that entitles the interested client from receiving
239 // all system messages. Only used by powerd.
241 #define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
243 #define WAKEEVENT_LOCK() IOLockLock(wakeEventLock)
244 #define WAKEEVENT_UNLOCK() IOLockUnlock(wakeEventLock)
249 #define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
250 #define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
252 #define kAggressivesMinValue 1
255 kAggressivesStateBusy
= 0x01,
256 kAggressivesStateQuickSpindown
= 0x02
259 struct AggressivesRecord
{
265 struct AggressivesRequest
{
271 AggressivesRecord record
;
276 kAggressivesRequestTypeService
= 1,
277 kAggressivesRequestTypeRecord
281 kAggressivesOptionSynchronous
= 0x00000001,
282 kAggressivesOptionQuickSpindownEnable
= 0x00000100,
283 kAggressivesOptionQuickSpindownDisable
= 0x00000200,
284 kAggressivesOptionQuickSpindownMask
= 0x00000300
288 kAggressivesRecordFlagModified
= 0x00000001,
289 kAggressivesRecordFlagMinValue
= 0x00000002
294 kDarkWakeFlagHIDTickleEarly
= 0x01, // hid tickle before gfx suppression
295 kDarkWakeFlagHIDTickleLate
= 0x02, // hid tickle after gfx suppression
296 kDarkWakeFlagHIDTickleNone
= 0x03, // hid tickle is not posted
297 kDarkWakeFlagHIDTickleMask
= 0x03,
298 kDarkWakeFlagAlarmIsDark
= 0x0100,
299 kDarkWakeFlagGraphicsPowerState1
= 0x0200,
300 kDarkWakeFlagAudioNotSuppressed
= 0x0400
303 static IOPMrootDomain
* gRootDomain
;
304 static IONotifier
* gSysPowerDownNotifier
= 0;
305 static UInt32 gSleepOrShutdownPending
= 0;
306 static UInt32 gWillShutdown
= 0;
307 static UInt32 gPagingOff
= 0;
308 static UInt32 gSleepWakeUUIDIsSet
= false;
309 static uint32_t gAggressivesState
= 0;
311 uuid_string_t bootsessionuuid_string
;
313 static uint32_t gDarkWakeFlags
= kDarkWakeFlagHIDTickleNone
;
314 static uint32_t gNoIdleFlag
= 0;
315 static PMStatsStruct gPMStats
;
318 static IOPMSystemSleepPolicyHandler gSleepPolicyHandler
= 0;
319 static IOPMSystemSleepPolicyVariables
* gSleepPolicyVars
= 0;
320 static void * gSleepPolicyTarget
;
323 struct timeval gIOLastSleepTime
;
324 struct timeval gIOLastWakeTime
;
326 static char gWakeReasonString
[128];
327 static bool gWakeReasonSysctlRegistered
= false;
329 #if defined(__i386__) || defined(__x86_64__)
330 static bool gSpinDumpBufferFull
= false;
333 static unsigned int gPMHaltBusyCount
;
334 static unsigned int gPMHaltIdleCount
;
335 static int gPMHaltDepth
;
336 static uint32_t gPMHaltMessageType
;
337 static IOLock
* gPMHaltLock
= 0;
338 static OSArray
* gPMHaltArray
= 0;
339 static const OSSymbol
* gPMHaltClientAcknowledgeKey
= 0;
340 static bool gPMQuiesced
;
342 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
343 #define kCPUUnknownIndex 9999999
350 const OSSymbol
*gIOPMStatsApplicationResponseTimedOut
;
351 const OSSymbol
*gIOPMStatsApplicationResponseCancel
;
352 const OSSymbol
*gIOPMStatsApplicationResponseSlow
;
353 const OSSymbol
*gIOPMStatsApplicationResponsePrompt
;
354 const OSSymbol
*gIOPMStatsDriverPSChangeSlow
;
356 #define kBadPMFeatureID 0
360 * Opaque handle passed to clients of registerPMSettingController()
362 class PMSettingHandle
: public OSObject
364 OSDeclareFinalStructors( PMSettingHandle
)
365 friend class PMSettingObject
;
368 PMSettingObject
*pmso
;
369 void free(void) APPLE_KEXT_OVERRIDE
;
374 * Internal object to track each PM setting controller
376 class PMSettingObject
: public OSObject
378 OSDeclareFinalStructors( PMSettingObject
)
379 friend class IOPMrootDomain
;
382 queue_head_t calloutQueue
;
384 IOPMrootDomain
*parent
;
385 PMSettingHandle
*pmsh
;
386 IOPMSettingControllerCallback func
;
389 uint32_t *publishedFeatureID
;
390 uint32_t settingCount
;
393 void free(void) APPLE_KEXT_OVERRIDE
;
396 static PMSettingObject
*pmSettingObject(
397 IOPMrootDomain
*parent_arg
,
398 IOPMSettingControllerCallback handler_arg
,
399 OSObject
*target_arg
,
400 uintptr_t refcon_arg
,
401 uint32_t supportedPowerSources
,
402 const OSSymbol
*settings
[],
403 OSObject
**handle_obj
);
405 void dispatchPMSetting(const OSSymbol
*type
, OSObject
*object
);
406 void clientHandleFreed(void);
409 struct PMSettingCallEntry
{
414 #define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
415 #define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
416 #define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
417 #define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
421 * Internal helper object for logging trace points to RTC
422 * IOPMrootDomain and only IOPMrootDomain should instantiate
423 * exactly one of these.
426 typedef void (*IOPMTracePointHandler
)(
427 void * target
, uint32_t code
, uint32_t data
);
429 class PMTraceWorker
: public OSObject
431 OSDeclareDefaultStructors(PMTraceWorker
)
433 typedef enum { kPowerChangeStart
, kPowerChangeCompleted
} change_t
;
435 static PMTraceWorker
*tracer( IOPMrootDomain
* );
436 void tracePCIPowerChange(change_t
, IOService
*, uint32_t, uint32_t);
437 void tracePoint(uint8_t phase
);
438 void tracePoint(uint8_t phase
, uint8_t data8
);
439 void traceDetail(uint32_t detail
);
440 void traceLoginWindowPhase(uint8_t phase
);
441 int recordTopLevelPCIDevice(IOService
*);
442 void RTC_TRACE(void);
443 virtual bool serialize(OSSerialize
*s
) const APPLE_KEXT_OVERRIDE
;
445 IOPMTracePointHandler tracePointHandler
;
446 void * tracePointTarget
;
447 uint64_t getPMStatusCode();
449 IOPMrootDomain
*owner
;
450 IOLock
*pciMappingLock
;
451 OSArray
*pciDeviceBitMappings
;
453 uint8_t addedToRegistry
;
455 uint8_t loginWindowPhase
;
457 uint32_t traceData32
;
461 * PMAssertionsTracker
462 * Tracks kernel and user space PM assertions
464 class PMAssertionsTracker
: public OSObject
466 OSDeclareFinalStructors(PMAssertionsTracker
)
468 static PMAssertionsTracker
*pmAssertionsTracker( IOPMrootDomain
* );
470 IOReturn
createAssertion(IOPMDriverAssertionType
, IOPMDriverAssertionLevel
, IOService
*, const char *, IOPMDriverAssertionID
*);
471 IOReturn
releaseAssertion(IOPMDriverAssertionID
);
472 IOReturn
setAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
473 IOReturn
setUserAssertionLevels(IOPMDriverAssertionType
);
475 OSArray
*copyAssertionsArray(void);
476 IOPMDriverAssertionType
getActivatedAssertions(void);
477 IOPMDriverAssertionLevel
getAssertionLevel(IOPMDriverAssertionType
);
479 IOReturn
handleCreateAssertion(OSData
*);
480 IOReturn
handleReleaseAssertion(IOPMDriverAssertionID
);
481 IOReturn
handleSetAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
482 IOReturn
handleSetUserAssertionLevels(void * arg0
);
483 void publishProperties(void);
487 IOPMDriverAssertionID id
;
488 IOPMDriverAssertionType assertionBits
;
489 uint64_t createdTime
;
490 uint64_t modifiedTime
;
491 const OSSymbol
*ownerString
;
492 IOService
*ownerService
;
493 uint64_t registryEntryID
;
494 IOPMDriverAssertionLevel level
;
497 uint32_t tabulateProducerCount
;
498 uint32_t tabulateConsumerCount
;
500 PMAssertStruct
*detailsForID(IOPMDriverAssertionID
, int *);
503 IOPMrootDomain
*owner
;
504 OSArray
*assertionsArray
;
505 IOLock
*assertionsArrayLock
;
506 IOPMDriverAssertionID issuingUniqueID
__attribute__((aligned(8))); /* aligned for atomic access */
507 IOPMDriverAssertionType assertionsKernel
;
508 IOPMDriverAssertionType assertionsUser
;
509 IOPMDriverAssertionType assertionsCombined
;
512 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker
, OSObject
);
516 * Internal helper object for Shutdown/Restart notifications.
518 #define kPMHaltMaxWorkers 8
519 #define kPMHaltTimeoutMS 100
521 class PMHaltWorker
: public OSObject
523 OSDeclareFinalStructors( PMHaltWorker
)
526 IOService
* service
; // service being worked on
527 AbsoluteTime startTime
; // time when work started
528 int depth
; // work on nubs at this PM-tree depth
529 int visits
; // number of nodes visited (debug)
531 bool timeout
; // service took too long
533 static PMHaltWorker
* worker( void );
534 static void main( void * arg
, wait_result_t waitResult
);
535 static void work( PMHaltWorker
* me
);
536 static void checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
);
537 virtual void free( void ) APPLE_KEXT_OVERRIDE
;
540 OSDefineMetaClassAndFinalStructors( PMHaltWorker
, OSObject
)
543 #define super IOService
544 OSDefineMetaClassAndFinalStructors(IOPMrootDomain
, IOService
)
546 static void IOPMRootDomainWillShutdown(void)
548 if (OSCompareAndSwap(0, 1, &gWillShutdown
))
550 OSKext::willShutdown();
551 for (int i
= 0; i
< 100; i
++)
553 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending
)) break;
561 IONotifier
* registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
563 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
);
566 IONotifier
* registerPrioritySleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
568 return gRootDomain
->registerInterest( gIOPriorityPowerStateInterest
, handler
, self
, ref
);
571 IOReturn
acknowledgeSleepWakeNotification(void * PMrefcon
)
573 return gRootDomain
->allowPowerChange ( (unsigned long)PMrefcon
);
576 IOReturn
vetoSleepWakeNotification(void * PMrefcon
)
578 return gRootDomain
->cancelPowerChange ( (unsigned long)PMrefcon
);
581 IOReturn
rootDomainRestart ( void )
583 return gRootDomain
->restartSystem();
586 IOReturn
rootDomainShutdown ( void )
588 return gRootDomain
->shutdownSystem();
591 void IOSystemShutdownNotification(void)
593 IOPMRootDomainWillShutdown();
595 IOHibernateSystemPostWake();
597 if (OSCompareAndSwap(0, 1, &gPagingOff
))
599 gRootDomain
->handlePlatformHaltRestart(kPEPagingOff
);
603 int sync_internal(void);
607 A device is always in the highest power state which satisfies its driver,
608 its policy-maker, and any power children it has, but within the constraint
609 of the power state provided by its parent. The driver expresses its desire by
610 calling changePowerStateTo(), the policy-maker expresses its desire by calling
611 changePowerStateToPriv(), and the children express their desires by calling
612 requestPowerDomainState().
614 The Root Power Domain owns the policy for idle and demand sleep for the system.
615 It is a power-managed IOService just like the others in the system.
616 It implements several power states which map to what we see as Sleep and On.
618 The sleep policy is as follows:
619 1. Sleep is prevented if the case is open so that nobody will think the machine
620 is off and plug/unplug cards.
621 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
622 3. System cannot Sleep if some object in the tree is in a power state marked
623 kIOPMPreventSystemSleep.
625 These three conditions are enforced using the "driver clamp" by calling
626 changePowerStateTo(). For example, if the case is opened,
627 changePowerStateTo(ON_STATE) is called to hold the system on regardless
628 of the desires of the children of the root or the state of the other clamp.
630 Demand Sleep is initiated by pressing the front panel power button, closing
631 the clamshell, or selecting the menu item. In this case the root's parent
632 actually initiates the power state change so that the root domain has no
633 choice and does not give applications the opportunity to veto the change.
635 Idle Sleep occurs if no objects in the tree are in a state marked
636 kIOPMPreventIdleSleep. When this is true, the root's children are not holding
637 the root on, so it sets the "policy-maker clamp" by calling
638 changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
639 This timer is set for the difference between the sleep timeout slider and the
640 display dim timeout slider. When the timer expires, it releases its clamp and
641 now nothing is holding it awake, so it falls asleep.
643 Demand sleep is prevented when the system is booting. When preferences are
644 transmitted by the loginwindow at the end of boot, a flag is cleared,
645 and this allows subsequent Demand Sleep.
648 //******************************************************************************
650 IOPMrootDomain
* IOPMrootDomain::construct( void )
652 IOPMrootDomain
*root
;
654 root
= new IOPMrootDomain
;
661 //******************************************************************************
662 // updateConsoleUsersCallout
664 //******************************************************************************
666 static void updateConsoleUsersCallout(thread_call_param_t p0
, thread_call_param_t p1
)
668 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
669 rootDomain
->updateConsoleUsers();
672 void IOPMrootDomain::updateConsoleUsers(void)
674 IOService::updateConsoleUsers(NULL
, kIOMessageSystemHasPoweredOn
);
677 tasksSuspended
= FALSE
;
678 tasks_system_suspend(tasksSuspended
);
682 //******************************************************************************
684 static void disk_sync_callout( thread_call_param_t p0
, thread_call_param_t p1
)
686 IOService
* rootDomain
= (IOService
*) p0
;
687 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
688 uint32_t powerState
= rootDomain
->getPowerState();
690 DLOG("disk_sync_callout ps=%u\n", powerState
);
692 if (ON_STATE
== powerState
)
699 IOHibernateSystemPostWake();
702 gRootDomain
->sleepWakeDebugSaveSpinDumpFile();
706 rootDomain
->allowPowerChange(notifyRef
);
707 DLOG("disk_sync_callout finish\n");
710 //******************************************************************************
712 static void hib_debugSetup_callout( thread_call_param_t p0
, thread_call_param_t p1
)
714 IOService
* rootDomain
= (IOService
*) p0
;
715 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
718 IOOpenDebugDataFile(kSleepWakeStackBinFilename
, SWD_BUF_SIZE
);
721 rootDomain
->allowPowerChange(notifyRef
);
722 DLOG("hib_debugSetup_callout finish\n");
724 //******************************************************************************
726 static UInt32
computeDeltaTimeMS( const AbsoluteTime
* startTime
)
728 AbsoluteTime endTime
;
731 clock_get_uptime(&endTime
);
732 if (CMP_ABSOLUTETIME(&endTime
, startTime
) > 0)
734 SUB_ABSOLUTETIME(&endTime
, startTime
);
735 absolutetime_to_nanoseconds(endTime
, &nano
);
738 return (UInt32
)(nano
/ 1000000ULL);
741 //******************************************************************************
744 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
746 struct timeval
*swt
= (struct timeval
*)arg1
;
747 struct proc
*p
= req
->p
;
750 return sysctl_io_opaque(req
, swt
, sizeof(*swt
), NULL
);
751 } else if(proc_is64bit(p
)) {
752 struct user64_timeval t
;
753 t
.tv_sec
= swt
->tv_sec
;
754 t
.tv_usec
= swt
->tv_usec
;
755 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
757 struct user32_timeval t
;
758 t
.tv_sec
= swt
->tv_sec
;
759 t
.tv_usec
= swt
->tv_usec
;
760 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
764 static SYSCTL_PROC(_kern
, OID_AUTO
, sleeptime
,
765 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
766 &gIOLastSleepTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
768 static SYSCTL_PROC(_kern
, OID_AUTO
, waketime
,
769 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
770 &gIOLastWakeTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
775 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
777 int new_value
, changed
;
778 int error
= sysctl_io_number(req
, gWillShutdown
, sizeof(int), &new_value
, &changed
);
780 if (!gWillShutdown
&& (new_value
== 1)) {
781 IOPMRootDomainWillShutdown();
788 static SYSCTL_PROC(_kern
, OID_AUTO
, willshutdown
,
789 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
790 0, 0, sysctl_willshutdown
, "I", "");
792 extern struct sysctl_oid sysctl__kern_iokittest
;
796 sysctl_progressmeterenable
797 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
800 int new_value
, changed
;
802 error
= sysctl_io_number(req
, vc_progressmeter_enable
, sizeof(int), &new_value
, &changed
);
804 if (changed
) vc_enable_progressmeter(new_value
);
811 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
814 int new_value
, changed
;
816 error
= sysctl_io_number(req
, vc_progressmeter_value
, sizeof(int), &new_value
, &changed
);
818 if (changed
) vc_set_progressmeter(new_value
);
823 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeterenable
,
824 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
825 0, 0, sysctl_progressmeterenable
, "I", "");
827 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeter
,
828 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
829 0, 0, sysctl_progressmeter
, "I", "");
835 sysctl_consoleoptions
836 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
841 error
= sysctl_io_number(req
, vc_user_options
.options
, sizeof(uint32_t), &new_value
, &changed
);
843 if (changed
) vc_user_options
.options
= new_value
;
848 static SYSCTL_PROC(_kern
, OID_AUTO
, consoleoptions
,
849 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
850 0, 0, sysctl_consoleoptions
, "I", "");
854 sysctl_progressoptions SYSCTL_HANDLER_ARGS
856 return sysctl_io_opaque(req
, &vc_user_options
, sizeof(vc_user_options
), NULL
);
859 static SYSCTL_PROC(_kern
, OID_AUTO
, progressoptions
,
860 CTLTYPE_STRUCT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
| CTLFLAG_ANYBODY
,
861 NULL
, 0, sysctl_progressoptions
, "S,vc_progress_user_options", "");
865 sysctl_wakereason SYSCTL_HANDLER_ARGS
867 char wr
[ sizeof(gWakeReasonString
) ];
871 gRootDomain
->copyWakeReasonString(wr
, sizeof(wr
));
873 return sysctl_io_string(req
, wr
, 0, 0, NULL
);
876 SYSCTL_PROC(_kern
, OID_AUTO
, wakereason
,
877 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
878 NULL
, 0, sysctl_wakereason
, "A", "wakereason");
881 sysctl_targettype SYSCTL_HANDLER_ARGS
889 root
= IOService::getServiceRoot();
890 if (root
&& (obj
= root
->copyProperty(gIODTTargetTypeKey
)))
892 if ((data
= OSDynamicCast(OSData
, obj
)))
894 strlcpy(tt
, (const char *) data
->getBytesNoCopy(), sizeof(tt
));
898 return sysctl_io_string(req
, tt
, 0, 0, NULL
);
901 SYSCTL_PROC(_hw
, OID_AUTO
, targettype
,
902 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
903 NULL
, 0, sysctl_targettype
, "A", "targettype");
905 static SYSCTL_INT(_debug
, OID_AUTO
, darkwake
, CTLFLAG_RW
, &gDarkWakeFlags
, 0, "");
906 static SYSCTL_INT(_debug
, OID_AUTO
, noidle
, CTLFLAG_RW
, &gNoIdleFlag
, 0, "");
908 static const OSSymbol
* gIOPMSettingAutoWakeCalendarKey
;
909 static const OSSymbol
* gIOPMSettingAutoWakeSecondsKey
;
910 static const OSSymbol
* gIOPMSettingDebugWakeRelativeKey
;
911 static const OSSymbol
* gIOPMSettingMaintenanceWakeCalendarKey
;
912 static const OSSymbol
* gIOPMSettingSleepServiceWakeCalendarKey
;
913 static const OSSymbol
* gIOPMSettingSilentRunningKey
;
914 static const OSSymbol
* gIOPMUserTriggeredFullWakeKey
;
915 static const OSSymbol
* gIOPMUserIsActiveKey
;
917 //******************************************************************************
920 //******************************************************************************
922 #define kRootDomainSettingsCount 17
924 bool IOPMrootDomain::start( IOService
* nub
)
926 OSIterator
*psIterator
;
927 OSDictionary
*tmpDict
;
928 IORootParent
* patriarch
;
929 #if defined(__i386__) || defined(__x86_64__)
930 IONotifier
* notifier
;
936 gIOPMSettingAutoWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
);
937 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
938 gIOPMSettingDebugWakeRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
);
939 gIOPMSettingMaintenanceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
940 gIOPMSettingSleepServiceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey
);
941 gIOPMSettingSilentRunningKey
= OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey
);
942 gIOPMUserTriggeredFullWakeKey
= OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey
);
943 gIOPMUserIsActiveKey
= OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey
);
945 gIOPMStatsApplicationResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
946 gIOPMStatsApplicationResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
947 gIOPMStatsApplicationResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
948 gIOPMStatsApplicationResponsePrompt
= OSSymbol::withCString(kIOPMStatsResponsePrompt
);
949 gIOPMStatsDriverPSChangeSlow
= OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow
);
951 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
952 sleepMessagePEFunction
= OSSymbol::withCString("IOPMSystemSleepMessage");
954 const OSSymbol
*settingsArr
[kRootDomainSettingsCount
] =
956 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
957 gIOPMSettingAutoWakeSecondsKey
,
958 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
),
959 gIOPMSettingAutoWakeCalendarKey
,
960 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
),
961 gIOPMSettingDebugWakeRelativeKey
,
962 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
),
963 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
964 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
965 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
966 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
967 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
968 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
969 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
970 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
971 OSSymbol::withCString(kIOPMStateConsoleShutdown
),
972 gIOPMSettingSilentRunningKey
975 PE_parse_boot_argn("darkwake", &gDarkWakeFlags
, sizeof(gDarkWakeFlags
));
976 PE_parse_boot_argn("noidle", &gNoIdleFlag
, sizeof(gNoIdleFlag
));
978 queue_init(&aggressivesQueue
);
979 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
980 aggressivesData
= OSData::withCapacity(
981 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
983 featuresDictLock
= IOLockAlloc();
984 settingsCtrlLock
= IOLockAlloc();
985 wakeEventLock
= IOLockAlloc();
986 setPMRootDomain(this);
988 extraSleepTimer
= thread_call_allocate(
989 idleSleepTimerExpired
,
990 (thread_call_param_t
) this);
992 diskSyncCalloutEntry
= thread_call_allocate(
994 (thread_call_param_t
) this);
995 hibDebugSetupEntry
= thread_call_allocate(
996 &hib_debugSetup_callout
,
997 (thread_call_param_t
) this);
999 updateConsoleUsersEntry
= thread_call_allocate(
1000 &updateConsoleUsersCallout
,
1001 (thread_call_param_t
) this);
1003 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
1004 fullWakeThreadCall
= thread_call_allocate(
1005 OSMemberFunctionCast(thread_call_func_t
, this,
1006 &IOPMrootDomain::fullWakeDelayedWork
),
1007 (thread_call_param_t
) this);
1010 setProperty(kIOSleepSupportedKey
, true);
1012 bzero(&gPMStats
, sizeof(gPMStats
));
1014 pmTracer
= PMTraceWorker::tracer(this);
1016 pmAssertions
= PMAssertionsTracker::pmAssertionsTracker(this);
1018 userDisabledAllSleep
= false;
1019 systemBooting
= true;
1021 idleSleepTimerPending
= false;
1023 clamshellClosed
= false;
1024 clamshellExists
= false;
1025 clamshellDisabled
= true;
1026 acAdaptorConnected
= true;
1027 clamshellSleepDisabled
= false;
1028 gWakeReasonString
[0] = '\0';
1030 // Initialize to user active.
1031 // Will never transition to user inactive w/o wrangler.
1032 fullWakeReason
= kFullWakeReasonLocalUser
;
1033 userIsActive
= userWasActive
= true;
1034 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
1036 // Set the default system capabilities at boot.
1037 _currentCapability
= kIOPMSystemCapabilityCPU
|
1038 kIOPMSystemCapabilityGraphics
|
1039 kIOPMSystemCapabilityAudio
|
1040 kIOPMSystemCapabilityNetwork
;
1042 _pendingCapability
= _currentCapability
;
1043 _desiredCapability
= _currentCapability
;
1044 _highestCapability
= _currentCapability
;
1045 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
1047 queuedSleepWakeUUIDString
= NULL
;
1048 initializeBootSessionUUID();
1049 pmStatsAppResponses
= OSArray::withCapacity(5);
1050 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
1051 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
1052 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
1053 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
1054 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
1055 _statsPowerCapsKey
= OSSymbol::withCString(kIOPMStatsPowerCapabilityKey
);
1056 assertOnWakeSecs
= -1; // Invalid value to prevent updates
1058 pmStatsLock
= IOLockAlloc();
1059 idxPMCPUClamshell
= kCPUUnknownIndex
;
1060 idxPMCPULimitedPower
= kCPUUnknownIndex
;
1062 tmpDict
= OSDictionary::withCapacity(1);
1063 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
1066 settingsCallbacks
= OSDictionary::withCapacity(1);
1068 // Create a list of the valid PM settings that we'll relay to
1069 // interested clients in setProperties() => setPMSetting()
1070 allowedPMSettings
= OSArray::withObjects(
1071 (const OSObject
**)settingsArr
,
1072 kRootDomainSettingsCount
,
1075 // List of PM settings that should not automatically publish itself
1076 // as a feature when registered by a listener.
1077 noPublishPMSettings
= OSArray::withObjects(
1078 (const OSObject
**) &gIOPMSettingSilentRunningKey
, 1, 0);
1080 fPMSettingsDict
= OSDictionary::withCapacity(5);
1081 preventIdleSleepList
= OSSet::withCapacity(8);
1082 preventSystemSleepList
= OSSet::withCapacity(2);
1084 PMinit(); // creates gIOPMWorkLoop
1086 // Create IOPMPowerStateQueue used to queue external power
1087 // events, and to handle those events on the PM work loop.
1088 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
1089 this, OSMemberFunctionCast(IOEventSource::Action
, this,
1090 &IOPMrootDomain::dispatchPowerEvent
));
1091 getPMworkloop()->addEventSource(pmPowerStateQueue
);
1092 #ifdef CHECK_THREAD_CONTEXT
1093 gIOPMWorkLoop
= getPMworkloop();
1096 // create our power parent
1097 patriarch
= new IORootParent
;
1099 patriarch
->attach(this);
1100 patriarch
->start(this);
1101 patriarch
->addPowerChild(this);
1103 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
1104 changePowerStateToPriv(ON_STATE
);
1106 // install power change handler
1107 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
1110 // Register for a notification when IODisplayWrangler is published
1111 if ((tmpDict
= serviceMatching("IODisplayWrangler")))
1113 _displayWranglerNotifier
= addMatchingNotification(
1114 gIOPublishNotification
, tmpDict
,
1115 (IOServiceMatchingNotificationHandler
) &displayWranglerMatchPublished
,
1121 #if defined(__i386__) || defined(__x86_64__)
1123 if ((tmpDict
= serviceMatching("IODTNVRAM")))
1125 notifier
= addMatchingNotification(
1126 gIOFirstPublishNotification
, tmpDict
,
1127 (IOServiceMatchingNotificationHandler
) &IONVRAMMatchPublished
,
1132 wranglerIdleSettings
= NULL
;
1133 OSNumber
* wranglerIdlePeriod
= NULL
;
1134 wranglerIdleSettings
= OSDictionary::withCapacity(1);
1135 wranglerIdlePeriod
= OSNumber::withNumber(kDefaultWranglerIdlePeriod
, 32);
1137 if(wranglerIdleSettings
&& wranglerIdlePeriod
)
1138 wranglerIdleSettings
->setObject(kIORequestWranglerIdleKey
,
1139 wranglerIdlePeriod
);
1141 if(wranglerIdlePeriod
)
1142 wranglerIdlePeriod
->release();
1145 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
1146 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
1147 ucClassName
->release();
1149 // IOBacklightDisplay can take a long time to load at boot, or it may
1150 // not load at all if you're booting with clamshell closed. We publish
1151 // 'DisplayDims' here redundantly to get it published early and at all.
1152 OSDictionary
* matching
;
1153 matching
= serviceMatching("IOPMPowerSource");
1154 psIterator
= getMatchingServices( matching
);
1155 if (matching
) matching
->release();
1156 if( psIterator
&& psIterator
->getNextObject() )
1158 // There's at least one battery on the system, so we publish
1159 // 'DisplayDims' support for the LCD.
1160 publishFeature("DisplayDims");
1163 psIterator
->release();
1166 sysctl_register_oid(&sysctl__kern_sleeptime
);
1167 sysctl_register_oid(&sysctl__kern_waketime
);
1168 sysctl_register_oid(&sysctl__kern_willshutdown
);
1169 sysctl_register_oid(&sysctl__kern_iokittest
);
1170 sysctl_register_oid(&sysctl__hw_targettype
);
1172 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
1173 sysctl_register_oid(&sysctl__kern_progressmeter
);
1174 sysctl_register_oid(&sysctl__kern_wakereason
);
1175 sysctl_register_oid(&sysctl__kern_consoleoptions
);
1176 sysctl_register_oid(&sysctl__kern_progressoptions
);
1179 IOHibernateSystemInit(this);
1182 registerService(); // let clients find us
1187 //******************************************************************************
1190 // Receive a setProperty call
1191 // The "System Boot" property means the system is completely booted.
1192 //******************************************************************************
1194 IOReturn
IOPMrootDomain::setProperties( OSObject
* props_obj
)
1196 IOReturn return_value
= kIOReturnSuccess
;
1197 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
1200 const OSSymbol
*key
;
1202 OSCollectionIterator
* iter
= 0;
1204 const OSSymbol
*publish_simulated_battery_string
= OSSymbol::withCString("SoftwareSimulatedBatteries");
1205 const OSSymbol
*boot_complete_string
= OSSymbol::withCString("System Boot Complete");
1206 const OSSymbol
*sys_shutdown_string
= OSSymbol::withCString("System Shutdown");
1207 const OSSymbol
*stall_halt_string
= OSSymbol::withCString("StallSystemAtHalt");
1208 const OSSymbol
*battery_warning_disabled_string
= OSSymbol::withCString("BatteryWarningsDisabled");
1209 const OSSymbol
*idle_seconds_string
= OSSymbol::withCString("System Idle Seconds");
1210 const OSSymbol
*sleepdisabled_string
= OSSymbol::withCString("SleepDisabled");
1211 const OSSymbol
*ondeck_sleepwake_uuid_string
= OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
1212 const OSSymbol
*loginwindow_tracepoint_string
= OSSymbol::withCString(kIOPMLoginWindowSecurityDebugKey
);
1214 const OSSymbol
*hibernatemode_string
= OSSymbol::withCString(kIOHibernateModeKey
);
1215 const OSSymbol
*hibernatefile_string
= OSSymbol::withCString(kIOHibernateFileKey
);
1216 const OSSymbol
*hibernatefilemin_string
= OSSymbol::withCString(kIOHibernateFileMinSizeKey
);
1217 const OSSymbol
*hibernatefilemax_string
= OSSymbol::withCString(kIOHibernateFileMaxSizeKey
);
1218 const OSSymbol
*hibernatefreeratio_string
= OSSymbol::withCString(kIOHibernateFreeRatioKey
);
1219 const OSSymbol
*hibernatefreetime_string
= OSSymbol::withCString(kIOHibernateFreeTimeKey
);
1224 return_value
= kIOReturnBadArgument
;
1228 iter
= OSCollectionIterator::withCollection(dict
);
1231 return_value
= kIOReturnNoMemory
;
1235 while ((key
= (const OSSymbol
*) iter
->getNextObject()) &&
1236 (obj
= dict
->getObject(key
)))
1238 if (key
->isEqualTo(publish_simulated_battery_string
))
1240 if (OSDynamicCast(OSBoolean
, obj
))
1241 publishResource(key
, kOSBooleanTrue
);
1243 else if (key
->isEqualTo(idle_seconds_string
))
1245 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1247 setProperty(key
, n
);
1248 idleSeconds
= n
->unsigned32BitValue();
1251 else if (key
->isEqualTo(boot_complete_string
))
1253 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemBootCompleted
);
1255 else if (key
->isEqualTo(sys_shutdown_string
))
1257 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1258 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
1260 else if (key
->isEqualTo(battery_warning_disabled_string
))
1262 setProperty(key
, obj
);
1265 else if (key
->isEqualTo(hibernatemode_string
) ||
1266 key
->isEqualTo(hibernatefilemin_string
) ||
1267 key
->isEqualTo(hibernatefilemax_string
) ||
1268 key
->isEqualTo(hibernatefreeratio_string
) ||
1269 key
->isEqualTo(hibernatefreetime_string
))
1271 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1272 setProperty(key
, n
);
1274 else if (key
->isEqualTo(hibernatefile_string
))
1276 OSString
* str
= OSDynamicCast(OSString
, obj
);
1277 if (str
) setProperty(key
, str
);
1280 else if (key
->isEqualTo(sleepdisabled_string
))
1282 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1284 setProperty(key
, b
);
1285 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
1288 else if (key
->isEqualTo(ondeck_sleepwake_uuid_string
))
1291 pmPowerStateQueue
->submitPowerEvent(kPowerEventQueueSleepWakeUUID
, (void *)obj
);
1293 else if (key
->isEqualTo(loginwindow_tracepoint_string
))
1295 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
)))
1296 pmTracer
->traceLoginWindowPhase(n
->unsigned8BitValue());
1298 else if (key
->isEqualTo(kIOPMDeepSleepEnabledKey
) ||
1299 key
->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey
) ||
1300 key
->isEqualTo(kIOPMAutoPowerOffEnabledKey
) ||
1301 key
->isEqualTo(stall_halt_string
))
1303 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1304 setProperty(key
, b
);
1306 else if (key
->isEqualTo(kIOPMDeepSleepDelayKey
) ||
1307 key
->isEqualTo(kIOPMAutoPowerOffDelayKey
) ||
1308 key
->isEqualTo(kIOPMAutoPowerOffTimerKey
))
1310 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1311 setProperty(key
, n
);
1313 else if (key
->isEqualTo(kIOPMUserWakeAlarmScheduledKey
))
1315 if (kOSBooleanTrue
== obj
)
1316 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1318 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1319 DLOG("_userScheduledAlarm = 0x%x\n", (uint32_t) _userScheduledAlarm
);
1322 // Relay our allowed PM settings onto our registered PM clients
1323 else if ((allowedPMSettings
->getNextIndexOfObject(key
, 0) != (unsigned int) -1))
1325 return_value
= setPMSetting(key
, obj
);
1326 if (kIOReturnSuccess
!= return_value
)
1329 if (gIOPMSettingDebugWakeRelativeKey
== key
)
1331 if ((n
= OSDynamicCast(OSNumber
, obj
)) &&
1332 (_debugWakeSeconds
= n
->unsigned32BitValue()))
1334 OSBitOrAtomic(kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1338 _debugWakeSeconds
= 0;
1339 OSBitAndAtomic(~kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1341 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1343 else if (gIOPMSettingAutoWakeCalendarKey
== key
)
1346 if ((data
= OSDynamicCast(OSData
, obj
)) &&
1347 (data
->getLength() == sizeof(IOPMCalendarStruct
)))
1349 const IOPMCalendarStruct
* cs
=
1350 (const IOPMCalendarStruct
*) data
->getBytesNoCopy();
1353 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1355 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1356 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1362 DLOG("setProperties(%s) not handled\n", key
->getCStringNoCopy());
1367 if(publish_simulated_battery_string
) publish_simulated_battery_string
->release();
1368 if(boot_complete_string
) boot_complete_string
->release();
1369 if(sys_shutdown_string
) sys_shutdown_string
->release();
1370 if(stall_halt_string
) stall_halt_string
->release();
1371 if(battery_warning_disabled_string
) battery_warning_disabled_string
->release();
1372 if(idle_seconds_string
) idle_seconds_string
->release();
1373 if(sleepdisabled_string
) sleepdisabled_string
->release();
1374 if(ondeck_sleepwake_uuid_string
) ondeck_sleepwake_uuid_string
->release();
1375 if(loginwindow_tracepoint_string
) loginwindow_tracepoint_string
->release();
1377 if(hibernatemode_string
) hibernatemode_string
->release();
1378 if(hibernatefile_string
) hibernatefile_string
->release();
1379 if(hibernatefreeratio_string
) hibernatefreeratio_string
->release();
1380 if(hibernatefreetime_string
) hibernatefreetime_string
->release();
1382 if (iter
) iter
->release();
1383 return return_value
;
1387 // MARK: Aggressiveness
1389 //******************************************************************************
1390 // setAggressiveness
1392 // Override IOService::setAggressiveness()
1393 //******************************************************************************
1395 IOReturn
IOPMrootDomain::setAggressiveness(
1397 unsigned long value
)
1399 return setAggressiveness( type
, value
, 0 );
1403 * Private setAggressiveness() with an internal options argument.
1405 IOReturn
IOPMrootDomain::setAggressiveness(
1407 unsigned long value
,
1408 IOOptionBits options
)
1410 AggressivesRequest
* entry
;
1411 AggressivesRequest
* request
;
1414 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1415 (uint32_t) options
, (uint32_t) type
, (uint32_t) value
);
1417 request
= IONew(AggressivesRequest
, 1);
1419 return kIOReturnNoMemory
;
1421 memset(request
, 0, sizeof(*request
));
1422 request
->options
= options
;
1423 request
->dataType
= kAggressivesRequestTypeRecord
;
1424 request
->data
.record
.type
= (uint32_t) type
;
1425 request
->data
.record
.value
= (uint32_t) value
;
1429 // Update disk quick spindown flag used by getAggressiveness().
1430 // Never merge requests with quick spindown flags set.
1432 if (options
& kAggressivesOptionQuickSpindownEnable
)
1433 gAggressivesState
|= kAggressivesStateQuickSpindown
;
1434 else if (options
& kAggressivesOptionQuickSpindownDisable
)
1435 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
1438 // Coalesce requests with identical aggressives types.
1439 // Deal with callers that calls us too "aggressively".
1441 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1443 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1444 (entry
->data
.record
.type
== type
) &&
1445 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1447 entry
->data
.record
.value
= value
;
1456 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1459 AGGRESSIVES_UNLOCK();
1462 IODelete(request
, AggressivesRequest
, 1);
1464 if (options
& kAggressivesOptionSynchronous
)
1465 handleAggressivesRequests(); // not truly synchronous
1467 thread_call_enter(aggressivesThreadCall
);
1469 return kIOReturnSuccess
;
1472 //******************************************************************************
1473 // getAggressiveness
1475 // Override IOService::setAggressiveness()
1476 // Fetch the aggressiveness factor with the given type.
1477 //******************************************************************************
1479 IOReturn
IOPMrootDomain::getAggressiveness (
1481 unsigned long * outLevel
)
1487 return kIOReturnBadArgument
;
1491 // Disk quick spindown in effect, report value = 1
1493 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
1494 (type
== kPMMinutesToSpinDown
))
1496 value
= kAggressivesMinValue
;
1500 // Consult the pending request queue.
1504 AggressivesRequest
* entry
;
1506 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1508 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1509 (entry
->data
.record
.type
== type
) &&
1510 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1512 value
= entry
->data
.record
.value
;
1519 // Consult the backend records.
1521 if (!source
&& aggressivesData
)
1523 AggressivesRecord
* record
;
1526 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1527 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1529 for (i
= 0; i
< count
; i
++, record
++)
1531 if (record
->type
== type
)
1533 value
= record
->value
;
1540 AGGRESSIVES_UNLOCK();
1544 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1545 source
, (uint32_t) type
, value
);
1546 *outLevel
= (unsigned long) value
;
1547 return kIOReturnSuccess
;
1551 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
1552 *outLevel
= 0; // default return = 0, driver may not check for error
1553 return kIOReturnInvalid
;
1557 //******************************************************************************
1558 // joinAggressiveness
1560 // Request from IOService to join future aggressiveness broadcasts.
1561 //******************************************************************************
1563 IOReturn
IOPMrootDomain::joinAggressiveness(
1564 IOService
* service
)
1566 AggressivesRequest
* request
;
1568 if (!service
|| (service
== this))
1569 return kIOReturnBadArgument
;
1571 DLOG("joinAggressiveness %s %p\n", service
->getName(), OBFUSCATE(service
));
1573 request
= IONew(AggressivesRequest
, 1);
1575 return kIOReturnNoMemory
;
1577 service
->retain(); // released by synchronizeAggressives()
1579 memset(request
, 0, sizeof(*request
));
1580 request
->dataType
= kAggressivesRequestTypeService
;
1581 request
->data
.service
= service
;
1584 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1585 AGGRESSIVES_UNLOCK();
1587 thread_call_enter(aggressivesThreadCall
);
1589 return kIOReturnSuccess
;
1592 //******************************************************************************
1593 // handleAggressivesRequests
1595 // Backend thread processes all incoming aggressiveness requests in the queue.
1596 //******************************************************************************
1599 handleAggressivesFunction(
1600 thread_call_param_t param1
,
1601 thread_call_param_t param2
)
1605 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
1609 void IOPMrootDomain::handleAggressivesRequests( void )
1611 AggressivesRecord
* start
;
1612 AggressivesRecord
* record
;
1613 AggressivesRequest
* request
;
1614 queue_head_t joinedQueue
;
1618 bool pingSelf
= false;
1622 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
1623 queue_empty(&aggressivesQueue
))
1626 gAggressivesState
|= kAggressivesStateBusy
;
1627 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1628 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1633 queue_init(&joinedQueue
);
1637 // Remove request from the incoming queue in FIFO order.
1638 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1639 switch (request
->dataType
)
1641 case kAggressivesRequestTypeRecord
:
1642 // Update existing record if found.
1644 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1646 if (record
->type
== request
->data
.record
.type
)
1650 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1652 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1655 record
->flags
|= (kAggressivesRecordFlagMinValue
|
1656 kAggressivesRecordFlagModified
);
1657 DLOG("disk spindown accelerated, was %u min\n",
1661 else if (request
->options
& kAggressivesOptionQuickSpindownDisable
)
1663 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1666 record
->flags
|= kAggressivesRecordFlagModified
;
1667 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
1668 DLOG("disk spindown restored to %u min\n",
1672 else if (record
->value
!= request
->data
.record
.value
)
1674 record
->value
= request
->data
.record
.value
;
1675 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1678 record
->flags
|= kAggressivesRecordFlagModified
;
1685 // No matching record, append a new record.
1687 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0))
1689 AggressivesRecord newRecord
;
1691 newRecord
.flags
= kAggressivesRecordFlagModified
;
1692 newRecord
.type
= request
->data
.record
.type
;
1693 newRecord
.value
= request
->data
.record
.value
;
1694 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1696 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
1697 DLOG("disk spindown accelerated\n");
1700 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
1702 // OSData may have switched to another (larger) buffer.
1703 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1704 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1708 // Finished processing the request, release it.
1709 IODelete(request
, AggressivesRequest
, 1);
1712 case kAggressivesRequestTypeService
:
1713 // synchronizeAggressives() will free request.
1714 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
1718 panic("bad aggressives request type %x\n", request
->dataType
);
1721 } while (!queue_empty(&aggressivesQueue
));
1723 // Release the lock to perform work, with busy flag set.
1724 if (!queue_empty(&joinedQueue
) || broadcast
)
1726 AGGRESSIVES_UNLOCK();
1727 if (!queue_empty(&joinedQueue
))
1728 synchronizeAggressives(&joinedQueue
, start
, count
);
1730 broadcastAggressives(start
, count
);
1734 // Remove the modified flag from all records.
1735 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1737 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
1738 ((record
->type
== kPMMinutesToDim
) ||
1739 (record
->type
== kPMMinutesToSleep
)))
1742 record
->flags
&= ~kAggressivesRecordFlagModified
;
1745 // Check the incoming queue again since new entries may have been
1746 // added while lock was released above.
1748 } while (!queue_empty(&aggressivesQueue
));
1750 gAggressivesState
&= ~kAggressivesStateBusy
;
1753 AGGRESSIVES_UNLOCK();
1755 // Root domain is interested in system and display sleep slider changes.
1756 // Submit a power event to handle those changes on the PM work loop.
1758 if (pingSelf
&& pmPowerStateQueue
) {
1759 pmPowerStateQueue
->submitPowerEvent(
1760 kPowerEventPolicyStimulus
,
1761 (void *) kStimulusAggressivenessChanged
);
1765 //******************************************************************************
1766 // synchronizeAggressives
1768 // Push all known aggressiveness records to one or more IOService.
1769 //******************************************************************************
1771 void IOPMrootDomain::synchronizeAggressives(
1772 queue_head_t
* joinedQueue
,
1773 const AggressivesRecord
* array
,
1776 IOService
* service
;
1777 AggressivesRequest
* request
;
1778 const AggressivesRecord
* record
;
1779 IOPMDriverCallEntry callEntry
;
1783 while (!queue_empty(joinedQueue
))
1785 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
1786 if (request
->dataType
== kAggressivesRequestTypeService
)
1787 service
= request
->data
.service
;
1791 IODelete(request
, AggressivesRequest
, 1);
1796 if (service
->assertPMDriverCall(&callEntry
))
1798 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1800 value
= record
->value
;
1801 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1802 value
= kAggressivesMinValue
;
1804 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
1805 record
->type
, value
, service
->getName());
1806 service
->setAggressiveness(record
->type
, value
);
1808 service
->deassertPMDriverCall(&callEntry
);
1810 service
->release(); // retained by joinAggressiveness()
1815 //******************************************************************************
1816 // broadcastAggressives
1818 // Traverse PM tree and call setAggressiveness() for records that have changed.
1819 //******************************************************************************
1821 void IOPMrootDomain::broadcastAggressives(
1822 const AggressivesRecord
* array
,
1825 IORegistryIterator
* iter
;
1826 IORegistryEntry
* entry
;
1827 IOPowerConnection
* connect
;
1828 IOService
* service
;
1829 const AggressivesRecord
* record
;
1830 IOPMDriverCallEntry callEntry
;
1834 iter
= IORegistryIterator::iterateOver(
1835 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
1841 while ((entry
= iter
->getNextObject()))
1843 connect
= OSDynamicCast(IOPowerConnection
, entry
);
1844 if (!connect
|| !connect
->getReadyFlag())
1847 if ((service
= (IOService
*) connect
->copyChildEntry(gIOPowerPlane
)))
1849 if (service
->assertPMDriverCall(&callEntry
))
1851 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1853 if (record
->flags
& kAggressivesRecordFlagModified
)
1855 value
= record
->value
;
1856 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1857 value
= kAggressivesMinValue
;
1858 _LOG("broadcastAggressives %x = %u to %s\n",
1859 record
->type
, value
, service
->getName());
1860 service
->setAggressiveness(record
->type
, value
);
1863 service
->deassertPMDriverCall(&callEntry
);
1869 while (!entry
&& !iter
->isValid());
1875 // MARK: System Sleep
1877 //******************************************************************************
1878 // startIdleSleepTimer
1880 //******************************************************************************
1882 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
1884 AbsoluteTime deadline
;
1888 DLOG("idle timer not set (noidle=%d)\n", gNoIdleFlag
);
1893 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
1894 thread_call_enter_delayed(extraSleepTimer
, deadline
);
1895 idleSleepTimerPending
= true;
1899 thread_call_enter(extraSleepTimer
);
1901 DLOG("idle timer set for %u seconds\n", inSeconds
);
1904 //******************************************************************************
1905 // cancelIdleSleepTimer
1907 //******************************************************************************
1909 void IOPMrootDomain::cancelIdleSleepTimer( void )
1912 if (idleSleepTimerPending
)
1914 DLOG("idle timer cancelled\n");
1915 thread_call_cancel(extraSleepTimer
);
1916 idleSleepTimerPending
= false;
1918 if (!assertOnWakeSecs
&& systemWakeTime
) {
1920 clock_usec_t microsecs
;
1921 clock_get_uptime(&now
);
1922 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
1923 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
1924 if (assertOnWakeReport
) {
1925 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
1926 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
1932 //******************************************************************************
1933 // idleSleepTimerExpired
1935 //******************************************************************************
1937 static void idleSleepTimerExpired(
1938 thread_call_param_t us
, thread_call_param_t
)
1940 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
1943 //******************************************************************************
1944 // handleSleepTimerExpiration
1946 // The time between the sleep idle timeout and the next longest one has elapsed.
1947 // It's time to sleep. Start that by removing the clamp that's holding us awake.
1948 //******************************************************************************
1950 void IOPMrootDomain::handleSleepTimerExpiration( void )
1952 if (!getPMworkloop()->inGate())
1954 getPMworkloop()->runAction(
1955 OSMemberFunctionCast(IOWorkLoop::Action
, this,
1956 &IOPMrootDomain::handleSleepTimerExpiration
),
1963 DLOG("sleep timer expired\n");
1966 idleSleepTimerPending
= false;
1968 clock_get_uptime(&time
);
1969 setQuickSpinDownTimeout();
1970 adjustPowerState(true);
1973 //******************************************************************************
1974 // getTimeToIdleSleep
1976 // Returns number of seconds left before going into idle sleep.
1977 // Caller has to make sure that idle sleep is allowed at the time of calling
1979 //******************************************************************************
1981 uint32_t IOPMrootDomain::getTimeToIdleSleep( void )
1984 AbsoluteTime now
, lastActivityTime
;
1986 uint32_t minutesSinceUserInactive
= 0;
1987 uint32_t sleepDelay
= 0;
1989 if (sleepSlider
== 0)
1992 if (userActivityTime
)
1993 lastActivityTime
= userActivityTime
;
1995 lastActivityTime
= userBecameInactiveTime
;
1997 clock_get_uptime(&now
);
1998 if (CMP_ABSOLUTETIME(&now
, &lastActivityTime
) > 0)
2000 SUB_ABSOLUTETIME(&now
, &lastActivityTime
);
2001 absolutetime_to_nanoseconds(now
, &nanos
);
2002 minutesSinceUserInactive
= nanos
/ (60000000000ULL);
2004 if (minutesSinceUserInactive
>= sleepSlider
)
2007 sleepDelay
= sleepSlider
- minutesSinceUserInactive
;
2011 sleepDelay
= sleepSlider
;
2014 DLOG("user inactive %u min, time to idle sleep %u min\n",
2015 minutesSinceUserInactive
, sleepDelay
);
2017 return (sleepDelay
* 60);
2020 //******************************************************************************
2021 // setQuickSpinDownTimeout
2023 //******************************************************************************
2025 void IOPMrootDomain::setQuickSpinDownTimeout( void )
2029 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
2032 //******************************************************************************
2033 // restoreUserSpinDownTimeout
2035 //******************************************************************************
2037 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
2041 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
2044 //******************************************************************************
2047 //******************************************************************************
2050 IOReturn
IOPMrootDomain::sleepSystem( void )
2052 return sleepSystemOptions(NULL
);
2056 IOReturn
IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
2058 OSObject
*obj
= NULL
;
2059 OSString
*reason
= NULL
;
2060 /* sleepSystem is a public function, and may be called by any kernel driver.
2061 * And that's bad - drivers should sleep the system by calling
2062 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2064 * Note that user space app calls to IOPMSleepSystem() will also travel
2065 * this code path and thus be correctly identified as software sleeps.
2068 if (options
&& options
->getObject("OSSwitch"))
2070 // Log specific sleep cause for OS Switch hibernation
2071 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate
);
2074 if (options
&& (obj
= options
->getObject("Sleep Reason")))
2076 reason
= OSDynamicCast(OSString
, obj
);
2077 if (reason
&& reason
->isEqualTo(kIOPMDarkWakeThermalEmergencyKey
))
2078 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
2081 return privateSleepSystem( kIOPMSleepReasonSoftware
);
2085 IOReturn
IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
2087 /* Called from both gated and non-gated context */
2089 if (!checkSystemSleepEnabled() || !pmPowerStateQueue
)
2091 return kIOReturnNotPermitted
;
2094 pmPowerStateQueue
->submitPowerEvent(
2095 kPowerEventPolicyStimulus
,
2096 (void *) kStimulusDemandSystemSleep
,
2099 return kIOReturnSuccess
;
2102 //******************************************************************************
2105 // This overrides powerChangeDone in IOService.
2106 //******************************************************************************
2108 void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState
)
2112 DLOG("PowerChangeDone: %u->%u\n",
2113 (uint32_t) previousPowerState
, (uint32_t) getPowerState());
2115 switch ( getPowerState() )
2118 if (previousPowerState
!= ON_STATE
)
2121 acceptSystemWakeEvents(true);
2123 // re-enable this timer for next sleep
2124 cancelIdleSleepTimer();
2127 clock_usec_t microsecs
;
2128 clock_get_calendar_absolute_and_microtime(&secs
, µsecs
, &now
);
2130 gIOLastSleepTime
.tv_sec
= secs
;
2131 gIOLastSleepTime
.tv_usec
= microsecs
;
2132 gIOLastWakeTime
.tv_sec
= 0;
2133 gIOLastWakeTime
.tv_usec
= 0;
2135 if (wake2DarkwakeDelay
&& sleepDelaysReport
) {
2136 clock_usec_t microsecs
;
2137 clock_sec_t wake2DarkwakeSecs
, darkwake2SleepSecs
;
2138 // Update 'wake2DarkwakeDelay' histogram if this is a fullwake->sleep transition
2140 SUB_ABSOLUTETIME(&now
, &ts_sleepStart
);
2141 absolutetime_to_microtime(now
, &darkwake2SleepSecs
, µsecs
);
2142 absolutetime_to_microtime(wake2DarkwakeDelay
, &wake2DarkwakeSecs
, µsecs
);
2143 HISTREPORT_TALLYVALUE(sleepDelaysReport
,
2144 (int64_t)(wake2DarkwakeSecs
+darkwake2SleepSecs
));
2146 DLOG("Updated sleepDelaysReport %lu %lu\n", (unsigned long)wake2DarkwakeSecs
, (unsigned long)darkwake2SleepSecs
);
2147 wake2DarkwakeDelay
= 0;
2150 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
2152 IOHibernateSystemHasSlept();
2154 evaluateSystemSleepPolicyFinal();
2156 LOG("System Sleep\n");
2158 if (thermalWarningState
) {
2159 const OSSymbol
*event
= OSSymbol::withCString(kIOPMThermalLevelWarningKey
);
2161 systemPowerEventOccurred(event
, kIOPMThermalLevelUnknown
);
2165 assertOnWakeSecs
= 0;
2166 ((IOService
*)this)->stop_watchdog_timer(); //14456299
2167 getPlatform()->sleepKernel();
2169 // The CPU(s) are off at this point,
2170 // Code will resume execution here upon wake.
2172 clock_get_uptime(&systemWakeTime
);
2173 _highestCapability
= 0;
2175 ((IOService
*)this)->start_watchdog_timer(); //14456299
2177 IOHibernateSystemWake();
2180 // sleep transition complete
2181 gSleepOrShutdownPending
= 0;
2183 // trip the reset of the calendar clock
2185 clock_sec_t wakeSecs
;
2186 clock_usec_t wakeMicrosecs
;
2188 clock_initialize_calendar();
2190 clock_get_calendar_microtime(&wakeSecs
, &wakeMicrosecs
);
2191 gIOLastWakeTime
.tv_sec
= wakeSecs
;
2192 gIOLastWakeTime
.tv_usec
= wakeMicrosecs
;
2196 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
2200 PMDebug(kPMLogSystemWake
, 0, 0);
2201 lowBatteryCondition
= false;
2202 lastSleepReason
= 0;
2204 _lastDebugWakeSeconds
= _debugWakeSeconds
;
2205 _debugWakeSeconds
= 0;
2206 _scheduledAlarms
= 0;
2212 #if defined(__i386__) || defined(__x86_64__)
2213 wranglerTickled
= false;
2214 graphicsSuppressed
= false;
2215 darkWakePostTickle
= false;
2216 darkWakeHibernateError
= false;
2217 darkWakeToSleepASAP
= true;
2218 logGraphicsClamp
= true;
2219 sleepTimerMaintenance
= false;
2220 sleepToStandby
= false;
2221 wranglerTickleLatched
= false;
2222 userWasActive
= false;
2223 fullWakeReason
= kFullWakeReasonNone
;
2225 OSString
* wakeType
= OSDynamicCast(
2226 OSString
, getProperty(kIOPMRootDomainWakeTypeKey
));
2227 OSString
* wakeReason
= OSDynamicCast(
2228 OSString
, getProperty(kIOPMRootDomainWakeReasonKey
));
2230 if (wakeReason
&& (wakeReason
->getLength() >= 2) &&
2231 gWakeReasonString
[0] == '\0')
2233 // Until the platform driver can claim its wake reasons
2234 strlcat(gWakeReasonString
, wakeReason
->getCStringNoCopy(),
2235 sizeof(gWakeReasonString
));
2238 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
))
2240 lowBatteryCondition
= true;
2241 darkWakeMaintenance
= true;
2243 else if ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0)
2246 OSNumber
* hibOptions
= OSDynamicCast(
2247 OSNumber
, getProperty(kIOHibernateOptionsKey
));
2248 if (hibernateAborted
|| ((hibOptions
&&
2249 !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
))))
2251 // Hibernate aborted, or EFI brought up graphics
2252 wranglerTickled
= true;
2253 DLOG("hibernation aborted %d, options 0x%x\n",
2255 hibOptions
? hibOptions
->unsigned32BitValue() : 0);
2260 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeUser
) ||
2261 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
)))
2263 // User wake or RTC alarm
2264 wranglerTickled
= true;
2268 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2270 // SMC standby timer trumps SleepX
2271 darkWakeMaintenance
= true;
2272 sleepTimerMaintenance
= true;
2275 if ((_lastDebugWakeSeconds
!= 0) &&
2276 ((gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
) == 0))
2278 // SleepX before maintenance
2279 wranglerTickled
= true;
2283 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
2285 darkWakeMaintenance
= true;
2289 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepService
))
2291 darkWakeMaintenance
= true;
2292 darkWakeSleepService
= true;
2294 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) {
2295 sleepToStandby
= true;
2301 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeHibernateError
))
2303 darkWakeMaintenance
= true;
2304 darkWakeHibernateError
= true;
2308 // Unidentified wake source, resume to full wake if debug
2309 // alarm is pending.
2311 if (_lastDebugWakeSeconds
&&
2312 (!wakeReason
|| wakeReason
->isEqualTo("")))
2313 wranglerTickled
= true;
2319 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2321 darkWakeMaintenance
= true;
2322 sleepTimerMaintenance
= true;
2324 else if (hibernateAborted
|| !wakeType
||
2325 !wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
) ||
2326 !wakeReason
|| !wakeReason
->isEqualTo("RTC"))
2328 // Post a HID tickle immediately - except for RTC maintenance wake.
2329 wranglerTickled
= true;
2333 darkWakeMaintenance
= true;
2337 if (wranglerTickled
)
2339 darkWakeToSleepASAP
= false;
2340 fullWakeReason
= kFullWakeReasonLocalUser
;
2343 else if (displayPowerOnRequested
&& checkSystemCanSustainFullWake())
2345 handleDisplayPowerOn();
2347 else if (!darkWakeMaintenance
)
2349 // Early/late tickle for non-maintenance wake.
2350 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2351 kDarkWakeFlagHIDTickleEarly
) ||
2352 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2353 kDarkWakeFlagHIDTickleLate
))
2355 darkWakePostTickle
= true;
2358 #else /* !__i386__ && !__x86_64__ */
2359 // stay awake for at least 30 seconds
2360 wranglerTickled
= true;
2361 fullWakeReason
= kFullWakeReasonLocalUser
;
2362 startIdleSleepTimer(30);
2366 thread_call_enter(updateConsoleUsersEntry
);
2368 changePowerStateToPriv(ON_STATE
);
2370 #if !__i386__ && !__x86_64__
2372 if (previousPowerState
!= ON_STATE
)
2374 DLOG("Force re-evaluating aggressiveness\n");
2375 /* Force re-evaluate the aggressiveness values to set appropriate idle sleep timer */
2376 pmPowerStateQueue
->submitPowerEvent(
2377 kPowerEventPolicyStimulus
,
2378 (void *) kStimulusNoIdleSleepPreventers
);
2388 //******************************************************************************
2389 // requestPowerDomainState
2391 // Extend implementation in IOService. Running on PM work loop thread.
2392 //******************************************************************************
2394 IOReturn
IOPMrootDomain::requestPowerDomainState (
2395 IOPMPowerFlags childDesire
,
2396 IOPowerConnection
* childConnection
,
2397 unsigned long specification
)
2399 // Idle and system sleep prevention flags affects driver desire.
2400 // Children desire are irrelevant so they are cleared.
2402 return super::requestPowerDomainState(0, childConnection
, specification
);
2406 //******************************************************************************
2407 // updatePreventIdleSleepList
2409 // Called by IOService on PM work loop.
2410 // Returns true if PM policy recognized the driver's desire to prevent idle
2411 // sleep and updated the list of idle sleep preventers. Returns false otherwise
2412 //******************************************************************************
2414 bool IOPMrootDomain::updatePreventIdleSleepList(
2415 IOService
* service
, bool addNotRemove
)
2417 unsigned int oldCount
, newCount
;
2421 #if defined(__i386__) || defined(__x86_64__)
2422 // Disregard disk I/O (besides the display wrangler) as a factor preventing
2423 // idle sleep, except in the case of legacy disk I/O
2424 if ((service
!= wrangler
) && (service
!= this))
2430 oldCount
= preventIdleSleepList
->getCount();
2433 preventIdleSleepList
->setObject(service
);
2434 DLOG("prevent idle sleep list: %s+ (%u)\n",
2435 service
->getName(), preventIdleSleepList
->getCount());
2437 else if (preventIdleSleepList
->member(service
))
2439 preventIdleSleepList
->removeObject(service
);
2440 DLOG("prevent idle sleep list: %s- (%u)\n",
2441 service
->getName(), preventIdleSleepList
->getCount());
2443 newCount
= preventIdleSleepList
->getCount();
2445 if ((oldCount
== 0) && (newCount
!= 0))
2447 // Driver added to empty prevent list.
2448 // Update the driver desire to prevent idle sleep.
2449 // Driver desire does not prevent demand sleep.
2451 changePowerStateTo(ON_STATE
);
2453 else if ((oldCount
!= 0) && (newCount
== 0))
2455 // Last driver removed from prevent list.
2456 // Drop the driver clamp to allow idle sleep.
2458 changePowerStateTo(SLEEP_STATE
);
2459 evaluatePolicy( kStimulusNoIdleSleepPreventers
);
2461 messageClient(kIOPMMessageIdleSleepPreventers
, systemCapabilityNotifier
,
2462 &newCount
, sizeof(newCount
));
2464 #if defined(__i386__) || defined(__x86_64__)
2465 if (addNotRemove
&& (service
== wrangler
) && !checkSystemCanSustainFullWake())
2467 return false; // do not idle-cancel
2474 //******************************************************************************
2475 // preventSystemSleepListUpdate
2477 // Called by IOService on PM work loop.
2478 //******************************************************************************
2480 void IOPMrootDomain::updatePreventSystemSleepList(
2481 IOService
* service
, bool addNotRemove
)
2483 unsigned int oldCount
, newCount
;
2486 if (this == service
)
2489 oldCount
= preventSystemSleepList
->getCount();
2492 preventSystemSleepList
->setObject(service
);
2493 DLOG("prevent system sleep list: %s+ (%u)\n",
2494 service
->getName(), preventSystemSleepList
->getCount());
2495 if (!assertOnWakeSecs
&& systemWakeTime
) {
2497 clock_usec_t microsecs
;
2498 clock_get_uptime(&now
);
2499 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
2500 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
2501 if (assertOnWakeReport
) {
2502 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
2503 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
2507 else if (preventSystemSleepList
->member(service
))
2509 preventSystemSleepList
->removeObject(service
);
2510 DLOG("prevent system sleep list: %s- (%u)\n",
2511 service
->getName(), preventSystemSleepList
->getCount());
2513 if ((oldCount
!= 0) && (preventSystemSleepList
->getCount() == 0))
2515 // Lost all system sleep preventers.
2516 // Send stimulus if system sleep was blocked, and is in dark wake.
2517 evaluatePolicy( kStimulusDarkWakeEvaluate
);
2520 newCount
= preventSystemSleepList
->getCount();
2521 messageClient(kIOPMMessageSystemSleepPreventers
, systemCapabilityNotifier
,
2522 &newCount
, sizeof(newCount
));
2525 void IOPMrootDomain::copySleepPreventersList(OSArray
**idleSleepList
, OSArray
**systemSleepList
)
2528 OSCollectionIterator
*iterator
= NULL
;
2529 OSObject
*object
= NULL
;
2530 OSArray
*array
= NULL
;
2532 if (!getPMworkloop()->inGate())
2534 getPMworkloop()->runAction(
2535 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2536 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersList
),
2537 this, (void *)idleSleepList
, (void *)systemSleepList
);
2541 if (idleSleepList
&& preventIdleSleepList
&& (preventIdleSleepList
->getCount() != 0))
2543 iterator
= OSCollectionIterator::withCollection(preventIdleSleepList
);
2544 array
= OSArray::withCapacity(5);
2546 while ((object
= iterator
->getNextObject()))
2548 IOService
*service
= OSDynamicCast(IOService
, object
);
2551 array
->setObject(OSSymbol::withCString(service
->getName()));
2555 iterator
->release();
2556 *idleSleepList
= array
;
2559 if (systemSleepList
&& preventSystemSleepList
&& (preventSystemSleepList
->getCount() != 0))
2561 iterator
= OSCollectionIterator::withCollection(preventSystemSleepList
);
2562 array
= OSArray::withCapacity(5);
2564 while ((object
= iterator
->getNextObject()))
2566 IOService
*service
= OSDynamicCast(IOService
, object
);
2569 array
->setObject(OSSymbol::withCString(service
->getName()));
2573 iterator
->release();
2574 *systemSleepList
= array
;
2578 //******************************************************************************
2581 // Override the superclass implementation to send a different message type.
2582 //******************************************************************************
2584 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
2586 DLOG("tellChangeDown %u->%u\n",
2587 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2589 if (SLEEP_STATE
== stateNum
)
2591 // Legacy apps were already told in the full->dark transition
2592 if (!ignoreTellChangeDown
)
2593 tracePoint( kIOPMTracePointSleepApplications
);
2595 tracePoint( kIOPMTracePointSleepPriorityClients
);
2598 if ((SLEEP_STATE
== stateNum
) && !ignoreTellChangeDown
)
2600 userActivityAtSleep
= userActivityCount
;
2601 hibernateAborted
= false;
2602 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
2604 // Direct callout into OSKext so it can disable kext unloads
2605 // during sleep/wake to prevent deadlocks.
2606 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
2608 IOService::updateConsoleUsers(NULL
, kIOMessageSystemWillSleep
);
2610 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2611 // But tellClientsWithResponse() must be called for both.
2612 ignoreTellChangeDown
= true;
2615 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
2618 //******************************************************************************
2621 // Override the superclass implementation to send a different message type.
2622 // This must be idle sleep since we don't ask during any other power change.
2623 //******************************************************************************
2625 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
2627 DLOG("askChangeDown %u->%u\n",
2628 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2630 // Don't log for dark wake entry
2631 if (kSystemTransitionSleep
== _systemTransitionType
)
2632 tracePoint( kIOPMTracePointSleepApplications
);
2634 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
2637 //******************************************************************************
2638 // askChangeDownDone
2640 // An opportunity for root domain to cancel the power transition,
2641 // possibily due to an assertion created by powerd in response to
2642 // kIOMessageCanSystemSleep.
2645 // full -> dark wake transition
2646 // 1. Notify apps and powerd with kIOMessageCanSystemSleep
2647 // 2. askChangeDownDone()
2648 // dark -> sleep transition
2649 // 1. Notify powerd with kIOMessageCanSystemSleep
2650 // 2. askChangeDownDone()
2653 // full -> dark wake transition
2654 // 1. Notify powerd with kIOMessageCanSystemSleep
2655 // 2. askChangeDownDone()
2656 // dark -> sleep transition
2657 // 1. Notify powerd with kIOMessageCanSystemSleep
2658 // 2. askChangeDownDone()
2659 //******************************************************************************
2661 void IOPMrootDomain::askChangeDownDone(
2662 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
2664 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2665 *inOutChangeFlags
, *cancel
,
2666 _systemTransitionType
,
2667 _currentCapability
, _pendingCapability
);
2669 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
))
2671 // Dark->Sleep transition.
2672 // Check if there are any deny sleep assertions.
2673 // lastSleepReason already set by handleOurPowerChangeStart()
2675 if (!checkSystemCanSleep(lastSleepReason
))
2677 // Cancel dark wake to sleep transition.
2678 // Must re-scan assertions upon entering dark wake.
2681 DLOG("cancel dark->sleep\n");
2686 //******************************************************************************
2687 // systemDidNotSleep
2689 // Work common to both canceled or aborted sleep.
2690 //******************************************************************************
2692 void IOPMrootDomain::systemDidNotSleep( void )
2694 // reset console lock state
2695 thread_call_enter(updateConsoleUsersEntry
);
2701 // stay awake for at least idleSeconds
2702 startIdleSleepTimer(idleSeconds
);
2707 if (sleepSlider
&& !userIsActive
)
2709 // Manually start the idle sleep timer besides waiting for
2710 // the user to become inactive.
2711 startIdleSleepTimer( kIdleSleepRetryInterval
);
2715 preventTransitionToUserActive(false);
2716 IOService::setAdvisoryTickleEnable( true );
2718 // After idle revert and cancel, send a did-change message to powerd
2719 // to balance the previous will-change message. Kernel clients do not
2720 // need this since sleep cannot be canceled once they are notified.
2722 if (toldPowerdCapWillChange
&& systemCapabilityNotifier
&&
2723 (_pendingCapability
!= _currentCapability
) &&
2724 ((_systemMessageClientMask
& kSystemMessageClientPowerd
) != 0))
2726 // Differs from a real capability gain change where notifyRef != 0,
2727 // but it is zero here since no response is expected.
2729 IOPMSystemCapabilityChangeParameters params
;
2731 bzero(¶ms
, sizeof(params
));
2732 params
.fromCapabilities
= _pendingCapability
;
2733 params
.toCapabilities
= _currentCapability
;
2734 params
.changeFlags
= kIOPMSystemCapabilityDidChange
;
2736 DLOG("MESG cap %x->%x did change\n",
2737 params
.fromCapabilities
, params
.toCapabilities
);
2738 messageClient(kIOMessageSystemCapabilityChange
, systemCapabilityNotifier
,
2739 ¶ms
, sizeof(params
));
2743 //******************************************************************************
2746 // Notify registered applications and kernel clients that we are not dropping
2749 // We override the superclass implementation so we can send a different message
2750 // type to the client or application being notified.
2752 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2753 //******************************************************************************
2755 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
2757 DLOG("tellNoChangeDown %u->%u\n",
2758 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2760 // Sleep canceled, clear the sleep trace point.
2761 tracePoint(kIOPMTracePointSystemUp
);
2763 systemDidNotSleep();
2764 return tellClients( kIOMessageSystemWillNotSleep
);
2767 //******************************************************************************
2770 // Notify registered applications and kernel clients that we are raising power.
2772 // We override the superclass implementation so we can send a different message
2773 // type to the client or application being notified.
2774 //******************************************************************************
2776 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
2778 DLOG("tellChangeUp %u->%u\n",
2779 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2781 ignoreTellChangeDown
= false;
2783 if ( stateNum
== ON_STATE
)
2785 // Direct callout into OSKext so it can disable kext unloads
2786 // during sleep/wake to prevent deadlocks.
2787 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
2789 // Notify platform that sleep was cancelled or resumed.
2790 getPlatform()->callPlatformFunction(
2791 sleepMessagePEFunction
, false,
2792 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
2795 if (getPowerState() == ON_STATE
)
2797 // this is a quick wake from aborted sleep
2798 systemDidNotSleep();
2799 tellClients( kIOMessageSystemWillPowerOn
);
2802 tracePoint( kIOPMTracePointWakeApplications
);
2803 tellClients( kIOMessageSystemHasPoweredOn
);
2807 //******************************************************************************
2808 // sysPowerDownHandler
2810 // Perform a vfs sync before system sleep.
2811 //******************************************************************************
2813 IOReturn
IOPMrootDomain::sysPowerDownHandler(
2814 void * target
, void * refCon
,
2815 UInt32 messageType
, IOService
* service
,
2816 void * messageArgs
, vm_size_t argSize
)
2820 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
2823 return kIOReturnUnsupported
;
2825 if (messageType
== kIOMessageSystemWillSleep
)
2828 static int32_t mem_only
= -1;
2829 IOPowerStateChangeNotification
*notify
=
2830 (IOPowerStateChangeNotification
*)messageArgs
;
2832 if ((mem_only
== -1) &&
2833 (PE_parse_boot_argn("swd_mem_only", &mem_only
, sizeof(mem_only
)) == false)) {
2836 if ((mem_only
!= 1) && (gRootDomain
->sleepWakeDebugIsWdogEnabled()))
2838 notify
->returnValue
= 30 * 1000 * 1000;
2840 gRootDomain
->hibDebugSetupEntry
,
2841 (thread_call_param_t
)(uintptr_t) notify
->powerRef
);
2845 else if (messageType
== kIOMessageSystemCapabilityChange
)
2847 IOPMSystemCapabilityChangeParameters
* params
=
2848 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
2850 // Interested applications have been notified of an impending power
2851 // change and have acked (when applicable).
2852 // This is our chance to save whatever state we can before powering
2854 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2857 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
2858 params
->fromCapabilities
, params
->toCapabilities
,
2859 params
->changeFlags
);
2861 if ((params
->changeFlags
& kIOPMSystemCapabilityWillChange
) &&
2862 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) &&
2863 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2865 // We will ack within 20 seconds
2866 params
->maxWaitForReply
= 20 * 1000 * 1000;
2868 gRootDomain
->evaluateSystemSleepPolicyEarly();
2870 // add in time we could spend freeing pages
2871 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
)
2873 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
2875 DLOG("sysPowerDownHandler max wait %d s\n",
2876 (int) (params
->maxWaitForReply
/ 1000 / 1000));
2879 // Notify platform that sleep has begun, after the early
2880 // sleep policy evaluation.
2881 getPlatform()->callPlatformFunction(
2882 sleepMessagePEFunction
, false,
2883 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
2886 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
2888 // Purposely delay the ack and hope that shutdown occurs quickly.
2889 // Another option is not to schedule the thread and wait for
2891 AbsoluteTime deadline
;
2892 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
2893 thread_call_enter1_delayed(
2894 gRootDomain
->diskSyncCalloutEntry
,
2895 (thread_call_param_t
)(uintptr_t) params
->notifyRef
,
2900 gRootDomain
->diskSyncCalloutEntry
,
2901 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
2904 if ((params
->changeFlags
& kIOPMSystemCapabilityDidChange
) &&
2905 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) &&
2906 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2909 // We will ack within 110 seconds
2910 params
->maxWaitForReply
= 110 * 1000 * 1000;
2913 gRootDomain
->diskSyncCalloutEntry
,
2914 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
2917 ret
= kIOReturnSuccess
;
2923 //******************************************************************************
2924 // handleQueueSleepWakeUUID
2926 // Called from IOPMrootDomain when we're initiating a sleep,
2927 // or indirectly from PM configd when PM decides to clear the UUID.
2928 // PM clears the UUID several minutes after successful wake from sleep,
2929 // so that we might associate App spindumps with the immediately previous
2932 // @param obj has a retain on it. We're responsible for releasing that retain.
2933 //******************************************************************************
2935 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
2937 OSString
*str
= NULL
;
2939 if (kOSBooleanFalse
== obj
)
2941 handlePublishSleepWakeUUID(NULL
);
2943 else if ((str
= OSDynamicCast(OSString
, obj
)))
2945 // This branch caches the UUID for an upcoming sleep/wake
2946 if (queuedSleepWakeUUIDString
) {
2947 queuedSleepWakeUUIDString
->release();
2948 queuedSleepWakeUUIDString
= NULL
;
2950 queuedSleepWakeUUIDString
= str
;
2951 queuedSleepWakeUUIDString
->retain();
2953 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
2962 //******************************************************************************
2963 // handlePublishSleepWakeUUID
2965 // Called from IOPMrootDomain when we're initiating a sleep,
2966 // or indirectly from PM configd when PM decides to clear the UUID.
2967 // PM clears the UUID several minutes after successful wake from sleep,
2968 // so that we might associate App spindumps with the immediately previous
2970 //******************************************************************************
2972 void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
2977 * Clear the current UUID
2979 if (gSleepWakeUUIDIsSet
)
2981 DLOG("SleepWake UUID cleared\n");
2983 gSleepWakeUUIDIsSet
= false;
2985 removeProperty(kIOPMSleepWakeUUIDKey
);
2986 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
2990 * Optionally, publish a new UUID
2992 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
2994 OSString
*publishThisUUID
= NULL
;
2996 publishThisUUID
= queuedSleepWakeUUIDString
;
2997 publishThisUUID
->retain();
2999 if (publishThisUUID
)
3001 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
);
3002 publishThisUUID
->release();
3005 gSleepWakeUUIDIsSet
= true;
3006 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
3008 queuedSleepWakeUUIDString
->release();
3009 queuedSleepWakeUUIDString
= NULL
;
3013 //******************************************************************************
3014 // initializeBootSessionUUID
3016 // Initialize the boot session uuid at boot up and sets it into registry.
3017 //******************************************************************************
3019 void IOPMrootDomain::initializeBootSessionUUID(void)
3022 uuid_string_t new_uuid_string
;
3024 uuid_generate(new_uuid
);
3025 uuid_unparse_upper(new_uuid
, new_uuid_string
);
3026 memcpy(bootsessionuuid_string
, new_uuid_string
, sizeof(uuid_string_t
));
3028 setProperty(kIOPMBootSessionUUIDKey
, new_uuid_string
);
3031 //******************************************************************************
3032 // changePowerStateTo & changePowerStateToPriv
3034 // Override of these methods for logging purposes.
3035 //******************************************************************************
3037 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
3039 DLOG("changePowerStateTo(%lu)\n", ordinal
);
3041 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3042 return kIOReturnUnsupported
;
3044 return super::changePowerStateTo(ordinal
);
3047 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
3049 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
3051 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3052 return kIOReturnUnsupported
;
3054 return super::changePowerStateToPriv(ordinal
);
3057 //******************************************************************************
3060 //******************************************************************************
3062 bool IOPMrootDomain::activitySinceSleep(void)
3064 return (userActivityCount
!= userActivityAtSleep
);
3067 bool IOPMrootDomain::abortHibernation(void)
3069 bool ret
= activitySinceSleep();
3071 if (ret
&& !hibernateAborted
&& checkSystemCanSustainFullWake())
3073 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
3074 hibernateAborted
= true;
3080 hibernate_should_abort(void)
3083 return (gRootDomain
->abortHibernation());
3088 //******************************************************************************
3089 // willNotifyPowerChildren
3091 // Called after all interested drivers have all acknowledged the power change,
3092 // but before any power children is informed. Dispatched though a thread call,
3093 // so it is safe to perform work that might block on a sleeping disk. PM state
3094 // machine (not thread) will block w/o timeout until this function returns.
3095 //******************************************************************************
3097 void IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState
)
3102 if (SLEEP_STATE
== newPowerState
)
3104 if (!tasksSuspended
)
3106 AbsoluteTime deadline
;
3107 tasksSuspended
= TRUE
;
3108 tasks_system_suspend(tasksSuspended
);
3110 clock_interval_to_deadline(10, kSecondScale
, &deadline
);
3111 vm_pageout_wait(AbsoluteTime_to_scalar(&deadline
));
3115 IOHibernateSystemSleep();
3116 IOHibernateIOKitSleep();
3118 if (gRootDomain
->activitySinceSleep()) {
3119 dict
= OSDictionary::withCapacity(1);
3120 secs
= OSNumber::withNumber(1, 32);
3123 dict
->setObject(gIOPMSettingDebugWakeRelativeKey
, secs
);
3124 gRootDomain
->setProperties(dict
);
3125 MSG("Reverting sleep with relative wake\n");
3127 if (dict
) dict
->release();
3128 if (secs
) secs
->release();
3134 //******************************************************************************
3135 // sleepOnClamshellClosed
3137 // contains the logic to determine if the system should sleep when the clamshell
3139 //******************************************************************************
3141 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
3143 if (!clamshellExists
)
3146 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
3147 clamshellClosed
, clamshellDisabled
, desktopMode
, acAdaptorConnected
, clamshellSleepDisabled
);
3149 return ( !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) && !clamshellSleepDisabled
);
3152 void IOPMrootDomain::sendClientClamshellNotification( void )
3154 /* Only broadcast clamshell alert if clamshell exists. */
3155 if (!clamshellExists
)
3158 setProperty(kAppleClamshellStateKey
,
3159 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
3161 setProperty(kAppleClamshellCausesSleepKey
,
3162 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
3164 /* Argument to message is a bitfiel of
3165 * ( kClamshellStateBit | kClamshellSleepBit )
3167 messageClients(kIOPMMessageClamshellStateChange
,
3168 (void *)(uintptr_t) ( (clamshellClosed
? kClamshellStateBit
: 0)
3169 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
3172 //******************************************************************************
3173 // getSleepSupported
3176 //******************************************************************************
3178 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
3180 return( platformSleepSupport
);
3183 //******************************************************************************
3184 // setSleepSupported
3187 //******************************************************************************
3189 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
3191 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
3192 OSBitOrAtomic(flags
, &platformSleepSupport
);
3195 //******************************************************************************
3196 // setDisableClamShellSleep
3198 //******************************************************************************
3200 void IOPMrootDomain::setDisableClamShellSleep( bool val
)
3202 if (gIOPMWorkLoop
->inGate() == false) {
3204 gIOPMWorkLoop
->runAction(
3205 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setDisableClamShellSleep
),
3212 DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val
);
3213 if ( clamshellSleepDisabled
!= val
)
3215 clamshellSleepDisabled
= val
;
3216 // If clamshellSleepDisabled is reset to 0, reevaluate if
3217 // system need to go to sleep due to clamshell state
3218 if ( !clamshellSleepDisabled
&& clamshellClosed
)
3219 handlePowerNotification(kLocalEvalClamshellCommand
);
3224 //******************************************************************************
3228 //******************************************************************************
3230 void IOPMrootDomain::wakeFromDoze( void )
3232 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
3238 //******************************************************************************
3241 // Adds a new feature to the supported features dictionary
3242 //******************************************************************************
3244 void IOPMrootDomain::publishFeature( const char * feature
)
3246 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
3249 //******************************************************************************
3250 // publishFeature (with supported power source specified)
3252 // Adds a new feature to the supported features dictionary
3253 //******************************************************************************
3255 void IOPMrootDomain::publishFeature(
3256 const char *feature
,
3257 uint32_t supportedWhere
,
3258 uint32_t *uniqueFeatureID
)
3260 static uint16_t next_feature_id
= 500;
3262 OSNumber
*new_feature_data
= NULL
;
3263 OSNumber
*existing_feature
= NULL
;
3264 OSArray
*existing_feature_arr
= NULL
;
3265 OSObject
*osObj
= NULL
;
3266 uint32_t feature_value
= 0;
3268 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
3270 if(!supportedWhere
) {
3271 // Feature isn't supported anywhere!
3275 if(next_feature_id
> 5000) {
3276 // Far, far too many features!
3280 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3282 OSDictionary
*features
=
3283 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3285 // Create new features dict if necessary
3286 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
3287 features
= OSDictionary::withDictionary(features
);
3289 features
= OSDictionary::withCapacity(1);
3292 // Create OSNumber to track new feature
3294 next_feature_id
+= 1;
3295 if( uniqueFeatureID
) {
3296 // We don't really mind if the calling kext didn't give us a place
3297 // to stash their unique id. Many kexts don't plan to unload, and thus
3298 // have no need to remove themselves later.
3299 *uniqueFeatureID
= next_feature_id
;
3302 feature_value
= (uint32_t)next_feature_id
;
3303 feature_value
<<= 16;
3304 feature_value
+= supportedWhere
;
3306 new_feature_data
= OSNumber::withNumber(
3307 (unsigned long long)feature_value
, 32);
3309 // Does features object already exist?
3310 if( (osObj
= features
->getObject(feature
)) )
3312 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
3314 // We need to create an OSArray to hold the now 2 elements.
3315 existing_feature_arr
= OSArray::withObjects(
3316 (const OSObject
**)&existing_feature
, 1, 2);
3317 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
3319 // Add object to existing array
3320 existing_feature_arr
= OSArray::withArray(
3321 existing_feature_arr
,
3322 existing_feature_arr
->getCount() + 1);
3325 if (existing_feature_arr
)
3327 existing_feature_arr
->setObject(new_feature_data
);
3328 features
->setObject(feature
, existing_feature_arr
);
3329 existing_feature_arr
->release();
3330 existing_feature_arr
= 0;
3333 // The easy case: no previously existing features listed. We simply
3334 // set the OSNumber at key 'feature' and we're on our way.
3335 features
->setObject(feature
, new_feature_data
);
3338 new_feature_data
->release();
3340 setProperty(kRootDomainSupportedFeatures
, features
);
3342 features
->release();
3344 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3346 // Notify EnergySaver and all those in user space so they might
3347 // re-populate their feature specific UI
3348 if(pmPowerStateQueue
) {
3349 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3353 //******************************************************************************
3354 // removePublishedFeature
3356 // Removes previously published feature
3357 //******************************************************************************
3359 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
3361 IOReturn ret
= kIOReturnError
;
3362 uint32_t feature_value
= 0;
3363 uint16_t feature_id
= 0;
3364 bool madeAChange
= false;
3366 OSSymbol
*dictKey
= NULL
;
3367 OSCollectionIterator
*dictIterator
= NULL
;
3368 OSArray
*arrayMember
= NULL
;
3369 OSNumber
*numberMember
= NULL
;
3370 OSObject
*osObj
= NULL
;
3371 OSNumber
*osNum
= NULL
;
3372 OSArray
*arrayMemberCopy
;
3374 if (kBadPMFeatureID
== removeFeatureID
)
3375 return kIOReturnNotFound
;
3377 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3379 OSDictionary
*features
=
3380 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3382 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
3384 // Any modifications to the dictionary are made to the copy to prevent
3385 // races & crashes with userland clients. Dictionary updated
3386 // automically later.
3387 features
= OSDictionary::withDictionary(features
);
3390 ret
= kIOReturnNotFound
;
3394 // We iterate 'features' dictionary looking for an entry tagged
3395 // with 'removeFeatureID'. If found, we remove it from our tracking
3396 // structures and notify the OS via a general interest message.
3398 dictIterator
= OSCollectionIterator::withCollection(features
);
3403 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
3405 osObj
= features
->getObject(dictKey
);
3407 // Each Feature is either tracked by an OSNumber
3408 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
3410 feature_value
= numberMember
->unsigned32BitValue();
3411 feature_id
= (uint16_t)(feature_value
>> 16);
3413 if( feature_id
== (uint16_t)removeFeatureID
)
3416 features
->removeObject(dictKey
);
3421 // Or tracked by an OSArray of OSNumbers
3422 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
3424 unsigned int arrayCount
= arrayMember
->getCount();
3426 for(unsigned int i
=0; i
<arrayCount
; i
++)
3428 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
3433 feature_value
= osNum
->unsigned32BitValue();
3434 feature_id
= (uint16_t)(feature_value
>> 16);
3436 if( feature_id
== (uint16_t)removeFeatureID
)
3439 if( 1 == arrayCount
) {
3440 // If the array only contains one element, remove
3442 features
->removeObject(dictKey
);
3444 // Otherwise remove the element from a copy of the array.
3445 arrayMemberCopy
= OSArray::withArray(arrayMember
);
3446 if (arrayMemberCopy
)
3448 arrayMemberCopy
->removeObject(i
);
3449 features
->setObject(dictKey
, arrayMemberCopy
);
3450 arrayMemberCopy
->release();
3461 dictIterator
->release();
3465 ret
= kIOReturnSuccess
;
3467 setProperty(kRootDomainSupportedFeatures
, features
);
3469 // Notify EnergySaver and all those in user space so they might
3470 // re-populate their feature specific UI
3471 if(pmPowerStateQueue
) {
3472 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3475 ret
= kIOReturnNotFound
;
3479 if(features
) features
->release();
3480 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3484 //******************************************************************************
3485 // publishPMSetting (private)
3487 // Should only be called by PMSettingObject to publish a PM Setting as a
3488 // supported feature.
3489 //******************************************************************************
3491 void IOPMrootDomain::publishPMSetting(
3492 const OSSymbol
* feature
, uint32_t where
, uint32_t * featureID
)
3494 if (noPublishPMSettings
&&
3495 (noPublishPMSettings
->getNextIndexOfObject(feature
, 0) != (unsigned int)-1))
3497 // Setting found in noPublishPMSettings array
3498 *featureID
= kBadPMFeatureID
;
3503 feature
->getCStringNoCopy(), where
, featureID
);
3506 //******************************************************************************
3507 // setPMSetting (private)
3509 // Internal helper to relay PM settings changes from user space to individual
3510 // drivers. Should be called only by IOPMrootDomain::setProperties.
3511 //******************************************************************************
3513 IOReturn
IOPMrootDomain::setPMSetting(
3514 const OSSymbol
*type
,
3517 PMSettingCallEntry
*entries
= 0;
3518 OSArray
*chosen
= 0;
3519 const OSArray
*array
;
3520 PMSettingObject
*pmso
;
3521 thread_t thisThread
;
3522 int i
, j
, count
, capacity
;
3525 return kIOReturnBadArgument
;
3529 // Update settings dict so changes are visible from copyPMSetting().
3530 fPMSettingsDict
->setObject(type
, object
);
3532 // Prep all PMSetting objects with the given 'type' for callout.
3533 array
= (const OSArray
*) settingsCallbacks
->getObject(type
);
3534 if (!array
|| ((capacity
= array
->getCount()) == 0))
3537 // Array to retain PMSetting objects targeted for callout.
3538 chosen
= OSArray::withCapacity(capacity
);
3540 goto unlock_exit
; // error
3542 entries
= IONew(PMSettingCallEntry
, capacity
);
3544 goto unlock_exit
; // error
3545 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
3547 thisThread
= current_thread();
3549 for (i
= 0, j
= 0; i
<capacity
; i
++)
3551 pmso
= (PMSettingObject
*) array
->getObject(i
);
3554 entries
[j
].thread
= thisThread
;
3555 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
3556 chosen
->setObject(pmso
);
3565 // Call each pmso in the chosen array.
3566 for (i
=0; i
<count
; i
++)
3568 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3569 pmso
->dispatchPMSetting(type
, object
);
3573 for (i
=0; i
<count
; i
++)
3575 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3576 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
3577 if (pmso
->waitThread
)
3579 PMSETTING_WAKEUP(pmso
);
3585 if (chosen
) chosen
->release();
3586 if (entries
) IODelete(entries
, PMSettingCallEntry
, capacity
);
3588 return kIOReturnSuccess
;
3591 //******************************************************************************
3592 // copyPMSetting (public)
3594 // Allows kexts to safely read setting values, without being subscribed to
3596 //******************************************************************************
3598 OSObject
* IOPMrootDomain::copyPMSetting(
3599 OSSymbol
*whichSetting
)
3601 OSObject
*obj
= NULL
;
3603 if(!whichSetting
) return NULL
;
3606 obj
= fPMSettingsDict
->getObject(whichSetting
);
3615 //******************************************************************************
3616 // registerPMSettingController (public)
3618 // direct wrapper to registerPMSettingController with uint32_t power source arg
3619 //******************************************************************************
3621 IOReturn
IOPMrootDomain::registerPMSettingController(
3622 const OSSymbol
* settings
[],
3623 IOPMSettingControllerCallback func
,
3628 return registerPMSettingController(
3630 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
3631 func
, target
, refcon
, handle
);
3634 //******************************************************************************
3635 // registerPMSettingController (public)
3637 // Kexts may register for notifications when a particular setting is changed.
3638 // A list of settings is available in IOPM.h.
3640 // * settings - An OSArray containing OSSymbols. Caller should populate this
3641 // array with a list of settings caller wants notifications from.
3642 // * func - A C function callback of the type IOPMSettingControllerCallback
3643 // * target - caller may provide an OSObject *, which PM will pass as an
3644 // target to calls to "func"
3645 // * refcon - caller may provide an void *, which PM will pass as an
3646 // argument to calls to "func"
3647 // * handle - This is a return argument. We will populate this pointer upon
3648 // call success. Hold onto this and pass this argument to
3649 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3651 // kIOReturnSuccess on success
3652 //******************************************************************************
3654 IOReturn
IOPMrootDomain::registerPMSettingController(
3655 const OSSymbol
* settings
[],
3656 uint32_t supportedPowerSources
,
3657 IOPMSettingControllerCallback func
,
3662 PMSettingObject
*pmso
= NULL
;
3663 OSObject
*pmsh
= NULL
;
3664 OSArray
*list
= NULL
;
3667 if (NULL
== settings
||
3671 return kIOReturnBadArgument
;
3674 pmso
= PMSettingObject::pmSettingObject(
3675 (IOPMrootDomain
*) this, func
, target
,
3676 refcon
, supportedPowerSources
, settings
, &pmsh
);
3680 return kIOReturnInternalError
;
3684 for (i
=0; settings
[i
]; i
++)
3686 list
= (OSArray
*) settingsCallbacks
->getObject(settings
[i
]);
3688 // New array of callbacks for this setting
3689 list
= OSArray::withCapacity(1);
3690 settingsCallbacks
->setObject(settings
[i
], list
);
3694 // Add caller to the callback list
3695 list
->setObject(pmso
);
3699 // Return handle to the caller, the setting object is private.
3702 return kIOReturnSuccess
;
3705 //******************************************************************************
3706 // deregisterPMSettingObject (private)
3708 // Only called from PMSettingObject.
3709 //******************************************************************************
3711 void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
3713 thread_t thisThread
= current_thread();
3714 PMSettingCallEntry
*callEntry
;
3715 OSCollectionIterator
*iter
;
3723 pmso
->disabled
= true;
3725 // Wait for all callout threads to finish.
3728 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
3730 if (callEntry
->thread
!= thisThread
)
3738 assert(0 == pmso
->waitThread
);
3739 pmso
->waitThread
= thisThread
;
3740 PMSETTING_WAIT(pmso
);
3741 pmso
->waitThread
= 0;
3745 // Search each PM settings array in the kernel.
3746 iter
= OSCollectionIterator::withCollection(settingsCallbacks
);
3749 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
3751 array
= (OSArray
*) settingsCallbacks
->getObject(sym
);
3752 index
= array
->getNextIndexOfObject(pmso
, 0);
3754 array
->removeObject(index
);
3765 //******************************************************************************
3766 // informCPUStateChange
3768 // Call into PM CPU code so that CPU power savings may dynamically adjust for
3769 // running on battery, with the lid closed, etc.
3771 // informCPUStateChange is a no-op on non x86 systems
3772 // only x86 has explicit support in the IntelCPUPowerManagement kext
3773 //******************************************************************************
3775 void IOPMrootDomain::informCPUStateChange(
3779 #if defined(__i386__) || defined(__x86_64__)
3781 pmioctlVariableInfo_t varInfoStruct
;
3783 const char *varNameStr
= NULL
;
3784 int32_t *varIndex
= NULL
;
3786 if (kInformAC
== type
) {
3787 varNameStr
= kIOPMRootDomainBatPowerCString
;
3788 varIndex
= &idxPMCPULimitedPower
;
3789 } else if (kInformLid
== type
) {
3790 varNameStr
= kIOPMRootDomainLidCloseCString
;
3791 varIndex
= &idxPMCPUClamshell
;
3796 // Set the new value!
3797 // pmCPUControl will assign us a new ID if one doesn't exist yet
3798 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
3799 varInfoStruct
.varID
= *varIndex
;
3800 varInfoStruct
.varType
= vBool
;
3801 varInfoStruct
.varInitValue
= value
;
3802 varInfoStruct
.varCurValue
= value
;
3803 strncpy( (char *)varInfoStruct
.varName
,
3804 (const char *)varNameStr
,
3805 strlen(varNameStr
) + 1 );
3808 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
3810 // pmCPU only assigns numerical id's when a new varName is specified
3812 && (*varIndex
== kCPUUnknownIndex
))
3814 // pmCPUControl has assigned us a new variable ID.
3815 // Let's re-read the structure we just SET to learn that ID.
3816 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
3820 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
3821 *varIndex
= varInfoStruct
.varID
;
3827 #endif /* __i386__ || __x86_64__ */
3831 // MARK: Deep Sleep Policy
3835 //******************************************************************************
3836 // evaluateSystemSleepPolicy
3837 //******************************************************************************
3839 #define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
3843 kIOPMSleepFlagHibernate
= 0x00000001,
3844 kIOPMSleepFlagSleepTimerEnable
= 0x00000002
3847 struct IOPMSystemSleepPolicyEntry
3849 uint32_t factorMask
;
3850 uint32_t factorBits
;
3851 uint32_t sleepFlags
;
3852 uint32_t wakeEvents
;
3853 } __attribute__((packed
));
3855 struct IOPMSystemSleepPolicyTable
3859 uint16_t entryCount
;
3860 IOPMSystemSleepPolicyEntry entries
[];
3861 } __attribute__((packed
));
3864 kIOPMSleepAttributeHibernateSetup
= 0x00000001,
3865 kIOPMSleepAttributeHibernateSleep
= 0x00000002
3869 getSleepTypeAttributes( uint32_t sleepType
)
3871 static const uint32_t sleepTypeAttributes
[ kIOPMSleepTypeLast
] =
3876 /* safesleep */ kIOPMSleepAttributeHibernateSetup
,
3877 /* hibernate */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3878 /* standby */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3879 /* poweroff */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3883 if (sleepType
>= kIOPMSleepTypeLast
)
3886 return sleepTypeAttributes
[sleepType
];
3889 bool IOPMrootDomain::evaluateSystemSleepPolicy(
3890 IOPMSystemSleepParameters
* params
, int sleepPhase
, uint32_t * hibMode
)
3892 const IOPMSystemSleepPolicyTable
* pt
;
3893 OSObject
* prop
= 0;
3894 OSData
* policyData
;
3895 uint64_t currentFactors
= 0;
3896 uint32_t standbyDelay
= 0;
3897 uint32_t powerOffDelay
= 0;
3898 uint32_t powerOffTimer
= 0;
3900 bool standbyEnabled
;
3901 bool powerOffEnabled
;
3904 // Get platform's sleep policy table
3905 if (!gSleepPolicyHandler
)
3907 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
3908 if (!prop
) goto done
;
3911 // Fetch additional settings
3912 standbyEnabled
= (getSleepOption(kIOPMDeepSleepDelayKey
, &standbyDelay
)
3913 && (getProperty(kIOPMDeepSleepEnabledKey
) == kOSBooleanTrue
));
3914 powerOffEnabled
= (getSleepOption(kIOPMAutoPowerOffDelayKey
, &powerOffDelay
)
3915 && (getProperty(kIOPMAutoPowerOffEnabledKey
) == kOSBooleanTrue
));
3916 if (!getSleepOption(kIOPMAutoPowerOffTimerKey
, &powerOffTimer
))
3917 powerOffTimer
= powerOffDelay
;
3919 DLOG("phase %d, standby %d delay %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
3920 sleepPhase
, standbyEnabled
, standbyDelay
,
3921 powerOffEnabled
, powerOffDelay
, powerOffTimer
, *hibMode
);
3923 // pmset level overrides
3924 if ((*hibMode
& kIOHibernateModeOn
) == 0)
3926 if (!gSleepPolicyHandler
)
3928 standbyEnabled
= false;
3929 powerOffEnabled
= false;
3932 else if (!(*hibMode
& kIOHibernateModeSleep
))
3934 // Force hibernate (i.e. mode 25)
3935 // If standby is enabled, force standy.
3936 // If poweroff is enabled, force poweroff.
3938 currentFactors
|= kIOPMSleepFactorStandbyForced
;
3939 else if (powerOffEnabled
)
3940 currentFactors
|= kIOPMSleepFactorAutoPowerOffForced
;
3942 currentFactors
|= kIOPMSleepFactorHibernateForced
;
3945 // Current factors based on environment and assertions
3946 if (sleepTimerMaintenance
)
3947 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
3948 if (standbyEnabled
&& sleepToStandby
&& !gSleepPolicyHandler
)
3949 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
3950 if (!clamshellClosed
)
3951 currentFactors
|= kIOPMSleepFactorLidOpen
;
3952 if (acAdaptorConnected
)
3953 currentFactors
|= kIOPMSleepFactorACPower
;
3954 if (lowBatteryCondition
)
3955 currentFactors
|= kIOPMSleepFactorBatteryLow
;
3957 currentFactors
|= kIOPMSleepFactorStandbyNoDelay
;
3958 if (!standbyEnabled
)
3959 currentFactors
|= kIOPMSleepFactorStandbyDisabled
;
3960 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
3961 kIOPMDriverAssertionLevelOff
)
3962 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
3963 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
3964 kIOPMDriverAssertionLevelOff
)
3965 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
3966 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
3967 kIOPMDriverAssertionLevelOff
)
3968 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
3969 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) !=
3970 kIOPMDriverAssertionLevelOff
)
3971 currentFactors
|= kIOPMSleepFactorThunderboltDevice
;
3972 if (_scheduledAlarms
!= 0)
3973 currentFactors
|= kIOPMSleepFactorRTCAlarmScheduled
;
3974 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit
) !=
3975 kIOPMDriverAssertionLevelOff
)
3976 currentFactors
|= kIOPMSleepFactorMagicPacketWakeEnabled
;
3977 #define TCPKEEPALIVE 1
3979 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit
) !=
3980 kIOPMDriverAssertionLevelOff
)
3981 currentFactors
|= kIOPMSleepFactorNetworkKeepAliveActive
;
3983 if (!powerOffEnabled
)
3984 currentFactors
|= kIOPMSleepFactorAutoPowerOffDisabled
;
3986 currentFactors
|= kIOPMSleepFactorExternalDisplay
;
3988 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
3989 if (darkWakeHibernateError
&& !CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
3990 currentFactors
|= kIOPMSleepFactorHibernateFailed
;
3991 if (thermalWarningState
)
3992 currentFactors
|= kIOPMSleepFactorThermalWarning
;
3994 DLOG("sleep factors 0x%llx\n", currentFactors
);
3996 if (gSleepPolicyHandler
)
3998 uint32_t savedHibernateMode
;
4001 if (!gSleepPolicyVars
)
4003 gSleepPolicyVars
= IONew(IOPMSystemSleepPolicyVariables
, 1);
4004 if (!gSleepPolicyVars
)
4006 bzero(gSleepPolicyVars
, sizeof(*gSleepPolicyVars
));
4008 gSleepPolicyVars
->signature
= kIOPMSystemSleepPolicySignature
;
4009 gSleepPolicyVars
->version
= kIOPMSystemSleepPolicyVersion
;
4010 gSleepPolicyVars
->currentCapability
= _currentCapability
;
4011 gSleepPolicyVars
->highestCapability
= _highestCapability
;
4012 gSleepPolicyVars
->sleepFactors
= currentFactors
;
4013 gSleepPolicyVars
->sleepReason
= lastSleepReason
;
4014 gSleepPolicyVars
->sleepPhase
= sleepPhase
;
4015 gSleepPolicyVars
->standbyDelay
= standbyDelay
;
4016 gSleepPolicyVars
->poweroffDelay
= powerOffDelay
;
4017 gSleepPolicyVars
->scheduledAlarms
= _scheduledAlarms
| _userScheduledAlarm
;
4018 gSleepPolicyVars
->poweroffTimer
= powerOffTimer
;
4020 if (kIOPMSleepPhase0
== sleepPhase
)
4022 // preserve hibernateMode
4023 savedHibernateMode
= gSleepPolicyVars
->hibernateMode
;
4024 gSleepPolicyVars
->hibernateMode
= *hibMode
;
4026 else if (kIOPMSleepPhase1
== sleepPhase
)
4028 // use original hibernateMode for phase2
4029 gSleepPolicyVars
->hibernateMode
= *hibMode
;
4032 result
= gSleepPolicyHandler(gSleepPolicyTarget
, gSleepPolicyVars
, params
);
4034 if (kIOPMSleepPhase0
== sleepPhase
)
4036 // restore hibernateMode
4037 gSleepPolicyVars
->hibernateMode
= savedHibernateMode
;
4040 if ((result
!= kIOReturnSuccess
) ||
4041 (kIOPMSleepTypeInvalid
== params
->sleepType
) ||
4042 (params
->sleepType
>= kIOPMSleepTypeLast
) ||
4043 (kIOPMSystemSleepParametersVersion
!= params
->version
))
4045 MSG("sleep policy handler error\n");
4049 if ((getSleepTypeAttributes(params
->sleepType
) &
4050 kIOPMSleepAttributeHibernateSetup
) &&
4051 ((*hibMode
& kIOHibernateModeOn
) == 0))
4053 *hibMode
|= (kIOHibernateModeOn
| kIOHibernateModeSleep
);
4056 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
4057 params
->version
, params
->sleepType
, params
->sleepFlags
,
4058 params
->ecWakeEvents
, params
->ecWakeTimer
, params
->ecPoweroffTimer
);
4063 // Policy table is meaningless without standby enabled
4064 if (!standbyEnabled
)
4067 // Validate the sleep policy table
4068 policyData
= OSDynamicCast(OSData
, prop
);
4069 if (!policyData
|| (policyData
->getLength() <= sizeof(IOPMSystemSleepPolicyTable
)))
4072 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
4073 if ((pt
->signature
!= kIOPMSystemSleepPolicySignature
) ||
4074 (pt
->version
!= 1) || (0 == pt
->entryCount
))
4077 if (((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
4078 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
)))
4081 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++)
4083 const IOPMSystemSleepPolicyEntry
* entry
= &pt
->entries
[i
];
4084 mismatch
= (((uint32_t)currentFactors
^ entry
->factorBits
) & entry
->factorMask
);
4086 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
4087 entry
->factorMask
, entry
->factorBits
,
4088 entry
->sleepFlags
, entry
->wakeEvents
, mismatch
);
4092 DLOG("^ found match\n");
4095 params
->version
= kIOPMSystemSleepParametersVersion
;
4096 params
->reserved1
= 1;
4097 if (entry
->sleepFlags
& kIOPMSleepFlagHibernate
)
4098 params
->sleepType
= kIOPMSleepTypeStandby
;
4100 params
->sleepType
= kIOPMSleepTypeNormalSleep
;
4102 params
->ecWakeEvents
= entry
->wakeEvents
;
4103 if (entry
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
)
4105 if (kIOPMSleepPhase2
== sleepPhase
)
4107 clock_sec_t now_secs
= gIOLastSleepTime
.tv_sec
;
4109 if (!_standbyTimerResetSeconds
||
4110 (now_secs
<= _standbyTimerResetSeconds
))
4112 // Reset standby timer adjustment
4113 _standbyTimerResetSeconds
= now_secs
;
4114 DLOG("standby delay %u, reset %u\n",
4115 standbyDelay
, (uint32_t) _standbyTimerResetSeconds
);
4117 else if (standbyDelay
)
4119 // Shorten the standby delay timer
4120 clock_sec_t elapsed
= now_secs
- _standbyTimerResetSeconds
;
4121 if (standbyDelay
> elapsed
)
4122 standbyDelay
-= elapsed
;
4124 standbyDelay
= 1; // must be > 0
4126 DLOG("standby delay %u, elapsed %u\n",
4127 standbyDelay
, (uint32_t) elapsed
);
4130 params
->ecWakeTimer
= standbyDelay
;
4132 else if (kIOPMSleepPhase2
== sleepPhase
)
4134 // A sleep that does not enable the sleep timer will reset
4135 // the standby delay adjustment.
4136 _standbyTimerResetSeconds
= 0;
4148 static IOPMSystemSleepParameters gEarlySystemSleepParams
;
4150 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
4152 // Evaluate early (priority interest phase), before drivers sleep.
4154 DLOG("%s\n", __FUNCTION__
);
4155 removeProperty(kIOPMSystemSleepParametersKey
);
4157 // Full wake resets the standby timer delay adjustment
4158 if (_highestCapability
& kIOPMSystemCapabilityGraphics
)
4159 _standbyTimerResetSeconds
= 0;
4161 hibernateDisabled
= false;
4163 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
4165 // Save for late evaluation if sleep is aborted
4166 bzero(&gEarlySystemSleepParams
, sizeof(gEarlySystemSleepParams
));
4168 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams
, kIOPMSleepPhase1
,
4171 if (!hibernateRetry
&&
4172 ((getSleepTypeAttributes(gEarlySystemSleepParams
.sleepType
) &
4173 kIOPMSleepAttributeHibernateSetup
) == 0))
4175 // skip hibernate setup
4176 hibernateDisabled
= true;
4180 // Publish IOPMSystemSleepType
4181 uint32_t sleepType
= gEarlySystemSleepParams
.sleepType
;
4182 if (sleepType
== kIOPMSleepTypeInvalid
)
4185 sleepType
= kIOPMSleepTypeNormalSleep
;
4186 if (hibernateMode
& kIOHibernateModeOn
)
4187 sleepType
= (hibernateMode
& kIOHibernateModeSleep
) ?
4188 kIOPMSleepTypeSafeSleep
: kIOPMSleepTypeHibernate
;
4190 else if ((sleepType
== kIOPMSleepTypeStandby
) &&
4191 (gEarlySystemSleepParams
.ecPoweroffTimer
))
4193 // report the lowest possible sleep state
4194 sleepType
= kIOPMSleepTypePowerOff
;
4197 setProperty(kIOPMSystemSleepTypeKey
, sleepType
, 32);
4200 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
4202 IOPMSystemSleepParameters params
;
4203 OSData
* paramsData
;
4205 // Evaluate sleep policy after sleeping drivers but before platform sleep.
4207 DLOG("%s\n", __FUNCTION__
);
4209 bzero(¶ms
, sizeof(params
));
4210 if (evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase2
, &hibernateMode
))
4212 if ((hibernateDisabled
|| hibernateAborted
) &&
4213 (getSleepTypeAttributes(params
.sleepType
) &
4214 kIOPMSleepAttributeHibernateSetup
))
4216 // Final evaluation picked a state requiring hibernation,
4217 // but hibernate setup was skipped. Arm a short sleep using
4218 // the early non-hibernate sleep parameters.
4219 // Set hibernateRetry flag to force hibernate setup on the
4222 bcopy(&gEarlySystemSleepParams
, ¶ms
, sizeof(params
));
4223 params
.sleepType
= kIOPMSleepTypeAbortedSleep
;
4224 params
.ecWakeTimer
= 1;
4225 hibernateRetry
= true;
4226 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d\n",
4227 params
.ecWakeTimer
, hibernateDisabled
, hibernateAborted
);
4231 hibernateRetry
= false;
4234 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
4237 setProperty(kIOPMSystemSleepParametersKey
, paramsData
);
4238 paramsData
->release();
4241 if (getSleepTypeAttributes(params
.sleepType
) &
4242 kIOPMSleepAttributeHibernateSleep
)
4244 // Disable sleep to force hibernation
4245 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
4250 bool IOPMrootDomain::getHibernateSettings(
4251 uint32_t * hibernateModePtr
,
4252 uint32_t * hibernateFreeRatio
,
4253 uint32_t * hibernateFreeTime
)
4255 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
4256 // has updated the hibernateDisabled flag.
4258 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateModePtr
);
4259 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
4260 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
4261 if (hibernateDisabled
)
4262 *hibernateModePtr
= 0;
4263 else if (gSleepPolicyHandler
)
4264 *hibernateModePtr
= hibernateMode
;
4265 DLOG("hibernateMode 0x%x\n", *hibernateModePtr
);
4269 bool IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
4271 OSObject
* optionsProp
;
4272 OSDictionary
* optionsDict
;
4277 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
4278 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
);
4282 obj
= optionsDict
->getObject(key
);
4283 if (obj
) obj
->retain();
4287 obj
= copyProperty(key
);
4291 if ((num
= OSDynamicCast(OSNumber
, obj
)))
4293 *option
= num
->unsigned32BitValue();
4296 else if (OSDynamicCast(OSBoolean
, obj
))
4298 *option
= (obj
== kOSBooleanTrue
) ? 1 : 0;
4306 optionsProp
->release();
4310 #endif /* HIBERNATION */
4312 IOReturn
IOPMrootDomain::getSystemSleepType( uint32_t * sleepType
)
4315 IOPMSystemSleepParameters params
;
4316 uint32_t hibMode
= 0;
4319 if (gIOPMWorkLoop
->inGate() == false)
4321 IOReturn ret
= gIOPMWorkLoop
->runAction(
4322 OSMemberFunctionCast(IOWorkLoop::Action
, this,
4323 &IOPMrootDomain::getSystemSleepType
),
4325 (void *) sleepType
);
4329 getSleepOption(kIOHibernateModeKey
, &hibMode
);
4330 bzero(¶ms
, sizeof(params
));
4332 ok
= evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase0
, &hibMode
);
4335 *sleepType
= params
.sleepType
;
4336 return kIOReturnSuccess
;
4340 return kIOReturnUnsupported
;
4344 // MARK: Shutdown and Restart
4346 //******************************************************************************
4347 // handlePlatformHaltRestart
4349 //******************************************************************************
4351 struct HaltRestartApplierContext
{
4352 IOPMrootDomain
* RootDomain
;
4353 unsigned long PowerState
;
4354 IOPMPowerFlags PowerFlags
;
4357 const char * LogString
;
4361 platformHaltRestartApplier( OSObject
* object
, void * context
)
4363 IOPowerStateChangeNotification notify
;
4364 HaltRestartApplierContext
* ctx
;
4365 AbsoluteTime startTime
;
4368 ctx
= (HaltRestartApplierContext
*) context
;
4370 memset(¬ify
, 0, sizeof(notify
));
4371 notify
.powerRef
= (void *)(uintptr_t)ctx
->Counter
;
4372 notify
.returnValue
= 0;
4373 notify
.stateNumber
= ctx
->PowerState
;
4374 notify
.stateFlags
= ctx
->PowerFlags
;
4376 clock_get_uptime(&startTime
);
4377 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
4378 deltaTime
= computeDeltaTimeMS(&startTime
);
4380 if ((deltaTime
> kPMHaltTimeoutMS
) ||
4381 (gIOKitDebug
& kIOLogPMRootDomain
))
4383 _IOServiceInterestNotifier
* notifier
;
4384 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
4386 // IOService children of IOPMrootDomain are not instrumented.
4387 // Only IORootParent currently falls under that group.
4391 LOG("%s handler %p took %u ms\n",
4392 ctx
->LogString
, OBFUSCATE(notifier
->handler
), deltaTime
);
4399 static void quiescePowerTreeCallback( void * target
, void * param
)
4401 IOLockLock(gPMHaltLock
);
4403 thread_wakeup(param
);
4404 IOLockUnlock(gPMHaltLock
);
4407 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
4409 HaltRestartApplierContext ctx
;
4410 AbsoluteTime startTime
;
4413 memset(&ctx
, 0, sizeof(ctx
));
4414 ctx
.RootDomain
= this;
4416 clock_get_uptime(&startTime
);
4420 case kPEUPSDelayHaltCPU
:
4421 ctx
.PowerState
= OFF_STATE
;
4422 ctx
.MessageType
= kIOMessageSystemWillPowerOff
;
4423 ctx
.LogString
= "PowerOff";
4427 ctx
.PowerState
= RESTART_STATE
;
4428 ctx
.MessageType
= kIOMessageSystemWillRestart
;
4429 ctx
.LogString
= "Restart";
4433 ctx
.PowerState
= ON_STATE
;
4434 ctx
.MessageType
= kIOMessageSystemPagingOff
;
4435 ctx
.LogString
= "PagingOff";
4436 IOService::updateConsoleUsers(NULL
, kIOMessageSystemPagingOff
);
4438 IOHibernateSystemRestart();
4446 // Notify legacy clients
4447 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &ctx
);
4449 // For normal shutdown, turn off File Server Mode.
4450 if (kPEHaltCPU
== pe_type
)
4452 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
4453 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
4456 setPMSetting(setting
, num
);
4462 if (kPEPagingOff
!= pe_type
)
4464 // Notify in power tree order
4465 notifySystemShutdown(this, ctx
.MessageType
);
4468 IOCPURunPlatformHaltRestartActions(pe_type
);
4470 // Wait for PM to quiesce
4471 if ((kPEPagingOff
!= pe_type
) && gPMHaltLock
)
4473 AbsoluteTime quiesceTime
= mach_absolute_time();
4475 IOLockLock(gPMHaltLock
);
4476 gPMQuiesced
= false;
4477 if (quiescePowerTree(this, &quiescePowerTreeCallback
, &gPMQuiesced
) ==
4480 while (!gPMQuiesced
)
4482 IOLockSleep(gPMHaltLock
, &gPMQuiesced
, THREAD_UNINT
);
4485 IOLockUnlock(gPMHaltLock
);
4487 deltaTime
= computeDeltaTimeMS(&quiesceTime
);
4488 DLOG("PM quiesce took %u ms\n", deltaTime
);
4491 deltaTime
= computeDeltaTimeMS(&startTime
);
4492 LOG("%s all drivers took %u ms\n", ctx
.LogString
, deltaTime
);
4495 //******************************************************************************
4498 //******************************************************************************
4500 IOReturn
IOPMrootDomain::shutdownSystem( void )
4502 return kIOReturnUnsupported
;
4505 //******************************************************************************
4508 //******************************************************************************
4510 IOReturn
IOPMrootDomain::restartSystem( void )
4512 return kIOReturnUnsupported
;
4516 // MARK: System Capability
4518 //******************************************************************************
4519 // tagPowerPlaneService
4521 // Running on PM work loop thread.
4522 //******************************************************************************
4524 void IOPMrootDomain::tagPowerPlaneService(
4525 IOService
* service
,
4526 IOPMActions
* actions
)
4529 bool isDisplayWrangler
;
4531 memset(actions
, 0, sizeof(*actions
));
4532 actions
->target
= this;
4534 if (service
== this)
4536 actions
->actionPowerChangeStart
=
4537 OSMemberFunctionCast(
4538 IOPMActionPowerChangeStart
, this,
4539 &IOPMrootDomain::handleOurPowerChangeStart
);
4541 actions
->actionPowerChangeDone
=
4542 OSMemberFunctionCast(
4543 IOPMActionPowerChangeDone
, this,
4544 &IOPMrootDomain::handleOurPowerChangeDone
);
4546 actions
->actionPowerChangeOverride
=
4547 OSMemberFunctionCast(
4548 IOPMActionPowerChangeOverride
, this,
4549 &IOPMrootDomain::overrideOurPowerChange
);
4554 isDisplayWrangler
= (0 != service
->metaCast("IODisplayWrangler"));
4555 if (isDisplayWrangler
)
4560 isDisplayWrangler
= false;
4563 #if defined(__i386__) || defined(__x86_64__)
4564 if (isDisplayWrangler
)
4565 flags
|= kPMActionsFlagIsDisplayWrangler
;
4566 if (service
->getProperty("IOPMStrictTreeOrder"))
4567 flags
|= kPMActionsFlagIsGraphicsDevice
;
4568 if (service
->getProperty("IOPMUnattendedWakePowerState"))
4569 flags
|= kPMActionsFlagIsAudioDevice
;
4572 // Find the power connection object that is a child of the PCI host
4573 // bridge, and has a graphics/audio device attached below. Mark the
4574 // power branch for delayed child notifications.
4578 IORegistryEntry
* child
= service
;
4579 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
4581 while (child
!= this)
4583 if ((parent
== pciHostBridgeDriver
) ||
4586 if (OSDynamicCast(IOPowerConnection
, child
))
4588 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
4589 conn
->delayChildNotification
= true;
4594 parent
= child
->getParentEntry(gIOPowerPlane
);
4600 DLOG("%s tag flags %x\n", service
->getName(), flags
);
4601 actions
->parameter
|= flags
;
4602 actions
->actionPowerChangeOverride
=
4603 OSMemberFunctionCast(
4604 IOPMActionPowerChangeOverride
, this,
4605 &IOPMrootDomain::overridePowerChangeForUIService
);
4607 if (flags
& kPMActionsFlagIsDisplayWrangler
)
4609 actions
->actionActivityTickle
=
4610 OSMemberFunctionCast(
4611 IOPMActionActivityTickle
, this,
4612 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
4614 actions
->actionUpdatePowerClient
=
4615 OSMemberFunctionCast(
4616 IOPMActionUpdatePowerClient
, this,
4617 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler
);
4622 // Locate the first PCI host bridge for PMTrace.
4623 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
4625 IOService
* provider
= service
->getProvider();
4626 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
4627 provider
->inPlane(gIODTPlane
))
4629 pciHostBridgeDevice
= provider
;
4630 pciHostBridgeDriver
= service
;
4631 DLOG("PMTrace found PCI host bridge %s->%s\n",
4632 provider
->getName(), service
->getName());
4636 // Tag top-level PCI devices. The order of PMinit() call does not
4637 // change across boots and is used as the PCI bit number.
4638 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
4640 // Would prefer to check built-in property, but tagPowerPlaneService()
4641 // is called before pciDevice->registerService().
4642 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
4643 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
4645 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
4648 // Save the assigned bit for fast lookup.
4649 actions
->parameter
|= (bit
& kPMActionsPCIBitNumberMask
);
4651 actions
->actionPowerChangeStart
=
4652 OSMemberFunctionCast(
4653 IOPMActionPowerChangeStart
, this,
4654 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
4656 actions
->actionPowerChangeDone
=
4657 OSMemberFunctionCast(
4658 IOPMActionPowerChangeDone
, this,
4659 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
4665 //******************************************************************************
4666 // PM actions for root domain
4667 //******************************************************************************
4669 void IOPMrootDomain::overrideOurPowerChange(
4670 IOService
* service
,
4671 IOPMActions
* actions
,
4672 IOPMPowerStateIndex
* inOutPowerState
,
4673 IOPMPowerChangeFlags
* inOutChangeFlags
,
4674 IOPMRequestTag requestTag
)
4676 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4677 uint32_t changeFlags
= *inOutChangeFlags
;
4678 uint32_t currentPowerState
= (uint32_t) getPowerState();
4680 if (changeFlags
& kIOPMParentInitiated
)
4682 // Root parent is permanently pegged at max power,
4683 // a parent initiated power change is unexpected.
4684 *inOutChangeFlags
|= kIOPMNotDone
;
4688 if (powerState
< currentPowerState
)
4690 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
4692 // Root domain is dropping power state ON->SLEEP.
4693 // If system is in full wake, first enter dark wake by
4694 // converting the power drop to a capability change.
4695 // Once in dark wake, transition to sleep state ASAP.
4697 darkWakeToSleepASAP
= true;
4699 // Drop graphics and audio capability
4700 _desiredCapability
&= ~(
4701 kIOPMSystemCapabilityGraphics
|
4702 kIOPMSystemCapabilityAudio
);
4704 // Convert to capability change (ON->ON)
4705 *inOutPowerState
= ON_STATE
;
4706 *inOutChangeFlags
|= kIOPMSynchronize
;
4708 // Revert device desire from SLEEP to ON
4709 changePowerStateToPriv(ON_STATE
);
4713 // System is in dark wake, ok to drop power state.
4714 // Broadcast root powering down to entire tree.
4715 *inOutChangeFlags
|= kIOPMRootChangeDown
;
4718 else if (powerState
> currentPowerState
)
4720 if ((_currentCapability
& kIOPMSystemCapabilityCPU
) == 0)
4722 // Broadcast power up when waking from sleep, but not for the
4723 // initial power change at boot by checking for cpu capability.
4724 *inOutChangeFlags
|= kIOPMRootChangeUp
;
4729 void IOPMrootDomain::handleOurPowerChangeStart(
4730 IOService
* service
,
4731 IOPMActions
* actions
,
4732 IOPMPowerStateIndex powerState
,
4733 IOPMPowerChangeFlags
* inOutChangeFlags
,
4734 IOPMRequestTag requestTag
)
4736 uint32_t changeFlags
= *inOutChangeFlags
;
4737 uint32_t currentPowerState
= (uint32_t) getPowerState();
4738 uint32_t sleepReason
= requestTag
? requestTag
: kIOPMSleepReasonIdle
;
4739 bool publishSleepReason
= false;
4741 _systemTransitionType
= kSystemTransitionNone
;
4742 _systemMessageClientMask
= 0;
4743 capabilityLoss
= false;
4744 toldPowerdCapWillChange
= false;
4746 if (lowBatteryCondition
)
4748 // Low battery notification may arrive after the initial sleep request
4749 // has been queued. Override the sleep reason so powerd and others can
4750 // treat this as an emergency sleep.
4751 sleepReason
= kIOPMSleepReasonLowPower
;
4754 // 1. Explicit capability change.
4756 if (changeFlags
& kIOPMSynchronize
)
4758 if (powerState
== ON_STATE
)
4760 if (changeFlags
& kIOPMSyncNoChildNotify
)
4761 _systemTransitionType
= kSystemTransitionNewCapClient
;
4763 _systemTransitionType
= kSystemTransitionCapability
;
4767 // 2. Going to sleep (cancellation still possible).
4769 else if (powerState
< currentPowerState
)
4770 _systemTransitionType
= kSystemTransitionSleep
;
4772 // 3. Woke from (idle or demand) sleep.
4774 else if (!systemBooting
&&
4775 (changeFlags
& kIOPMSelfInitiated
) &&
4776 (powerState
> currentPowerState
))
4778 _systemTransitionType
= kSystemTransitionWake
;
4779 _desiredCapability
= kIOPMSystemCapabilityCPU
|
4780 kIOPMSystemCapabilityNetwork
;
4782 // Early exit from dark wake to full (e.g. LID open)
4783 if (kFullWakeReasonNone
!= fullWakeReason
)
4785 _desiredCapability
|= (
4786 kIOPMSystemCapabilityGraphics
|
4787 kIOPMSystemCapabilityAudio
);
4790 IOHibernateSetWakeCapabilities(_desiredCapability
);
4794 // Update pending wake capability at the beginning of every
4795 // state transition (including synchronize). This will become
4796 // the current capability at the end of the transition.
4798 if (kSystemTransitionSleep
== _systemTransitionType
)
4800 _pendingCapability
= 0;
4801 capabilityLoss
= true;
4803 // Clear previous stats
4804 IOLockLock(pmStatsLock
);
4805 if (pmStatsAppResponses
)
4807 pmStatsAppResponses
->release();
4808 pmStatsAppResponses
= OSArray::withCapacity(5);
4810 IOLockUnlock(pmStatsLock
);
4813 else if (kSystemTransitionNewCapClient
!= _systemTransitionType
)
4815 _pendingCapability
= _desiredCapability
|
4816 kIOPMSystemCapabilityCPU
|
4817 kIOPMSystemCapabilityNetwork
;
4819 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4820 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
4822 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
4823 (_pendingCapability
== _currentCapability
))
4825 // Cancel the PM state change.
4826 _systemTransitionType
= kSystemTransitionNone
;
4827 *inOutChangeFlags
|= kIOPMNotDone
;
4829 if (__builtin_popcount(_pendingCapability
) <
4830 __builtin_popcount(_currentCapability
))
4831 capabilityLoss
= true;
4834 // 1. Capability change.
4836 if (kSystemTransitionCapability
== _systemTransitionType
)
4838 // Dark to Full transition.
4839 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4841 tracePoint( kIOPMTracePointDarkWakeExit
);
4843 willEnterFullWake();
4846 // Full to Dark transition.
4847 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4849 tracePoint( kIOPMTracePointDarkWakeEntry
);
4850 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
4851 _systemMessageClientMask
= kSystemMessageClientPowerd
|
4852 kSystemMessageClientLegacyApp
;
4856 // Prevent user active transitions before notifying clients
4857 // that system will sleep.
4858 preventTransitionToUserActive(true);
4860 IOService::setAdvisoryTickleEnable( false );
4862 // Publish the sleep reason for full to dark wake
4863 publishSleepReason
= true;
4864 lastSleepReason
= fullToDarkReason
= sleepReason
;
4866 // Publish a UUID for the Sleep --> Wake cycle
4867 handlePublishSleepWakeUUID(true);
4868 if (sleepDelaysReport
) {
4869 clock_get_uptime(&ts_sleepStart
);
4870 DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart
);
4877 else if (kSystemTransitionSleep
== _systemTransitionType
)
4879 // Beginning of a system sleep transition.
4880 // Cancellation is still possible.
4881 tracePoint( kIOPMTracePointSleepStarted
, sleepReason
);
4883 _systemMessageClientMask
= kSystemMessageClientAll
;
4884 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4885 _systemMessageClientMask
&= ~kSystemMessageClientLegacyApp
;
4886 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4887 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
4889 // Record the reason for dark wake back to sleep
4890 // System may not have ever achieved full wake
4892 publishSleepReason
= true;
4893 lastSleepReason
= sleepReason
;
4894 if (sleepDelaysReport
) {
4895 clock_get_uptime(&ts_sleepStart
);
4896 DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart
);
4902 else if (kSystemTransitionWake
== _systemTransitionType
)
4904 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
4905 // Clear stats about sleep
4907 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4909 willEnterFullWake();
4913 // Message powerd only
4914 _systemMessageClientMask
= kSystemMessageClientPowerd
;
4915 tellClients(kIOMessageSystemWillPowerOn
);
4919 // The only location where the sleep reason is published. At this point
4920 // sleep can still be cancelled, but sleep reason should be published
4921 // early for logging purposes.
4923 if (publishSleepReason
)
4925 static const char * IOPMSleepReasons
[] =
4927 kIOPMClamshellSleepKey
,
4928 kIOPMPowerButtonSleepKey
,
4929 kIOPMSoftwareSleepKey
,
4930 kIOPMOSSwitchHibernationKey
,
4932 kIOPMLowPowerSleepKey
,
4933 kIOPMThermalEmergencySleepKey
,
4934 kIOPMMaintenanceSleepKey
,
4935 kIOPMSleepServiceExitKey
,
4936 kIOPMDarkWakeThermalEmergencyKey
4939 // Record sleep cause in IORegistry
4940 uint32_t reasonIndex
= sleepReason
- kIOPMSleepReasonClamshell
;
4941 if (reasonIndex
< sizeof(IOPMSleepReasons
)/sizeof(IOPMSleepReasons
[0])) {
4942 DLOG("sleep reason %s\n", IOPMSleepReasons
[reasonIndex
]);
4943 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[reasonIndex
]);
4947 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
4948 (kSystemTransitionNewCapClient
!= _systemTransitionType
))
4950 _systemStateGeneration
++;
4951 systemDarkWake
= false;
4953 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4955 currentPowerState
, (uint32_t) powerState
, *inOutChangeFlags
,
4956 _systemTransitionType
, _systemStateGeneration
,
4957 _systemMessageClientMask
,
4958 _desiredCapability
, _currentCapability
, _pendingCapability
);
4962 void IOPMrootDomain::handleOurPowerChangeDone(
4963 IOService
* service
,
4964 IOPMActions
* actions
,
4965 IOPMPowerStateIndex powerState
,
4966 IOPMPowerChangeFlags changeFlags
,
4967 IOPMRequestTag requestTag __unused
)
4969 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
4971 _systemTransitionType
= kSystemTransitionNone
;
4975 if (_systemTransitionType
!= kSystemTransitionNone
)
4977 uint32_t currentPowerState
= (uint32_t) getPowerState();
4979 if (changeFlags
& kIOPMNotDone
)
4981 // Power down was cancelled or vetoed.
4982 _pendingCapability
= _currentCapability
;
4983 lastSleepReason
= 0;
4985 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
) &&
4986 CAP_CURRENT(kIOPMSystemCapabilityCPU
))
4988 pmPowerStateQueue
->submitPowerEvent(
4989 kPowerEventPolicyStimulus
,
4990 (void *) kStimulusDarkWakeReentry
,
4991 _systemStateGeneration
);
4994 // Revert device desire to max.
4995 changePowerStateToPriv(ON_STATE
);
4999 // Send message on dark wake to full wake promotion.
5000 // tellChangeUp() handles the normal SLEEP->ON case.
5002 if (kSystemTransitionCapability
== _systemTransitionType
)
5004 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
5006 lastSleepReason
= 0; // stop logging wrangler tickles
5007 tellClients(kIOMessageSystemHasPoweredOn
);
5009 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
5011 // Going dark, reset full wake state
5012 // userIsActive will be cleared by wrangler powering down
5013 wranglerTickled
= false;
5014 fullWakeReason
= kFullWakeReasonNone
;
5016 if (ts_sleepStart
) {
5017 clock_get_uptime(&wake2DarkwakeDelay
);
5018 SUB_ABSOLUTETIME(&wake2DarkwakeDelay
, &ts_sleepStart
);
5019 DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay
);
5025 // Reset state after exiting from dark wake.
5027 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
5028 CAP_LOSS(kIOPMSystemCapabilityCPU
))
5030 darkWakeMaintenance
= false;
5031 darkWakeToSleepASAP
= false;
5032 pciCantSleepValid
= false;
5033 darkWakeSleepService
= false;
5035 if (CAP_LOSS(kIOPMSystemCapabilityCPU
))
5037 // Remove the influence of display power assertion
5038 // before next system wake.
5039 if (wrangler
) wrangler
->changePowerStateForRootDomain(
5040 kWranglerPowerStateMin
);
5041 removeProperty(gIOPMUserTriggeredFullWakeKey
);
5045 // Entered dark mode.
5047 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5048 (_pendingCapability
& kIOPMSystemCapabilityCPU
))
5050 // Queue an evaluation of whether to remain in dark wake,
5051 // and for how long. This serves the purpose of draining
5052 // any assertions from the queue.
5054 pmPowerStateQueue
->submitPowerEvent(
5055 kPowerEventPolicyStimulus
,
5056 (void *) kStimulusDarkWakeEntry
,
5057 _systemStateGeneration
);
5061 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5062 "dcp %x:%x:%x, dbgtimer %u\n",
5063 currentPowerState
, (uint32_t) powerState
, changeFlags
,
5064 _systemTransitionType
, _systemStateGeneration
,
5065 _systemMessageClientMask
,
5066 _desiredCapability
, _currentCapability
, _pendingCapability
,
5067 _lastDebugWakeSeconds
);
5069 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5072 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
5073 if (clamshellExists
&& fullWakeThreadCall
&&
5074 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
5076 // Not the initial graphics full power, graphics won't
5077 // send a power notification to trigger a lid state
5080 AbsoluteTime deadline
;
5081 clock_interval_to_deadline(45, kSecondScale
, &deadline
);
5082 thread_call_enter_delayed(fullWakeThreadCall
, deadline
);
5086 else if (CAP_GAIN(kIOPMSystemCapabilityCPU
))
5089 // Update current system capability.
5090 if (_currentCapability
!= _pendingCapability
)
5091 _currentCapability
= _pendingCapability
;
5093 // Update highest system capability.
5095 _highestCapability
|= _currentCapability
;
5097 if (darkWakePostTickle
&&
5098 (kSystemTransitionWake
== _systemTransitionType
) &&
5099 (gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5100 kDarkWakeFlagHIDTickleLate
)
5102 darkWakePostTickle
= false;
5106 // Reset tracepoint at completion of capability change,
5107 // completion of wake transition, and aborted sleep transition.
5109 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
5110 (_systemTransitionType
== kSystemTransitionWake
) ||
5111 ((_systemTransitionType
== kSystemTransitionSleep
) &&
5112 (changeFlags
& kIOPMNotDone
)))
5114 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
5115 tracePoint( kIOPMTracePointSystemUp
, 0 );
5118 _systemTransitionType
= kSystemTransitionNone
;
5119 _systemMessageClientMask
= 0;
5120 toldPowerdCapWillChange
= false;
5122 logGraphicsClamp
= false;
5126 //******************************************************************************
5127 // PM actions for graphics and audio.
5128 //******************************************************************************
5130 void IOPMrootDomain::overridePowerChangeForUIService(
5131 IOService
* service
,
5132 IOPMActions
* actions
,
5133 IOPMPowerStateIndex
* inOutPowerState
,
5134 IOPMPowerChangeFlags
* inOutChangeFlags
)
5136 uint32_t powerState
= (uint32_t) *inOutPowerState
;
5137 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
5139 if (kSystemTransitionNone
== _systemTransitionType
)
5141 // Not in midst of a system transition.
5142 // Do not modify power limit enable state.
5144 else if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5146 // Activate power limiter.
5148 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5149 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5150 (changeFlags
& kIOPMSynchronize
))
5152 actions
->parameter
|= kPMActionsFlagLimitPower
;
5154 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5155 ((gDarkWakeFlags
& kDarkWakeFlagAudioNotSuppressed
) == 0) &&
5156 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0) &&
5157 (changeFlags
& kIOPMSynchronize
))
5159 actions
->parameter
|= kPMActionsFlagLimitPower
;
5161 else if ((actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) &&
5162 (_systemTransitionType
== kSystemTransitionSleep
))
5164 // For graphics devices, arm the limiter when entering
5165 // system sleep. Not when dropping to dark wake.
5166 actions
->parameter
|= kPMActionsFlagLimitPower
;
5169 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5171 DLOG("+ plimit %s %p\n",
5172 service
->getName(), OBFUSCATE(service
));
5177 // Remove power limit.
5179 if ((actions
->parameter
& (
5180 kPMActionsFlagIsDisplayWrangler
|
5181 kPMActionsFlagIsGraphicsDevice
)) &&
5182 (_pendingCapability
& kIOPMSystemCapabilityGraphics
))
5184 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5186 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5187 (_pendingCapability
& kIOPMSystemCapabilityAudio
))
5189 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5192 if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5194 DLOG("- plimit %s %p\n",
5195 service
->getName(), OBFUSCATE(service
));
5199 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5201 uint32_t maxPowerState
= (uint32_t)(-1);
5203 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
))
5205 // Enforce limit for system power/cap transitions.
5208 if ((service
->getPowerState() > maxPowerState
) &&
5209 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
))
5213 // Remove lingering effects of any tickle before entering
5214 // dark wake. It will take a new tickle to return to full
5215 // wake, so the existing tickle state is useless.
5217 if (changeFlags
& kIOPMDomainDidChange
)
5218 *inOutChangeFlags
|= kIOPMExpireIdleTimer
;
5220 else if (actions
->parameter
& kPMActionsFlagIsGraphicsDevice
)
5227 // Deny all self-initiated changes when power is limited.
5228 // Wrangler tickle should never defeat the limiter.
5230 maxPowerState
= service
->getPowerState();
5233 if (powerState
> maxPowerState
)
5235 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
5236 service
->getName(), OBFUSCATE(service
), powerState
, maxPowerState
,
5238 *inOutPowerState
= maxPowerState
;
5240 if (darkWakePostTickle
&&
5241 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5242 (changeFlags
& kIOPMDomainWillChange
) &&
5243 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5244 kDarkWakeFlagHIDTickleEarly
))
5246 darkWakePostTickle
= false;
5251 if (!graphicsSuppressed
&& (changeFlags
& kIOPMDomainDidChange
))
5253 if (logGraphicsClamp
)
5258 clock_get_uptime(&now
);
5259 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
5260 absolutetime_to_nanoseconds(now
, &nsec
);
5261 if (kIOLogPMRootDomain
& gIOKitDebug
)
5262 MSG("Graphics suppressed %u ms\n",
5263 ((int)((nsec
) / 1000000ULL)));
5265 graphicsSuppressed
= true;
5270 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
5271 IOService
* service
,
5272 IOPMActions
* actions
)
5275 // Warning: Not running in PM work loop context - don't modify state !!!
5276 // Trap tickle directed to IODisplayWrangler while running with graphics
5277 // capability suppressed.
5279 assert(service
== wrangler
);
5281 clock_get_uptime(&userActivityTime
);
5282 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
5283 || (lastSleepReason
== kIOPMSleepReasonMaintenance
)
5284 || (lastSleepReason
== kIOPMSleepReasonSoftware
));
5286 userActivityCount
++;
5287 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
5288 userActivityCount
, lastSleepReason
);
5291 if (!wranglerTickled
&&
5292 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
5294 DLOG("display wrangler tickled\n");
5295 if (kIOLogPMRootDomain
& gIOKitDebug
)
5296 OSReportWithBacktrace("Dark wake display tickle");
5297 if (pmPowerStateQueue
)
5299 pmPowerStateQueue
->submitPowerEvent(
5300 kPowerEventPolicyStimulus
,
5301 (void *) kStimulusDarkWakeActivityTickle
,
5302 true /* set wake type */ );
5308 void IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
5309 IOService
* service
,
5310 IOPMActions
* actions
,
5311 const OSSymbol
* powerClient
,
5312 IOPMPowerStateIndex oldPowerState
,
5313 IOPMPowerStateIndex newPowerState
)
5316 assert(service
== wrangler
);
5318 // This function implements half of the user active detection
5319 // by monitoring changes to the display wrangler's device desire.
5321 // User becomes active when either:
5322 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
5323 // in max power state. This desire change in absence of a power state
5324 // change is detected within. This handles the case when user becomes
5325 // active while the display is already lit by setDisplayPowerOn().
5327 // 2. Power state change to max, and DeviceDesire is also at max.
5328 // Handled by displayWranglerNotification().
5330 // User becomes inactive when DeviceDesire drops to sleep state or below.
5332 DLOG("wrangler %s (ps %u, %u->%u)\n",
5333 powerClient
->getCStringNoCopy(),
5334 (uint32_t) service
->getPowerState(),
5335 (uint32_t) oldPowerState
, (uint32_t) newPowerState
);
5337 if (powerClient
== gIOPMPowerClientDevice
)
5339 if ((newPowerState
> oldPowerState
) &&
5340 (newPowerState
== kWranglerPowerStateMax
) &&
5341 (service
->getPowerState() == kWranglerPowerStateMax
))
5343 evaluatePolicy( kStimulusEnterUserActiveState
);
5346 if ((newPowerState
< oldPowerState
) &&
5347 (newPowerState
<= kWranglerPowerStateSleep
))
5349 evaluatePolicy( kStimulusLeaveUserActiveState
);
5355 //******************************************************************************
5356 // User active state management
5357 //******************************************************************************
5359 void IOPMrootDomain::preventTransitionToUserActive( bool prevent
)
5362 _preventUserActive
= prevent
;
5363 if (wrangler
&& !_preventUserActive
)
5365 // Allowing transition to user active, but the wrangler may have
5366 // already powered ON in case of sleep cancel/revert. Poll the
5367 // same conditions checked for in displayWranglerNotification()
5368 // to bring the user active state up to date.
5370 if ((wrangler
->getPowerState() == kWranglerPowerStateMax
) &&
5371 (wrangler
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5372 kWranglerPowerStateMax
))
5374 evaluatePolicy( kStimulusEnterUserActiveState
);
5380 //******************************************************************************
5381 // Approve usage of delayed child notification by PM.
5382 //******************************************************************************
5384 bool IOPMrootDomain::shouldDelayChildNotification(
5385 IOService
* service
)
5387 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) &&
5388 (kFullWakeReasonNone
== fullWakeReason
) &&
5389 (kSystemTransitionWake
== _systemTransitionType
))
5391 DLOG("%s: delay child notify\n", service
->getName());
5397 //******************************************************************************
5398 // PM actions for PCI device.
5399 //******************************************************************************
5401 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
5402 IOService
* service
,
5403 IOPMActions
* actions
,
5404 IOPMPowerStateIndex powerState
,
5405 IOPMPowerChangeFlags
* inOutChangeFlags
)
5407 pmTracer
->tracePCIPowerChange(
5408 PMTraceWorker::kPowerChangeStart
,
5409 service
, *inOutChangeFlags
,
5410 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5413 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
5414 IOService
* service
,
5415 IOPMActions
* actions
,
5416 IOPMPowerStateIndex powerState
,
5417 IOPMPowerChangeFlags changeFlags
)
5419 pmTracer
->tracePCIPowerChange(
5420 PMTraceWorker::kPowerChangeCompleted
,
5421 service
, changeFlags
,
5422 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5425 //******************************************************************************
5428 // Override IOService::registerInterest() to intercept special clients.
5429 //******************************************************************************
5431 class IOPMServiceInterestNotifier
: public _IOServiceInterestNotifier
5434 friend class IOPMrootDomain
;
5435 OSDeclareDefaultStructors(IOPMServiceInterestNotifier
)
5438 uint32_t ackTimeoutCnt
;
5442 OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier
, _IOServiceInterestNotifier
)
5444 IONotifier
* IOPMrootDomain::registerInterest(
5445 const OSSymbol
* typeOfInterest
,
5446 IOServiceInterestHandler handler
,
5447 void * target
, void * ref
)
5449 IOPMServiceInterestNotifier
*notifier
= 0;
5450 bool isSystemCapabilityClient
;
5451 bool isKernelCapabilityClient
;
5452 IOReturn rc
= kIOReturnError
;;
5454 isSystemCapabilityClient
=
5456 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
5458 isKernelCapabilityClient
=
5460 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
5462 if (isSystemCapabilityClient
)
5463 typeOfInterest
= gIOAppPowerStateInterest
;
5465 notifier
= new IOPMServiceInterestNotifier
;
5466 if (!notifier
) return NULL
;
5468 if (notifier
->init()) {
5469 rc
= super::registerInterestForNotifer(notifier
, typeOfInterest
, handler
, target
, ref
);
5471 if (rc
!= kIOReturnSuccess
) {
5472 notifier
->release();
5477 if (pmPowerStateQueue
)
5479 notifier
->ackTimeoutCnt
= 0;
5480 if (isSystemCapabilityClient
)
5483 if (pmPowerStateQueue
->submitPowerEvent(
5484 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false)
5485 notifier
->release();
5488 if (isKernelCapabilityClient
)
5491 if (pmPowerStateQueue
->submitPowerEvent(
5492 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false)
5493 notifier
->release();
5500 //******************************************************************************
5501 // systemMessageFilter
5503 //******************************************************************************
5505 bool IOPMrootDomain::systemMessageFilter(
5506 void * object
, void * arg1
, void * arg2
, void * arg3
)
5508 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
5509 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
5510 bool isCapClient
= false;
5514 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
5515 (!isCapMsg
|| !_joinedCapabilityClients
||
5516 !_joinedCapabilityClients
->containsObject((OSObject
*) object
)))
5519 // Capability change message for app and kernel clients.
5523 if ((context
->notifyType
== kNotifyPriority
) ||
5524 (context
->notifyType
== kNotifyCapabilityChangePriority
))
5527 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
5528 (object
== (void *) systemCapabilityNotifier
))
5534 IOPMSystemCapabilityChangeParameters
* capArgs
=
5535 (IOPMSystemCapabilityChangeParameters
*) arg2
;
5537 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5539 capArgs
->fromCapabilities
= 0;
5540 capArgs
->toCapabilities
= _currentCapability
;
5541 capArgs
->changeFlags
= 0;
5545 capArgs
->fromCapabilities
= _currentCapability
;
5546 capArgs
->toCapabilities
= _pendingCapability
;
5548 if (context
->isPreChange
)
5549 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
5551 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
5553 if ((object
== (void *) systemCapabilityNotifier
) &&
5554 context
->isPreChange
)
5556 toldPowerdCapWillChange
= true;
5560 // Capability change messages only go to the PM configd plugin.
5561 // Wait for response post-change if capabilitiy is increasing.
5562 // Wait for response pre-change if capability is decreasing.
5564 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
5565 ( (capabilityLoss
&& context
->isPreChange
) ||
5566 (!capabilityLoss
&& !context
->isPreChange
) ) )
5568 // app has not replied yet, wait for it
5569 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5576 // Capability client will always see kIOMessageCanSystemSleep,
5577 // even for demand sleep. It will also have a chance to veto
5578 // sleep one last time after all clients have responded to
5579 // kIOMessageSystemWillSleep
5581 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
5582 (kIOMessageSystemWillNotSleep
== context
->messageType
))
5584 if (object
== (OSObject
*) systemCapabilityNotifier
)
5590 // Not idle sleep, don't ask apps.
5591 if (context
->changeFlags
& kIOPMSkipAskPowerDown
)
5597 if (kIOPMMessageLastCallBeforeSleep
== context
->messageType
)
5599 if ((object
== (OSObject
*) systemCapabilityNotifier
) &&
5600 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) &&
5601 (fullToDarkReason
== kIOPMSleepReasonIdle
))
5606 // Reject capability change messages for legacy clients.
5607 // Reject legacy system sleep messages for capability client.
5609 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
))
5614 // Filter system sleep messages.
5616 if ((context
->notifyType
== kNotifyApps
) &&
5617 (_systemMessageClientMask
& kSystemMessageClientLegacyApp
))
5619 IOPMServiceInterestNotifier
*notify
;
5622 if ((notify
= OSDynamicCast(IOPMServiceInterestNotifier
, (OSObject
*)object
))
5625 if (notify
->ackTimeoutCnt
>= 3)
5626 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5628 *((OSObject
**) arg3
) = kOSBooleanTrue
;
5631 else if ((context
->notifyType
== kNotifyPriority
) &&
5632 (_systemMessageClientMask
& kSystemMessageClientKernel
))
5639 if (allow
&& isCapMsg
&& _joinedCapabilityClients
)
5641 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
5642 if (_joinedCapabilityClients
->getCount() == 0)
5644 DLOG("destroyed capability client set %p\n",
5645 OBFUSCATE(_joinedCapabilityClients
));
5646 _joinedCapabilityClients
->release();
5647 _joinedCapabilityClients
= 0;
5654 //******************************************************************************
5655 // setMaintenanceWakeCalendar
5657 //******************************************************************************
5659 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
5660 const IOPMCalendarStruct
* calendar
)
5666 return kIOReturnBadArgument
;
5668 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
5670 return kIOReturnNoMemory
;
5672 if (kPMCalendarTypeMaintenance
== calendar
->selector
) {
5673 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
5674 if (kIOReturnSuccess
== ret
)
5675 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake
, &_scheduledAlarms
);
5677 if (kPMCalendarTypeSleepService
== calendar
->selector
)
5679 ret
= setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey
, data
);
5680 if (kIOReturnSuccess
== ret
)
5681 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake
, &_scheduledAlarms
);
5683 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
5690 // MARK: Display Wrangler
5692 //******************************************************************************
5693 // displayWranglerNotification
5695 // Handle the notification when the IODisplayWrangler changes power state.
5696 //******************************************************************************
5698 IOReturn
IOPMrootDomain::displayWranglerNotification(
5699 void * target
, void * refCon
,
5700 UInt32 messageType
, IOService
* service
,
5701 void * messageArgument
, vm_size_t argSize
)
5704 int displayPowerState
;
5705 IOPowerStateChangeNotification
* params
=
5706 (IOPowerStateChangeNotification
*) messageArgument
;
5708 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
5709 (messageType
!= kIOMessageDeviceHasPoweredOn
))
5710 return kIOReturnUnsupported
;
5714 return kIOReturnUnsupported
;
5716 displayPowerState
= params
->stateNumber
;
5717 DLOG("wrangler %s ps %d\n",
5718 getIOMessageString(messageType
), displayPowerState
);
5720 switch (messageType
) {
5721 case kIOMessageDeviceWillPowerOff
:
5722 // Display wrangler has dropped power due to display idle
5723 // or force system sleep.
5725 // 4 Display ON kWranglerPowerStateMax
5726 // 3 Display Dim kWranglerPowerStateDim
5727 // 2 Display Sleep kWranglerPowerStateSleep
5728 // 1 Not visible to user
5729 // 0 Not visible to user kWranglerPowerStateMin
5731 if (displayPowerState
<= kWranglerPowerStateSleep
)
5732 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
5735 case kIOMessageDeviceHasPoweredOn
:
5736 // Display wrangler has powered on due to user activity
5737 // or wake from sleep.
5739 if (kWranglerPowerStateMax
== displayPowerState
)
5741 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
5743 // See comment in handleUpdatePowerClientForDisplayWrangler
5744 if (service
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5745 kWranglerPowerStateMax
)
5747 gRootDomain
->evaluatePolicy( kStimulusEnterUserActiveState
);
5753 return kIOReturnUnsupported
;
5756 //******************************************************************************
5757 // displayWranglerMatchPublished
5759 // Receives a notification when the IODisplayWrangler is published.
5760 // When it's published we install a power state change handler.
5761 //******************************************************************************
5763 bool IOPMrootDomain::displayWranglerMatchPublished(
5766 IOService
* newService
,
5767 IONotifier
* notifier __unused
)
5770 // found the display wrangler, now install a handler
5771 if( !newService
->registerInterest( gIOGeneralInterest
,
5772 &displayWranglerNotification
, target
, 0) )
5780 #if defined(__i386__) || defined(__x86_64__)
5782 bool IOPMrootDomain::IONVRAMMatchPublished(
5785 IOService
* newService
,
5786 IONotifier
* notifier
)
5788 unsigned int len
= 0;
5789 IOPMrootDomain
*rd
= (IOPMrootDomain
*)target
;
5790 OSNumber
*statusCode
= NULL
;
5792 if (PEReadNVRAMProperty(kIOSleepWakeDebugKey
, NULL
, &len
))
5794 statusCode
= OSDynamicCast(OSNumber
, rd
->getProperty(kIOPMSleepWakeFailureCodeKey
));
5795 if (statusCode
!= NULL
) {
5796 if (statusCode
->unsigned64BitValue() != 0) {
5797 rd
->swd_flags
|= SWD_BOOT_BY_SW_WDOG
;
5798 MSG("System was rebooted due to Sleep/Wake failure\n");
5801 rd
->swd_flags
|= SWD_BOOT_BY_OSX_WDOG
;
5802 MSG("System was non-responsive and was rebooted by watchdog\n");
5806 rd
->swd_logBufMap
= rd
->sleepWakeDebugRetrieve();
5808 if (notifier
) notifier
->remove();
5813 bool IOPMrootDomain::IONVRAMMatchPublished(
5816 IOService
* newService
,
5817 IONotifier
* notifier __unused
)
5824 //******************************************************************************
5827 //******************************************************************************
5829 void IOPMrootDomain::reportUserInput( void )
5833 OSDictionary
* matching
;
5837 matching
= serviceMatching("IODisplayWrangler");
5838 iter
= getMatchingServices(matching
);
5839 if (matching
) matching
->release();
5842 wrangler
= (IOService
*) iter
->getNextObject();
5848 wrangler
->activityTickle(0,0);
5852 //******************************************************************************
5853 // latchDisplayWranglerTickle
5854 //******************************************************************************
5856 bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch
)
5861 if (!(_currentCapability
& kIOPMSystemCapabilityGraphics
) &&
5862 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
5863 !checkSystemCanSustainFullWake())
5865 // Currently in dark wake, and not transitioning to full wake.
5866 // Full wake is unsustainable, so latch the tickle to prevent
5867 // the display from lighting up momentarily.
5868 wranglerTickleLatched
= true;
5872 wranglerTickleLatched
= false;
5875 else if (wranglerTickleLatched
&& checkSystemCanSustainFullWake())
5877 wranglerTickleLatched
= false;
5879 pmPowerStateQueue
->submitPowerEvent(
5880 kPowerEventPolicyStimulus
,
5881 (void *) kStimulusDarkWakeActivityTickle
);
5884 return wranglerTickleLatched
;
5890 //******************************************************************************
5891 // setDisplayPowerOn
5893 // For root domain user client
5894 //******************************************************************************
5896 void IOPMrootDomain::setDisplayPowerOn( uint32_t options
)
5898 pmPowerStateQueue
->submitPowerEvent( kPowerEventSetDisplayPowerOn
,
5899 (void *) 0, options
);
5905 //******************************************************************************
5908 // Notification on battery class IOPowerSource appearance
5909 //******************************************************************************
5911 bool IOPMrootDomain::batteryPublished(
5914 IOService
* resourceService
,
5915 IONotifier
* notifier __unused
)
5917 // rdar://2936060&4435589
5918 // All laptops have dimmable LCD displays
5919 // All laptops have batteries
5920 // So if this machine has a battery, publish the fact that the backlight
5921 // supports dimming.
5922 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
5928 // MARK: System PM Policy
5930 //******************************************************************************
5931 // checkSystemSleepAllowed
5933 //******************************************************************************
5935 bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options
,
5936 uint32_t sleepReason
)
5940 // Conditions that prevent idle and demand system sleep.
5943 if (userDisabledAllSleep
)
5945 err
= 1; // 1. user-space sleep kill switch
5949 if (systemBooting
|| systemShutdown
|| gWillShutdown
)
5951 err
= 2; // 2. restart or shutdown in progress
5958 // Conditions above pegs the system at full wake.
5959 // Conditions below prevent system sleep but does not prevent
5960 // dark wake, and must be called from gated context.
5963 err
= 3; // 3. config does not support sleep
5967 if (lowBatteryCondition
|| thermalWarningState
)
5969 break; // always sleep on low battery or when in thermal warning state
5972 if (sleepReason
== kIOPMSleepReasonDarkWakeThermalEmergency
)
5974 break; // always sleep on dark wake thermal emergencies
5977 if (preventSystemSleepList
->getCount() != 0)
5979 err
= 4; // 4. child prevent system sleep clamp
5983 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
5984 kIOPMDriverAssertionLevelOn
)
5986 err
= 5; // 5. CPU assertion
5990 if (pciCantSleepValid
)
5992 if (pciCantSleepFlag
)
5993 err
= 6; // 6. PCI card does not support PM (cached)
5996 else if (sleepSupportedPEFunction
&&
5997 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
6000 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
6001 ret
= getPlatform()->callPlatformFunction(
6002 sleepSupportedPEFunction
, false,
6003 NULL
, NULL
, NULL
, NULL
);
6004 pciCantSleepValid
= true;
6005 pciCantSleepFlag
= false;
6006 if ((platformSleepSupport
& kPCICantSleep
) ||
6007 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
)))
6009 err
= 6; // 6. PCI card does not support PM
6010 pciCantSleepFlag
= true;
6019 DLOG("System sleep prevented by %d\n", err
);
6025 bool IOPMrootDomain::checkSystemSleepEnabled( void )
6027 return checkSystemSleepAllowed(0, 0);
6030 bool IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason
)
6033 return checkSystemSleepAllowed(1, sleepReason
);
6036 //******************************************************************************
6037 // checkSystemCanSustainFullWake
6038 //******************************************************************************
6040 bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
6043 if (lowBatteryCondition
|| thermalWarningState
)
6045 // Low battery wake, or received a low battery notification
6046 // while system is awake. This condition will persist until
6047 // the following wake.
6051 if (clamshellExists
&& clamshellClosed
&& !clamshellSleepDisabled
)
6053 // Graphics state is unknown and external display might not be probed.
6054 // Do not incorporate state that requires graphics to be in max power
6055 // such as desktopMode or clamshellDisabled.
6057 if (!acAdaptorConnected
)
6059 DLOG("full wake check: no AC\n");
6067 //******************************************************************************
6070 // Conditions that affect our wake/sleep decision has changed.
6071 // If conditions dictate that the system must remain awake, clamp power
6072 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
6073 // is TRUE, then remove the power clamp and allow the power state to drop
6075 //******************************************************************************
6077 void IOPMrootDomain::adjustPowerState( bool sleepASAP
)
6079 DLOG("adjustPowerState ps %u, asap %d, slider %ld\n",
6080 (uint32_t) getPowerState(), sleepASAP
, sleepSlider
);
6084 if ((sleepSlider
== 0) || !checkSystemSleepEnabled())
6086 changePowerStateToPriv(ON_STATE
);
6088 else if ( sleepASAP
)
6090 changePowerStateToPriv(SLEEP_STATE
);
6094 void IOPMrootDomain::handleDisplayPowerOn( )
6096 if (!wrangler
) return;
6097 if (displayPowerOnRequested
)
6099 if (!checkSystemCanSustainFullWake()) return;
6101 // Force wrangler to max power state. If system is in dark wake
6102 // this alone won't raise the wrangler's power state.
6104 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMax
);
6106 // System in dark wake, always requesting full wake should
6107 // not have any bad side-effects, even if the request fails.
6109 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6111 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeNotification
);
6112 requestFullWake( kFullWakeReasonDisplayOn
);
6117 // Relenquish desire to power up display.
6118 // Must first transition to state 1 since wrangler doesn't
6119 // power off the displays at state 0. At state 0 the root
6120 // domain is removed from the wrangler's power client list.
6122 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
+ 1);
6123 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
);
6129 //******************************************************************************
6130 // dispatchPowerEvent
6132 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
6133 //******************************************************************************
6135 void IOPMrootDomain::dispatchPowerEvent(
6136 uint32_t event
, void * arg0
, uint64_t arg1
)
6138 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6143 case kPowerEventFeatureChanged
:
6144 messageClients(kIOPMMessageFeatureChange
, this);
6147 case kPowerEventReceivedPowerNotification
:
6148 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
6151 case kPowerEventSystemBootCompleted
:
6154 systemBooting
= false;
6156 if (lowBatteryCondition
)
6158 privateSleepSystem (kIOPMSleepReasonLowPower
);
6160 // The rest is unnecessary since the system is expected
6161 // to sleep immediately. The following wake will update
6166 if (swd_flags
& SWD_VALID_LOGS
) {
6167 if (swd_flags
& SWD_LOGS_IN_MEM
) {
6168 sleepWakeDebugDumpFromMem(swd_logBufMap
);
6169 swd_logBufMap
->release();
6172 else if (swd_flags
& SWD_LOGS_IN_FILE
)
6173 sleepWakeDebugDumpFromFile();
6175 else if (swd_flags
& (SWD_BOOT_BY_SW_WDOG
|SWD_BOOT_BY_OSX_WDOG
)) {
6176 // If logs are invalid, write the failure code
6177 sleepWakeDebugDumpFromMem(NULL
);
6179 // If lid is closed, re-send lid closed notification
6180 // now that booting is complete.
6181 if ( clamshellClosed
)
6183 handlePowerNotification(kLocalEvalClamshellCommand
);
6185 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
6190 case kPowerEventSystemShutdown
:
6191 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
6193 /* We set systemShutdown = true during shutdown
6194 to prevent sleep at unexpected times while loginwindow is trying
6195 to shutdown apps and while the OS is trying to transition to
6198 Set to true during shutdown, as soon as loginwindow shows
6199 the "shutdown countdown dialog", through individual app
6200 termination, and through black screen kernel shutdown.
6202 systemShutdown
= true;
6205 A shutdown was initiated, but then the shutdown
6206 was cancelled, clearing systemShutdown to false here.
6208 systemShutdown
= false;
6212 case kPowerEventUserDisabledSleep
:
6213 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
6216 case kPowerEventRegisterSystemCapabilityClient
:
6217 if (systemCapabilityNotifier
)
6219 systemCapabilityNotifier
->release();
6220 systemCapabilityNotifier
= 0;
6224 systemCapabilityNotifier
= (IONotifier
*) arg0
;
6225 systemCapabilityNotifier
->retain();
6227 /* intentional fall-through */
6229 case kPowerEventRegisterKernelCapabilityClient
:
6230 if (!_joinedCapabilityClients
)
6231 _joinedCapabilityClients
= OSSet::withCapacity(8);
6234 IONotifier
* notify
= (IONotifier
*) arg0
;
6235 if (_joinedCapabilityClients
)
6237 _joinedCapabilityClients
->setObject(notify
);
6238 synchronizePowerTree( kIOPMSyncNoChildNotify
);
6244 case kPowerEventPolicyStimulus
:
6247 int stimulus
= (uintptr_t) arg0
;
6248 evaluatePolicy( stimulus
, (uint32_t) arg1
);
6252 case kPowerEventAssertionCreate
:
6254 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
6259 case kPowerEventAssertionRelease
:
6261 pmAssertions
->handleReleaseAssertion(arg1
);
6265 case kPowerEventAssertionSetLevel
:
6267 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
6271 case kPowerEventQueueSleepWakeUUID
:
6272 handleQueueSleepWakeUUID((OSObject
*)arg0
);
6274 case kPowerEventPublishSleepWakeUUID
:
6275 handlePublishSleepWakeUUID((bool)arg0
);
6278 case kPowerEventSetDisplayPowerOn
:
6279 if (!wrangler
) break;
6282 displayPowerOnRequested
= true;
6286 displayPowerOnRequested
= false;
6288 handleDisplayPowerOn();
6293 //******************************************************************************
6294 // systemPowerEventOccurred
6296 // The power controller is notifying us of a hardware-related power management
6297 // event that we must handle.
6299 // systemPowerEventOccurred covers the same functionality that
6300 // receivePowerNotification does; it simply provides a richer API for conveying
6301 // more information.
6302 //******************************************************************************
6304 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6305 const OSSymbol
*event
,
6308 IOReturn attempt
= kIOReturnSuccess
;
6309 OSNumber
*newNumber
= NULL
;
6312 return kIOReturnBadArgument
;
6314 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
6316 return kIOReturnInternalError
;
6318 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
6320 newNumber
->release();
6325 void IOPMrootDomain::setThermalState(OSObject
*value
)
6329 if (gIOPMWorkLoop
->inGate() == false) {
6330 gIOPMWorkLoop
->runAction(
6331 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setThermalState
),
6337 if (value
&& (num
= OSDynamicCast(OSNumber
, value
))) {
6338 thermalWarningState
= ((num
->unsigned32BitValue() == kIOPMThermalLevelWarning
) ||
6339 (num
->unsigned32BitValue() == kIOPMThermalLevelTrap
)) ? 1 : 0;
6343 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6344 const OSSymbol
*event
,
6347 OSDictionary
*thermalsDict
= NULL
;
6348 bool shouldUpdate
= true;
6350 if (!event
|| !value
)
6351 return kIOReturnBadArgument
;
6354 // We reuse featuresDict Lock because it already exists and guards
6355 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
6356 // of stepping on that lock.
6357 if (featuresDictLock
) IOLockLock(featuresDictLock
);
6359 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
6361 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
6362 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
6364 thermalsDict
= OSDictionary::withCapacity(1);
6367 if (!thermalsDict
) {
6368 shouldUpdate
= false;
6372 thermalsDict
->setObject (event
, value
);
6374 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
6376 thermalsDict
->release();
6380 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
6384 event
->isEqualTo(kIOPMThermalLevelWarningKey
)) {
6385 setThermalState(value
);
6387 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
6390 return kIOReturnSuccess
;
6393 //******************************************************************************
6394 // receivePowerNotification
6396 // The power controller is notifying us of a hardware-related power management
6397 // event that we must handle. This may be a result of an 'environment' interrupt
6398 // from the power mgt micro.
6399 //******************************************************************************
6401 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
6403 pmPowerStateQueue
->submitPowerEvent(
6404 kPowerEventReceivedPowerNotification
, (void *)(uintptr_t) msg
);
6405 return kIOReturnSuccess
;
6408 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
6410 bool eval_clamshell
= false;
6415 * Local (IOPMrootDomain only) eval clamshell command
6417 if (msg
& kLocalEvalClamshellCommand
)
6419 eval_clamshell
= true;
6425 if (msg
& kIOPMOverTemp
)
6427 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
6428 privateSleepSystem (kIOPMSleepReasonThermalEmergency
);
6432 * Forward DW thermal notification to client, if system is not going to sleep
6434 if ((msg
& kIOPMDWOverTemp
) && (_systemTransitionType
!= kSystemTransitionSleep
))
6436 DLOG("DarkWake thermal limits message received!\n");
6438 messageClients(kIOPMMessageDarkWakeThermalEmergency
);
6444 if (msg
& kIOPMSleepNow
)
6446 privateSleepSystem (kIOPMSleepReasonSoftware
);
6452 if (msg
& kIOPMPowerEmergency
)
6454 lowBatteryCondition
= true;
6455 privateSleepSystem (kIOPMSleepReasonLowPower
);
6461 if (msg
& kIOPMClamshellOpened
)
6463 // Received clamshel open message from clamshell controlling driver
6464 // Update our internal state and tell general interest clients
6465 clamshellClosed
= false;
6466 clamshellExists
= true;
6468 // Don't issue a hid tickle when lid is open and polled on wake
6469 if (msg
& kIOPMSetValue
)
6471 setProperty(kIOPMRootDomainWakeTypeKey
, "Lid Open");
6476 informCPUStateChange(kInformLid
, 0);
6478 // Tell general interest clients
6479 sendClientClamshellNotification();
6481 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
6482 || (lastSleepReason
== kIOPMSleepReasonIdle
)
6483 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
6484 if (aborting
) userActivityCount
++;
6485 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
6490 * Send the clamshell interest notification since the lid is closing.
6492 if (msg
& kIOPMClamshellClosed
)
6494 // Received clamshel open message from clamshell controlling driver
6495 // Update our internal state and tell general interest clients
6496 clamshellClosed
= true;
6497 clamshellExists
= true;
6500 informCPUStateChange(kInformLid
, 1);
6502 // Tell general interest clients
6503 sendClientClamshellNotification();
6505 // And set eval_clamshell = so we can attempt
6506 eval_clamshell
= true;
6510 * Set Desktop mode (sent from graphics)
6512 * -> reevaluate lid state
6514 if (msg
& kIOPMSetDesktopMode
)
6516 desktopMode
= (0 != (msg
& kIOPMSetValue
));
6517 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
6519 sendClientClamshellNotification();
6521 // Re-evaluate the lid state
6522 eval_clamshell
= true;
6526 * AC Adaptor connected
6528 * -> reevaluate lid state
6530 if (msg
& kIOPMSetACAdaptorConnected
)
6532 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
6533 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
6536 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
6538 // Tell BSD if AC is connected
6539 // 0 == external power source; 1 == on battery
6540 post_sys_powersource(acAdaptorConnected
? 0:1);
6542 sendClientClamshellNotification();
6544 // Re-evaluate the lid state
6545 eval_clamshell
= true;
6547 // Lack of AC may have latched a display wrangler tickle.
6548 // This mirrors the hardware's USB wake event latch, where a latched
6549 // USB wake event followed by an AC attach will trigger a full wake.
6550 latchDisplayWranglerTickle( false );
6553 // AC presence will reset the standy timer delay adjustment.
6554 _standbyTimerResetSeconds
= 0;
6556 if (!userIsActive
) {
6557 // Reset userActivityTime when power supply is changed(rdr 13789330)
6558 clock_get_uptime(&userActivityTime
);
6563 * Enable Clamshell (external display disappear)
6565 * -> reevaluate lid state
6567 if (msg
& kIOPMEnableClamshell
)
6569 // Re-evaluate the lid state
6570 // System should sleep on external display disappearance
6571 // in lid closed operation.
6572 if (true == clamshellDisabled
)
6574 eval_clamshell
= true;
6577 clamshellDisabled
= false;
6578 sendClientClamshellNotification();
6582 * Disable Clamshell (external display appeared)
6583 * We don't bother re-evaluating clamshell state. If the system is awake,
6584 * the lid is probably open.
6586 if (msg
& kIOPMDisableClamshell
)
6588 clamshellDisabled
= true;
6589 sendClientClamshellNotification();
6593 * Evaluate clamshell and SLEEP if appropiate
6595 if (eval_clamshell
&& clamshellClosed
)
6597 if (shouldSleepOnClamshellClosed())
6598 privateSleepSystem (kIOPMSleepReasonClamshell
);
6600 evaluatePolicy( kStimulusDarkWakeEvaluate
);
6606 if (msg
& kIOPMPowerButton
)
6608 if (!wranglerAsleep
)
6610 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
6611 // Check that power button sleep is enabled
6613 if( kOSBooleanTrue
!= getProperty(pbs
))
6614 privateSleepSystem (kIOPMSleepReasonPowerButton
);
6622 //******************************************************************************
6625 // Evaluate root-domain policy in response to external changes.
6626 //******************************************************************************
6628 void IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
6632 int idleSleepEnabled
: 1;
6633 int idleSleepDisabled
: 1;
6634 int displaySleep
: 1;
6635 int sleepDelayChanged
: 1;
6636 int evaluateDarkWake
: 1;
6637 int adjustPowerState
: 1;
6638 int userBecameInactive
: 1;
6643 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
6650 case kStimulusDisplayWranglerSleep
:
6651 if (!wranglerAsleep
)
6653 // first transition to wrangler sleep or lower
6654 wranglerAsleep
= true;
6655 flags
.bit
.displaySleep
= true;
6659 case kStimulusDisplayWranglerWake
:
6660 displayIdleForDemandSleep
= false;
6661 wranglerAsleep
= false;
6664 case kStimulusEnterUserActiveState
:
6665 if (_preventUserActive
)
6667 DLOG("user active dropped\n");
6672 userIsActive
= true;
6673 userWasActive
= true;
6675 // Stay awake after dropping demand for display power on
6676 if (kFullWakeReasonDisplayOn
== fullWakeReason
)
6677 fullWakeReason
= fFullWakeReasonDisplayOnAndLocalUser
;
6679 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
6680 messageClients(kIOPMMessageUserIsActiveChanged
);
6682 flags
.bit
.idleSleepDisabled
= true;
6685 case kStimulusLeaveUserActiveState
:
6688 userIsActive
= false;
6689 clock_get_uptime(&userBecameInactiveTime
);
6690 flags
.bit
.userBecameInactive
= true;
6692 setProperty(gIOPMUserIsActiveKey
, kOSBooleanFalse
);
6693 messageClients(kIOPMMessageUserIsActiveChanged
);
6697 case kStimulusAggressivenessChanged
:
6699 unsigned long minutesToIdleSleep
= 0;
6700 unsigned long minutesToDisplayDim
= 0;
6701 unsigned long minutesDelta
= 0;
6703 // Fetch latest display and system sleep slider values.
6704 getAggressiveness(kPMMinutesToSleep
, &minutesToIdleSleep
);
6705 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
6706 DLOG("aggressiveness changed: system %u->%u, display %u\n",
6707 (uint32_t) sleepSlider
,
6708 (uint32_t) minutesToIdleSleep
,
6709 (uint32_t) minutesToDisplayDim
);
6711 DLOG("idle time -> %ld secs (ena %d)\n",
6712 idleSeconds
, (minutesToIdleSleep
!= 0));
6714 if (0x7fffffff == minutesToIdleSleep
)
6715 minutesToIdleSleep
= idleSeconds
;
6717 // How long to wait before sleeping the system once
6718 // the displays turns off is indicated by 'extraSleepDelay'.
6720 if ( minutesToIdleSleep
> minutesToDisplayDim
)
6721 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
6722 else if ( minutesToIdleSleep
== minutesToDisplayDim
)
6725 if ((sleepSlider
== 0) && (minutesToIdleSleep
!= 0))
6726 flags
.bit
.idleSleepEnabled
= true;
6728 if ((sleepSlider
!= 0) && (minutesToIdleSleep
== 0))
6729 flags
.bit
.idleSleepDisabled
= true;
6731 if (((minutesDelta
!= extraSleepDelay
) ||
6732 (userActivityTime
!= userActivityTime_prev
)) &&
6733 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
)
6734 flags
.bit
.sleepDelayChanged
= true;
6736 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
6737 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
))
6739 // Reconsider decision to remain in dark wake
6740 flags
.bit
.evaluateDarkWake
= true;
6743 sleepSlider
= minutesToIdleSleep
;
6744 extraSleepDelay
= minutesDelta
;
6745 userActivityTime_prev
= userActivityTime
;
6748 case kStimulusDemandSystemSleep
:
6749 displayIdleForDemandSleep
= true;
6750 if (wrangler
&& wranglerIdleSettings
)
6752 // Request wrangler idle only when demand sleep is triggered
6754 if(CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6756 wrangler
->setProperties(wranglerIdleSettings
);
6757 DLOG("Requested wrangler idle\n");
6760 // arg = sleepReason
6761 changePowerStateWithOverrideTo( SLEEP_STATE
, arg
);
6764 case kStimulusAllowSystemSleepChanged
:
6765 flags
.bit
.adjustPowerState
= true;
6768 case kStimulusDarkWakeActivityTickle
:
6769 // arg == true implies real and not self generated wrangler tickle.
6770 // Update wake type on PM work loop instead of the tickle thread to
6771 // eliminate the possibility of an early tickle clobbering the wake
6772 // type set by the platform driver.
6774 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeHIDActivity
);
6776 if (false == wranglerTickled
)
6778 if (latchDisplayWranglerTickle(true))
6780 DLOG("latched tickle\n");
6784 wranglerTickled
= true;
6785 DLOG("Requesting full wake after dark wake activity tickle\n");
6786 requestFullWake( kFullWakeReasonLocalUser
);
6790 case kStimulusDarkWakeEntry
:
6791 case kStimulusDarkWakeReentry
:
6792 // Any system transitions since the last dark wake transition
6793 // will invalid the stimulus.
6795 if (arg
== _systemStateGeneration
)
6797 DLOG("dark wake entry\n");
6798 systemDarkWake
= true;
6800 // Keep wranglerAsleep an invariant when wrangler is absent
6802 wranglerAsleep
= true;
6804 if (kStimulusDarkWakeEntry
== stimulus
)
6806 clock_get_uptime(&userBecameInactiveTime
);
6807 flags
.bit
.evaluateDarkWake
= true;
6810 // Always accelerate disk spindown while in dark wake,
6811 // even if system does not support/allow sleep.
6813 cancelIdleSleepTimer();
6814 setQuickSpinDownTimeout();
6818 case kStimulusDarkWakeEvaluate
:
6821 flags
.bit
.evaluateDarkWake
= true;
6825 case kStimulusNoIdleSleepPreventers
:
6826 flags
.bit
.adjustPowerState
= true;
6829 } /* switch(stimulus) */
6831 if (flags
.bit
.evaluateDarkWake
&& (kFullWakeReasonNone
== fullWakeReason
))
6833 if (darkWakeToSleepASAP
||
6834 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
)))
6836 uint32_t newSleepReason
;
6838 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
6840 // System was previously in full wake. Sleep reason from
6841 // full to dark already recorded in fullToDarkReason.
6843 if (lowBatteryCondition
)
6844 newSleepReason
= kIOPMSleepReasonLowPower
;
6846 newSleepReason
= fullToDarkReason
;
6850 // In dark wake from system sleep.
6852 if (darkWakeSleepService
)
6853 newSleepReason
= kIOPMSleepReasonSleepServiceExit
;
6855 newSleepReason
= kIOPMSleepReasonMaintenance
;
6858 if (checkSystemCanSleep(newSleepReason
))
6860 privateSleepSystem(newSleepReason
);
6863 else // non-maintenance (network) dark wake
6865 if (checkSystemCanSleep(kIOPMSleepReasonIdle
))
6867 // Release power clamp, and wait for children idle.
6868 adjustPowerState(true);
6872 changePowerStateToPriv(ON_STATE
);
6879 // The rest are irrelevant while system is in dark wake.
6883 if ((flags
.bit
.displaySleep
) &&
6884 (kFullWakeReasonDisplayOn
== fullWakeReason
))
6886 // kIOPMSleepReasonMaintenance?
6887 changePowerStateWithOverrideTo( SLEEP_STATE
, kIOPMSleepReasonMaintenance
);
6890 if (flags
.bit
.userBecameInactive
|| flags
.bit
.sleepDelayChanged
)
6892 bool cancelQuickSpindown
= false;
6894 if (flags
.bit
.sleepDelayChanged
)
6896 // Cancel existing idle sleep timer and quick disk spindown.
6897 // New settings will be applied by the idleSleepEnabled flag
6898 // handler below if idle sleep is enabled.
6900 DLOG("extra sleep timer changed\n");
6901 cancelIdleSleepTimer();
6902 cancelQuickSpindown
= true;
6906 DLOG("user inactive\n");
6909 if (!userIsActive
&& sleepSlider
)
6911 startIdleSleepTimer(getTimeToIdleSleep());
6914 if (cancelQuickSpindown
)
6915 restoreUserSpinDownTimeout();
6918 if (flags
.bit
.idleSleepEnabled
)
6920 DLOG("idle sleep timer enabled\n");
6923 changePowerStateToPriv(ON_STATE
);
6926 startIdleSleepTimer( idleSeconds
);
6931 // Start idle timer if prefs now allow system sleep
6932 // and user is already inactive. Disk spindown is
6933 // accelerated upon timer expiration.
6937 startIdleSleepTimer(getTimeToIdleSleep());
6942 if (flags
.bit
.idleSleepDisabled
)
6944 DLOG("idle sleep timer disabled\n");
6945 cancelIdleSleepTimer();
6946 restoreUserSpinDownTimeout();
6950 if (flags
.bit
.adjustPowerState
)
6952 bool sleepASAP
= false;
6954 if (!systemBooting
&& (preventIdleSleepList
->getCount() == 0))
6958 changePowerStateToPriv(ON_STATE
);
6961 // stay awake for at least idleSeconds
6962 startIdleSleepTimer(idleSeconds
);
6965 else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
)
6971 adjustPowerState(sleepASAP
);
6975 //******************************************************************************
6978 // Request transition from dark wake to full wake
6979 //******************************************************************************
6981 void IOPMrootDomain::requestFullWake( FullWakeReason reason
)
6983 uint32_t options
= 0;
6984 IOService
* pciRoot
= 0;
6985 bool promotion
= false;
6987 // System must be in dark wake and a valid reason for entering full wake
6988 if ((kFullWakeReasonNone
== reason
) ||
6989 (kFullWakeReasonNone
!= fullWakeReason
) ||
6990 (CAP_CURRENT(kIOPMSystemCapabilityGraphics
)))
6995 // Will clear reason upon exit from full wake
6996 fullWakeReason
= reason
;
6998 _desiredCapability
|= (kIOPMSystemCapabilityGraphics
|
6999 kIOPMSystemCapabilityAudio
);
7001 if ((kSystemTransitionWake
== _systemTransitionType
) &&
7002 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
7003 !graphicsSuppressed
)
7005 // Promote to full wake while waking up to dark wake due to tickle.
7006 // PM will hold off notifying the graphics subsystem about system wake
7007 // as late as possible, so if a HID tickle does arrive, graphics can
7008 // power up on this same wake cycle. The latency to power up graphics
7009 // on the next cycle can be huge on some systems. However, once any
7010 // graphics suppression has taken effect, it is too late. All other
7011 // graphics devices must be similarly suppressed. But the delay till
7012 // the following cycle should be short.
7014 _pendingCapability
|= (kIOPMSystemCapabilityGraphics
|
7015 kIOPMSystemCapabilityAudio
);
7017 // Immediately bring up audio and graphics
7018 pciRoot
= pciHostBridgeDriver
;
7019 willEnterFullWake();
7023 // Unsafe to cancel once graphics was powered.
7024 // If system woke from dark wake, the return to sleep can
7025 // be cancelled. "awake -> dark -> sleep" transition
7026 // can be canceled also, during the "dark --> sleep" phase
7027 // *prior* to driver power down.
7028 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) ||
7029 _pendingCapability
== 0) {
7030 options
|= kIOPMSyncCancelPowerDown
;
7033 synchronizePowerTree(options
, pciRoot
);
7034 if (kFullWakeReasonLocalUser
== fullWakeReason
)
7036 // IOGraphics doesn't light the display even though graphics is
7037 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
7038 // So, do an explicit activity tickle
7040 wrangler
->activityTickle(0,0);
7043 // Log a timestamp for the initial full wake request.
7044 // System may not always honor this full wake request.
7045 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
7050 clock_get_uptime(&now
);
7051 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
7052 absolutetime_to_nanoseconds(now
, &nsec
);
7053 MSG("full wake %s (reason %u) %u ms\n",
7054 promotion
? "promotion" : "request",
7055 fullWakeReason
, ((int)((nsec
) / 1000000ULL)));
7059 //******************************************************************************
7060 // willEnterFullWake
7062 // System will enter full wake from sleep, from dark wake, or from dark
7063 // wake promotion. This function aggregate things that are in common to
7064 // all three full wake transitions.
7066 // Assumptions: fullWakeReason was updated
7067 //******************************************************************************
7069 void IOPMrootDomain::willEnterFullWake( void )
7071 hibernateRetry
= false;
7072 sleepToStandby
= false;
7073 sleepTimerMaintenance
= false;
7075 _systemMessageClientMask
= kSystemMessageClientPowerd
|
7076 kSystemMessageClientLegacyApp
;
7078 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
7080 // Initial graphics full power
7081 _systemMessageClientMask
|= kSystemMessageClientKernel
;
7083 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
7084 setProperty(gIOPMUserTriggeredFullWakeKey
,
7085 (kFullWakeReasonLocalUser
== fullWakeReason
) ?
7086 kOSBooleanTrue
: kOSBooleanFalse
);
7089 IOHibernateSetWakeCapabilities(_pendingCapability
);
7092 IOService::setAdvisoryTickleEnable( true );
7093 tellClients(kIOMessageSystemWillPowerOn
);
7094 preventTransitionToUserActive(false);
7097 //******************************************************************************
7098 // fullWakeDelayedWork
7100 // System has already entered full wake. Invoked by a delayed thread call.
7101 //******************************************************************************
7103 void IOPMrootDomain::fullWakeDelayedWork( void )
7105 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
7106 // Not gated, don't modify state
7107 if ((kSystemTransitionNone
== _systemTransitionType
) &&
7108 CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
7110 receivePowerNotification( kLocalEvalClamshellCommand
);
7115 //******************************************************************************
7116 // evaluateAssertions
7118 //******************************************************************************
7119 void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions
, IOPMDriverAssertionType oldAssertions
)
7121 IOPMDriverAssertionType changedBits
= newAssertions
^ oldAssertions
;
7123 messageClients(kIOPMMessageDriverAssertionsChanged
);
7125 if (changedBits
& kIOPMDriverAssertionPreventDisplaySleepBit
) {
7128 bool value
= (newAssertions
& kIOPMDriverAssertionPreventDisplaySleepBit
) ? true : false;
7130 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value
);
7131 wrangler
->setIgnoreIdleTimer( value
);
7135 if (changedBits
& kIOPMDriverAssertionCPUBit
) {
7136 evaluatePolicy(kStimulusDarkWakeEvaluate
);
7137 if (!assertOnWakeSecs
&& systemWakeTime
) {
7139 clock_usec_t microsecs
;
7140 clock_get_uptime(&now
);
7141 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
7142 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
7143 if (assertOnWakeReport
) {
7144 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
7145 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
7150 if (changedBits
& kIOPMDriverAssertionReservedBit7
) {
7151 bool value
= (newAssertions
& kIOPMDriverAssertionReservedBit7
) ? true : false;
7153 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
7154 updatePreventIdleSleepList(this, true);
7157 DLOG("Driver assertion ReservedBit7 dropped\n");
7158 updatePreventIdleSleepList(this, false);
7166 //******************************************************************************
7169 //******************************************************************************
7171 void IOPMrootDomain::pmStatsRecordEvent(
7173 AbsoluteTime timestamp
)
7175 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
7176 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
7179 OSData
*publishPMStats
= NULL
;
7181 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
7183 absolutetime_to_nanoseconds(timestamp
, &nsec
);
7185 switch (eventIndex
) {
7186 case kIOPMStatsHibernateImageWrite
:
7188 gPMStats
.hibWrite
.start
= nsec
;
7190 gPMStats
.hibWrite
.stop
= nsec
;
7193 delta
= gPMStats
.hibWrite
.stop
- gPMStats
.hibWrite
.start
;
7194 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/1000000ULL);
7197 case kIOPMStatsHibernateImageRead
:
7199 gPMStats
.hibRead
.start
= nsec
;
7201 gPMStats
.hibRead
.stop
= nsec
;
7204 delta
= gPMStats
.hibRead
.stop
- gPMStats
.hibRead
.start
;
7205 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/1000000ULL);
7207 publishPMStats
= OSData::withBytes(&gPMStats
, sizeof(gPMStats
));
7208 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
7209 publishPMStats
->release();
7210 bzero(&gPMStats
, sizeof(gPMStats
));
7217 * Appends a record of the application response to
7218 * IOPMrootDomain::pmStatsAppResponses
7220 void IOPMrootDomain::pmStatsRecordApplicationResponse(
7221 const OSSymbol
*response
,
7227 IOPMPowerStateIndex powerState
)
7229 OSDictionary
*responseDescription
= NULL
;
7230 OSNumber
*delayNum
= NULL
;
7231 OSNumber
*powerCaps
= NULL
;
7232 OSNumber
*pidNum
= NULL
;
7233 OSNumber
*msgNum
= NULL
;
7234 const OSSymbol
*appname
;
7235 const OSSymbol
*sleep
= NULL
, *wake
= NULL
;
7236 IOPMServiceInterestNotifier
*notify
= 0;
7238 if (object
&& (notify
= OSDynamicCast(IOPMServiceInterestNotifier
, object
)))
7240 if (response
->isEqualTo(gIOPMStatsApplicationResponseTimedOut
))
7241 notify
->ackTimeoutCnt
++;
7243 notify
->ackTimeoutCnt
= 0;
7247 if (response
->isEqualTo(gIOPMStatsApplicationResponsePrompt
) ||
7248 (_systemTransitionType
== kSystemTransitionNone
) || (_systemTransitionType
== kSystemTransitionNewCapClient
))
7252 responseDescription
= OSDictionary::withCapacity(5);
7253 if (responseDescription
)
7256 responseDescription
->setObject(_statsResponseTypeKey
, response
);
7259 msgNum
= OSNumber::withNumber(messageType
, 32);
7261 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
7265 if (name
&& (strlen(name
) > 0))
7267 appname
= OSSymbol::withCString(name
);
7269 responseDescription
->setObject(_statsNameKey
, appname
);
7274 if (app_pid
!= -1) {
7275 pidNum
= OSNumber::withNumber(app_pid
, 32);
7277 responseDescription
->setObject(_statsPIDKey
, pidNum
);
7282 delayNum
= OSNumber::withNumber(delay_ms
, 32);
7284 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
7285 delayNum
->release();
7288 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
7289 powerCaps
= OSNumber::withNumber(powerState
, 32);
7291 #if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
7292 IOLog("%s::powerStateChange type(%d) to(%lu) async took %d ms\n",
7294 powerState
, delay_ms
);
7299 powerCaps
= OSNumber::withNumber(_pendingCapability
, 32);
7302 responseDescription
->setObject(_statsPowerCapsKey
, powerCaps
);
7303 powerCaps
->release();
7306 sleep
= OSSymbol::withCString("Sleep");
7307 wake
= OSSymbol::withCString("Wake");
7308 if (_systemTransitionType
== kSystemTransitionSleep
) {
7309 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7311 else if (_systemTransitionType
== kSystemTransitionWake
) {
7312 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7314 else if (_systemTransitionType
== kSystemTransitionCapability
) {
7315 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
7316 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7317 else if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
7318 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7320 if (sleep
) sleep
->release();
7321 if (wake
) wake
->release();
7325 IOLockLock(pmStatsLock
);
7326 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount() < 50) {
7327 pmStatsAppResponses
->setObject(responseDescription
);
7329 IOLockUnlock(pmStatsLock
);
7331 responseDescription
->release();
7338 // MARK: PMTraceWorker
7340 //******************************************************************************
7341 // TracePoint support
7343 //******************************************************************************
7345 #define kIOPMRegisterNVRAMTracePointHandlerKey \
7346 "IOPMRegisterNVRAMTracePointHandler"
7348 IOReturn
IOPMrootDomain::callPlatformFunction(
7349 const OSSymbol
* functionName
,
7350 bool waitForFunction
,
7351 void * param1
, void * param2
,
7352 void * param3
, void * param4
)
7354 if (pmTracer
&& functionName
&&
7355 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
7356 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
7358 uint32_t tracePointPhases
, tracePointPCI
;
7359 uint64_t statusCode
;
7361 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
7362 pmTracer
->tracePointTarget
= (void *) param2
;
7363 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
7364 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
7365 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
7366 if ((tracePointPhases
>> 24) != kIOPMTracePointSystemUp
)
7368 MSG("Sleep failure code 0x%08x 0x%08x\n",
7369 tracePointPCI
, tracePointPhases
);
7371 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
7372 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
7374 return kIOReturnSuccess
;
7377 else if (functionName
&&
7378 functionName
->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey
))
7380 if (gSleepPolicyHandler
)
7381 return kIOReturnExclusiveAccess
;
7383 return kIOReturnBadArgument
;
7384 gSleepPolicyHandler
= (IOPMSystemSleepPolicyHandler
) param1
;
7385 gSleepPolicyTarget
= (void *) param2
;
7386 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue
);
7387 return kIOReturnSuccess
;
7391 return super::callPlatformFunction(
7392 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
7395 void IOPMrootDomain::tracePoint( uint8_t point
)
7397 if (systemBooting
) return;
7399 if (kIOPMTracePointWakeCapabilityClients
== point
)
7400 acceptSystemWakeEvents(false);
7402 PMDebug(kPMLogSleepWakeTracePoint
, point
, 0);
7403 pmTracer
->tracePoint(point
);
7406 void IOPMrootDomain::tracePoint( uint8_t point
, uint8_t data
)
7408 if (systemBooting
) return;
7410 PMDebug(kPMLogSleepWakeTracePoint
, point
, data
);
7411 pmTracer
->tracePoint(point
, data
);
7414 void IOPMrootDomain::traceDetail( uint32_t detail
)
7417 pmTracer
->traceDetail( detail
);
7421 void IOPMrootDomain::configureReportGated(uint64_t channel_id
, uint64_t action
, void *result
)
7424 void **report
= NULL
;
7427 uint32_t *clientCnt
;
7432 if (channel_id
== kAssertDelayChID
) {
7433 report
= &assertOnWakeReport
;
7434 bktCnt
= kAssertDelayBcktCnt
;
7435 bktSize
= kAssertDelayBcktSize
;
7436 clientCnt
= &assertOnWakeClientCnt
;
7438 else if (channel_id
== kSleepDelaysChID
) {
7439 report
= &sleepDelaysReport
;
7440 bktCnt
= kSleepDelaysBcktCnt
;
7441 bktSize
= kSleepDelaysBcktSize
;
7442 clientCnt
= &sleepDelaysClientCnt
;
7447 case kIOReportEnable
:
7454 reportSize
= HISTREPORT_BUFSIZE(bktCnt
);
7455 *report
= IOMalloc(reportSize
);
7456 if (*report
== NULL
) {
7459 bzero(*report
, reportSize
);
7460 HISTREPORT_INIT(bktCnt
, bktSize
, *report
, reportSize
,
7461 getRegistryEntryID(), channel_id
, kIOReportCategoryPower
);
7463 if (channel_id
== kAssertDelayChID
)
7464 assertOnWakeSecs
= 0;
7468 case kIOReportDisable
:
7469 if (*clientCnt
== 0) {
7472 if (*clientCnt
== 1)
7474 IOFree(*report
, HISTREPORT_BUFSIZE(bktCnt
));
7479 if (channel_id
== kAssertDelayChID
)
7480 assertOnWakeSecs
= -1; // Invalid value to prevent updates
7484 case kIOReportGetDimensions
:
7486 HISTREPORT_UPDATERES(*report
, kIOReportGetDimensions
, result
);
7494 IOReturn
IOPMrootDomain::configureReport(IOReportChannelList
*channelList
,
7495 IOReportConfigureAction action
,
7500 uint64_t configAction
= (uint64_t)action
;
7502 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7503 if ( (channelList
->channels
[cnt
].channel_id
== kSleepCntChID
) ||
7504 (channelList
->channels
[cnt
].channel_id
== kDarkWkCntChID
) ||
7505 (channelList
->channels
[cnt
].channel_id
== kUserWkCntChID
) ) {
7506 if (action
!= kIOReportGetDimensions
) continue;
7507 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions
, result
);
7509 else if ((channelList
->channels
[cnt
].channel_id
== kAssertDelayChID
) ||
7510 (channelList
->channels
[cnt
].channel_id
== kSleepDelaysChID
)) {
7511 gIOPMWorkLoop
->runAction(
7512 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::configureReportGated
),
7513 (OSObject
*)this, (void *)channelList
->channels
[cnt
].channel_id
,
7514 (void *)configAction
, (void *)result
);
7518 return super::configureReport(channelList
, action
, result
, destination
);
7521 IOReturn
IOPMrootDomain::updateReportGated(uint64_t ch_id
, void *result
, IOBufferMemoryDescriptor
*dest
)
7531 if (ch_id
== kAssertDelayChID
) {
7532 report
= &assertOnWakeReport
;
7534 else if (ch_id
== kSleepDelaysChID
) {
7535 report
= &sleepDelaysReport
;
7538 if (*report
== NULL
) {
7539 return kIOReturnNotOpen
;
7542 HISTREPORT_UPDATEPREP(*report
, data2cpy
, size2cpy
);
7543 if (size2cpy
> (dest
->getCapacity() - dest
->getLength()) ) {
7544 return kIOReturnOverrun
;
7547 HISTREPORT_UPDATERES(*report
, kIOReportCopyChannelData
, result
);
7548 dest
->appendBytes(data2cpy
, size2cpy
);
7550 return kIOReturnSuccess
;
7553 IOReturn
IOPMrootDomain::updateReport(IOReportChannelList
*channelList
,
7554 IOReportUpdateAction action
,
7560 uint8_t buf
[SIMPLEREPORT_BUFSIZE
];
7561 IOBufferMemoryDescriptor
*dest
= OSDynamicCast(IOBufferMemoryDescriptor
, (OSObject
*)destination
);
7565 if (action
!= kIOReportCopyChannelData
) goto exit
;
7567 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7568 ch_id
= channelList
->channels
[cnt
].channel_id
;
7570 if ((ch_id
== kAssertDelayChID
) || (ch_id
== kSleepDelaysChID
)) {
7571 gIOPMWorkLoop
->runAction(
7572 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::updateReportGated
),
7573 (OSObject
*)this, (void *)ch_id
,
7574 (void *)result
, (void *)dest
);
7578 else if ((ch_id
== kSleepCntChID
) ||
7579 (ch_id
== kDarkWkCntChID
) || (ch_id
== kUserWkCntChID
)) {
7580 SIMPLEREPORT_INIT(buf
, sizeof(buf
), getRegistryEntryID(), ch_id
, kIOReportCategoryPower
);
7584 if (ch_id
== kSleepCntChID
)
7585 SIMPLEREPORT_SETVALUE(buf
, sleepCnt
);
7586 else if (ch_id
== kDarkWkCntChID
)
7587 SIMPLEREPORT_SETVALUE(buf
, darkWakeCnt
);
7588 else if (ch_id
== kUserWkCntChID
)
7589 SIMPLEREPORT_SETVALUE(buf
, displayWakeCnt
);
7591 SIMPLEREPORT_UPDATEPREP(buf
, data2cpy
, size2cpy
);
7592 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData
, result
);
7593 dest
->appendBytes(data2cpy
, size2cpy
);
7597 return super::updateReport(channelList
, action
, result
, destination
);
7601 //******************************************************************************
7602 // PMTraceWorker Class
7604 //******************************************************************************
7607 #define super OSObject
7608 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
7610 #define kPMBestGuessPCIDevicesCount 25
7611 #define kPMMaxRTCBitfieldSize 32
7613 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
7617 me
= OSTypeAlloc( PMTraceWorker
);
7618 if (!me
|| !me
->init())
7623 DLOG("PMTraceWorker %p\n", OBFUSCATE(me
));
7625 // Note that we cannot instantiate the PCI device -> bit mappings here, since
7626 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
7627 // this dictionary lazily.
7629 me
->pciDeviceBitMappings
= NULL
;
7630 me
->pciMappingLock
= IOLockAlloc();
7631 me
->tracePhase
= kIOPMTracePointSystemUp
;
7632 me
->loginWindowPhase
= 0;
7633 me
->traceData32
= 0;
7637 void PMTraceWorker::RTC_TRACE(void)
7639 if (tracePointHandler
&& tracePointTarget
)
7643 wordA
= (tracePhase
<< 24) | (loginWindowPhase
<< 16) |
7646 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
7647 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
7651 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
7653 const OSSymbol
* deviceName
;
7656 IOLockLock(pciMappingLock
);
7658 if (!pciDeviceBitMappings
)
7660 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
7661 if (!pciDeviceBitMappings
)
7665 // Check for bitmask overflow.
7666 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
7669 if ((deviceName
= pciDevice
->copyName()) &&
7670 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
7671 pciDeviceBitMappings
->setObject(deviceName
))
7673 index
= pciDeviceBitMappings
->getCount() - 1;
7674 _LOG("PMTrace PCI array: set object %s => %d\n",
7675 deviceName
->getCStringNoCopy(), index
);
7678 deviceName
->release();
7679 if (!addedToRegistry
&& (index
>= 0))
7680 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
7683 IOLockUnlock(pciMappingLock
);
7687 bool PMTraceWorker::serialize(OSSerialize
*s
) const
7690 if (pciDeviceBitMappings
)
7692 IOLockLock(pciMappingLock
);
7693 ok
= pciDeviceBitMappings
->serialize(s
);
7694 IOLockUnlock(pciMappingLock
);
7699 void PMTraceWorker::tracePoint(uint8_t phase
)
7701 // clear trace detail when phase begins
7702 if (tracePhase
!= phase
)
7707 DLOG("trace point 0x%02x\n", tracePhase
);
7711 void PMTraceWorker::tracePoint(uint8_t phase
, uint8_t data8
)
7713 // clear trace detail when phase begins
7714 if (tracePhase
!= phase
)
7720 DLOG("trace point 0x%02x 0x%02x\n", tracePhase
, traceData8
);
7724 void PMTraceWorker::traceDetail(uint32_t detail
)
7726 if (kIOPMTracePointSleepPriorityClients
!= tracePhase
)
7729 traceData32
= detail
;
7730 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
7735 void PMTraceWorker::traceLoginWindowPhase(uint8_t phase
)
7737 loginWindowPhase
= phase
;
7739 DLOG("loginwindow tracepoint 0x%02x\n", loginWindowPhase
);
7743 void PMTraceWorker::tracePCIPowerChange(
7744 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
7747 uint32_t expectedFlag
;
7749 // Ignore PCI changes outside of system sleep/wake.
7750 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
7751 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
))
7754 // Only record the WillChange transition when going to sleep,
7755 // and the DidChange on the way up.
7756 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
7757 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
7758 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
7759 if (changeFlags
!= expectedFlag
)
7762 // Mark this device off in our bitfield
7763 if (bitNum
< kPMMaxRTCBitfieldSize
)
7765 bitMask
= (1 << bitNum
);
7767 if (kPowerChangeStart
== type
)
7769 traceData32
|= bitMask
;
7770 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
7771 service
->getName(), bitNum
, bitMask
, traceData32
);
7775 traceData32
&= ~bitMask
;
7776 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
7777 service
->getName(), bitNum
, bitMask
, traceData32
);
7780 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
7785 uint64_t PMTraceWorker::getPMStatusCode( )
7787 return (((uint64_t)traceData32
<< 32) | ((uint64_t)tracePhase
<< 24) |
7788 (loginWindowPhase
<< 16) | (traceData8
<< 8));
7793 // MARK: PMHaltWorker
7795 //******************************************************************************
7796 // PMHaltWorker Class
7798 //******************************************************************************
7800 PMHaltWorker
* PMHaltWorker::worker( void )
7806 me
= OSTypeAlloc( PMHaltWorker
);
7807 if (!me
|| !me
->init())
7810 me
->lock
= IOLockAlloc();
7814 DLOG("PMHaltWorker %p\n", OBFUSCATE(me
));
7815 me
->retain(); // thread holds extra retain
7816 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
7821 thread_deallocate(thread
);
7826 if (me
) me
->release();
7830 void PMHaltWorker::free( void )
7832 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
7838 return OSObject::free();
7841 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
7843 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
7845 IOLockLock( gPMHaltLock
);
7847 me
->depth
= gPMHaltDepth
;
7848 IOLockUnlock( gPMHaltLock
);
7850 while (me
->depth
>= 0)
7852 PMHaltWorker::work( me
);
7854 IOLockLock( gPMHaltLock
);
7855 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
7857 // This is the last thread to finish work on this level,
7858 // inform everyone to start working on next lower level.
7860 me
->depth
= gPMHaltDepth
;
7861 gPMHaltIdleCount
= 0;
7862 thread_wakeup((event_t
) &gPMHaltIdleCount
);
7866 // One or more threads are still working on this level,
7867 // this thread must wait.
7868 me
->depth
= gPMHaltDepth
- 1;
7870 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
7871 } while (me
->depth
!= gPMHaltDepth
);
7873 IOLockUnlock( gPMHaltLock
);
7876 // No more work to do, terminate thread
7877 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me
), me
->visits
);
7878 thread_wakeup( &gPMHaltDepth
);
7882 void PMHaltWorker::work( PMHaltWorker
* me
)
7884 IOService
* service
;
7886 AbsoluteTime startTime
;
7895 // Claim an unit of work from the shared pool
7896 IOLockLock( gPMHaltLock
);
7897 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
7900 service
= (IOService
*)inner
->getAnyObject();
7904 inner
->removeObject(service
);
7907 IOLockUnlock( gPMHaltLock
);
7909 break; // no more work at this depth
7911 clock_get_uptime(&startTime
);
7913 if (!service
->isInactive() &&
7914 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
7916 IOLockLock(me
->lock
);
7917 me
->startTime
= startTime
;
7918 me
->service
= service
;
7919 me
->timeout
= false;
7920 IOLockUnlock(me
->lock
);
7922 service
->systemWillShutdown( gPMHaltMessageType
);
7924 // Wait for driver acknowledgement
7925 IOLockLock(me
->lock
);
7926 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
7928 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
7931 timeout
= me
->timeout
;
7932 IOLockUnlock(me
->lock
);
7935 deltaTime
= computeDeltaTimeMS(&startTime
);
7936 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
7937 (gIOKitDebug
& kIOLogPMRootDomain
))
7939 LOG("%s driver %s (0x%llx) took %u ms\n",
7940 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ?
7941 "PowerOff" : "Restart",
7942 service
->getName(), service
->getRegistryEntryID(),
7943 (uint32_t) deltaTime
);
7951 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
7954 AbsoluteTime startTime
;
7955 AbsoluteTime endTime
;
7959 IOLockLock(me
->lock
);
7960 if (me
->service
&& !me
->timeout
)
7962 startTime
= me
->startTime
;
7964 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
7966 SUB_ABSOLUTETIME(&endTime
, &startTime
);
7967 absolutetime_to_nanoseconds(endTime
, &nano
);
7969 if (nano
> 3000000000ULL)
7972 MSG("%s still waiting on %s\n",
7973 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ?
7974 "PowerOff" : "Restart",
7975 me
->service
->getName());
7978 IOLockUnlock(me
->lock
);
7981 //******************************************************************************
7982 // acknowledgeSystemWillShutdown
7984 // Acknowledgement from drivers that they have prepared for shutdown/restart.
7985 //******************************************************************************
7987 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
7989 PMHaltWorker
* worker
;
7995 //DLOG("%s acknowledged\n", from->getName());
7996 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
7999 worker
= (PMHaltWorker
*) prop
;
8000 IOLockLock(worker
->lock
);
8001 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
8002 thread_wakeup((event_t
) worker
);
8003 IOLockUnlock(worker
->lock
);
8008 DLOG("%s acknowledged without worker property\n",
8014 //******************************************************************************
8015 // notifySystemShutdown
8017 // Notify all objects in PM tree that system will shutdown or restart
8018 //******************************************************************************
8021 notifySystemShutdown( IOService
* root
, uint32_t messageType
)
8023 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
8024 IORegistryIterator
* iter
;
8025 IORegistryEntry
* entry
;
8028 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
8029 AbsoluteTime deadline
;
8030 unsigned int totalNodes
= 0;
8032 unsigned int rootDepth
;
8033 unsigned int numWorkers
;
8039 DLOG("%s msgType = 0x%x\n", __FUNCTION__
, messageType
);
8041 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
8043 // Iterate the entire PM tree starting from root
8045 rootDepth
= root
->getDepth( gIOPowerPlane
);
8046 if (!rootDepth
) goto done
;
8048 // debug - for repeated test runs
8049 while (PMHaltWorker::metaClass
->getInstanceCount())
8054 gPMHaltArray
= OSArray::withCapacity(40);
8055 if (!gPMHaltArray
) goto done
;
8058 gPMHaltArray
->flushCollection();
8062 gPMHaltLock
= IOLockAlloc();
8063 if (!gPMHaltLock
) goto done
;
8066 if (!gPMHaltClientAcknowledgeKey
)
8068 gPMHaltClientAcknowledgeKey
=
8069 OSSymbol::withCStringNoCopy("PMShutdown");
8070 if (!gPMHaltClientAcknowledgeKey
) goto done
;
8073 gPMHaltMessageType
= messageType
;
8075 // Depth-first walk of PM plane
8077 iter
= IORegistryIterator::iterateOver(
8078 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
8082 while ((entry
= iter
->getNextObject()))
8084 node
= OSDynamicCast(IOService
, entry
);
8089 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
8092 depth
= node
->getDepth( gIOPowerPlane
);
8093 if (depth
<= rootDepth
)
8098 // adjust to zero based depth
8099 depth
-= (rootDepth
+ 1);
8101 // gPMHaltArray is an array of containers, each container
8102 // refers to nodes with the same depth.
8104 count
= gPMHaltArray
->getCount();
8105 while (depth
>= count
)
8107 // expand array and insert placeholders
8108 gPMHaltArray
->setObject(PLACEHOLDER
);
8111 count
= gPMHaltArray
->getCount();
8114 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
8115 if (inner
== PLACEHOLDER
)
8117 inner
= OSSet::withCapacity(40);
8120 gPMHaltArray
->replaceObject(depth
, inner
);
8125 // PM nodes that appear more than once in the tree will have
8126 // the same depth, OSSet will refuse to add the node twice.
8128 ok
= inner
->setObject(node
);
8131 DLOG("Skipped PM node %s\n", node
->getName());
8137 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
8140 if (inner
!= PLACEHOLDER
)
8141 count
= inner
->getCount();
8142 DLOG("Nodes at depth %u = %u\n", i
, count
);
8145 // strip placeholders (not all depths are populated)
8147 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
8149 if (inner
== PLACEHOLDER
)
8151 gPMHaltArray
->removeObject(i
);
8154 count
= inner
->getCount();
8155 if (count
> numWorkers
)
8157 totalNodes
+= count
;
8161 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
8164 gPMHaltBusyCount
= 0;
8165 gPMHaltIdleCount
= 0;
8166 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
8168 // Create multiple workers (and threads)
8170 if (numWorkers
> kPMHaltMaxWorkers
)
8171 numWorkers
= kPMHaltMaxWorkers
;
8173 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
8174 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
8176 for (unsigned int i
= 0; i
< numWorkers
; i
++)
8177 workers
[i
] = PMHaltWorker::worker();
8179 // Wait for workers to exhaust all available work
8181 IOLockLock(gPMHaltLock
);
8182 while (gPMHaltDepth
>= 0)
8184 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
8186 waitResult
= IOLockSleepDeadline(
8187 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
8188 if (THREAD_TIMED_OUT
== waitResult
)
8191 clock_get_uptime(&now
);
8193 IOLockUnlock(gPMHaltLock
);
8194 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
8197 PMHaltWorker::checkTimeout(workers
[i
], &now
);
8199 IOLockLock(gPMHaltLock
);
8202 IOLockUnlock(gPMHaltLock
);
8204 // Release all workers
8206 for (unsigned int i
= 0; i
< numWorkers
; i
++)
8209 workers
[i
]->release();
8210 // worker also retained by it's own thread
8214 DLOG("%s done\n", __FUNCTION__
);
8219 // MARK: Kernel Assertion
8221 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8223 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
8224 IOPMDriverAssertionType whichAssertionBits
,
8225 IOPMDriverAssertionLevel assertionLevel
,
8226 IOService
*ownerService
,
8227 const char *ownerDescription
)
8230 IOPMDriverAssertionID newAssertion
;
8235 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
8237 if (kIOReturnSuccess
== ret
)
8238 return newAssertion
;
8243 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
8246 return kIOReturnInternalError
;
8248 return pmAssertions
->releaseAssertion(releaseAssertion
);
8252 IOReturn
IOPMrootDomain::setPMAssertionLevel(
8253 IOPMDriverAssertionID assertionID
,
8254 IOPMDriverAssertionLevel assertionLevel
)
8256 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
8259 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
8261 IOPMDriverAssertionType sysLevels
;
8263 if (!pmAssertions
|| whichAssertion
== 0)
8264 return kIOPMDriverAssertionLevelOff
;
8266 sysLevels
= pmAssertions
->getActivatedAssertions();
8268 // Check that every bit set in argument 'whichAssertion' is asserted
8269 // in the aggregate bits.
8270 if ((sysLevels
& whichAssertion
) == whichAssertion
)
8271 return kIOPMDriverAssertionLevelOn
;
8273 return kIOPMDriverAssertionLevelOff
;
8276 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
8279 return kIOReturnNotFound
;
8281 return pmAssertions
->setUserAssertionLevels(inLevels
);
8284 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
8288 pmAssertions
->publishProperties();
8290 return( IOService::serializeProperties(s
) );
8293 OSObject
* IOPMrootDomain::copyProperty( const char * aKey
) const
8295 OSObject
*obj
= NULL
;
8296 obj
= IOService::copyProperty(aKey
);
8298 if (obj
) return obj
;
8300 if (!strncmp(aKey
, kIOPMSleepWakeWdogRebootKey
,
8301 sizeof(kIOPMSleepWakeWdogRebootKey
))) {
8302 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
)
8303 return kOSBooleanTrue
;
8305 return kOSBooleanFalse
;
8309 if (!strncmp(aKey
, kIOPMSleepWakeWdogLogsValidKey
,
8310 sizeof(kIOPMSleepWakeWdogLogsValidKey
))) {
8311 if (swd_flags
& SWD_VALID_LOGS
)
8312 return kOSBooleanTrue
;
8314 return kOSBooleanFalse
;
8319 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
8320 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
8321 * issued by DisplayWrangler on darkwake.
8323 if (!strcmp(aKey
, "DesktopMode")) {
8325 return kOSBooleanTrue
;
8327 return kOSBooleanFalse
;
8329 if (!strcmp(aKey
, "DisplayIdleForDemandSleep")) {
8330 if (displayIdleForDemandSleep
) {
8331 return kOSBooleanTrue
;
8334 return kOSBooleanFalse
;
8338 if (!strcmp(aKey
, kIOPMDriverWakeEventsKey
))
8340 OSArray
* array
= 0;
8342 if (_systemWakeEventsArray
&& _systemWakeEventsArray
->getCount()) {
8343 OSCollection
*collection
= _systemWakeEventsArray
->copyCollection();
8344 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
8345 collection
->release();
8352 if (!strcmp(aKey
, kIOPMSleepStatisticsAppsKey
))
8354 OSArray
* array
= 0;
8355 IOLockLock(pmStatsLock
);
8356 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount()) {
8357 OSCollection
*collection
= pmStatsAppResponses
->copyCollection();
8358 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
8359 collection
->release();
8361 pmStatsAppResponses
->flushCollection();
8363 IOLockUnlock(pmStatsLock
);
8367 if (!strcmp(aKey
, kIOPMIdleSleepPreventersKey
))
8369 OSArray
*idleSleepList
= NULL
;
8370 gRootDomain
->copySleepPreventersList(&idleSleepList
, NULL
);
8371 return idleSleepList
;
8374 if (!strcmp(aKey
, kIOPMSystemSleepPreventersKey
))
8376 OSArray
*systemSleepList
= NULL
;
8377 gRootDomain
->copySleepPreventersList(NULL
, &systemSleepList
);
8378 return systemSleepList
;
8385 // MARK: Wake Event Reporting
8387 void IOPMrootDomain::copyWakeReasonString( char * outBuf
, size_t bufSize
)
8390 strlcpy(outBuf
, gWakeReasonString
, bufSize
);
8394 //******************************************************************************
8395 // acceptSystemWakeEvents
8397 // Private control for the acceptance of driver wake event claims.
8398 //******************************************************************************
8400 void IOPMrootDomain::acceptSystemWakeEvents( bool accept
)
8402 bool logWakeReason
= false;
8407 gWakeReasonString
[0] = '\0';
8408 if (!_systemWakeEventsArray
)
8409 _systemWakeEventsArray
= OSArray::withCapacity(4);
8410 if ((_acceptSystemWakeEvents
= (_systemWakeEventsArray
!= 0)))
8411 _systemWakeEventsArray
->flushCollection();
8415 _acceptSystemWakeEvents
= false;
8420 MSG("system wake events:%s\n", gWakeReasonString
);
8423 //******************************************************************************
8424 // claimSystemWakeEvent
8426 // For a driver to claim a device is the source/conduit of a system wake event.
8427 //******************************************************************************
8429 void IOPMrootDomain::claimSystemWakeEvent(
8432 const char * reason
,
8433 OSObject
* details
)
8435 const OSSymbol
* deviceName
= 0;
8436 OSNumber
* deviceRegId
= 0;
8437 OSNumber
* claimTime
= 0;
8438 OSData
* flagsData
= 0;
8439 OSString
* reasonString
= 0;
8440 OSDictionary
* d
= 0;
8444 pmEventTimeStamp(×tamp
);
8446 if (!device
|| !reason
) return;
8448 deviceName
= device
->copyName(gIOServicePlane
);
8449 deviceRegId
= OSNumber::withNumber(device
->getRegistryEntryID(), 64);
8450 claimTime
= OSNumber::withNumber(timestamp
, 64);
8451 flagsData
= OSData::withBytes(&flags
, sizeof(flags
));
8452 reasonString
= OSString::withCString(reason
);
8453 d
= OSDictionary::withCapacity(5 + (details
? 1 : 0));
8454 if (!deviceName
|| !deviceRegId
|| !claimTime
|| !flagsData
|| !reasonString
)
8457 d
->setObject(gIONameKey
, deviceName
);
8458 d
->setObject(gIORegistryEntryIDKey
, deviceRegId
);
8459 d
->setObject(kIOPMWakeEventTimeKey
, claimTime
);
8460 d
->setObject(kIOPMWakeEventFlagsKey
, flagsData
);
8461 d
->setObject(kIOPMWakeEventReasonKey
, reasonString
);
8463 d
->setObject(kIOPMWakeEventDetailsKey
, details
);
8466 if (!gWakeReasonSysctlRegistered
)
8468 // Lazy registration until the platform driver stops registering
8470 gWakeReasonSysctlRegistered
= true;
8472 if (_acceptSystemWakeEvents
)
8474 ok
= _systemWakeEventsArray
->setObject(d
);
8475 if (gWakeReasonString
[0] != '\0')
8476 strlcat(gWakeReasonString
, " ", sizeof(gWakeReasonString
));
8477 strlcat(gWakeReasonString
, reason
, sizeof(gWakeReasonString
));
8482 if (deviceName
) deviceName
->release();
8483 if (deviceRegId
) deviceRegId
->release();
8484 if (claimTime
) claimTime
->release();
8485 if (flagsData
) flagsData
->release();
8486 if (reasonString
) reasonString
->release();
8487 if (d
) d
->release();
8490 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8493 // MARK: PMSettingHandle
8495 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
8497 void PMSettingHandle::free( void )
8501 pmso
->clientHandleFreed();
8510 // MARK: PMSettingObject
8513 #define super OSObject
8514 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
8517 * Static constructor/initializer for PMSettingObject
8519 PMSettingObject
*PMSettingObject::pmSettingObject(
8520 IOPMrootDomain
*parent_arg
,
8521 IOPMSettingControllerCallback handler_arg
,
8522 OSObject
*target_arg
,
8523 uintptr_t refcon_arg
,
8524 uint32_t supportedPowerSources
,
8525 const OSSymbol
* settings
[],
8526 OSObject
**handle_obj
)
8528 uint32_t settingCount
= 0;
8529 PMSettingObject
*pmso
= 0;
8530 PMSettingHandle
*pmsh
= 0;
8532 if ( !parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
)
8535 // count OSSymbol entries in NULL terminated settings array
8536 while (settings
[settingCount
]) {
8539 if (0 == settingCount
)
8542 pmso
= new PMSettingObject
;
8543 if (!pmso
|| !pmso
->init())
8546 pmsh
= new PMSettingHandle
;
8547 if (!pmsh
|| !pmsh
->init())
8550 queue_init(&pmso
->calloutQueue
);
8551 pmso
->parent
= parent_arg
;
8552 pmso
->func
= handler_arg
;
8553 pmso
->target
= target_arg
;
8554 pmso
->refcon
= refcon_arg
;
8555 pmso
->settingCount
= settingCount
;
8557 pmso
->retain(); // handle holds a retain on pmso
8561 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount
);
8562 if (pmso
->publishedFeatureID
) {
8563 for (unsigned int i
=0; i
<settingCount
; i
++) {
8564 // Since there is now at least one listener to this setting, publish
8565 // PM root domain support for it.
8566 parent_arg
->publishPMSetting( settings
[i
],
8567 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
8575 if (pmso
) pmso
->release();
8576 if (pmsh
) pmsh
->release();
8580 void PMSettingObject::free( void )
8582 if (publishedFeatureID
) {
8583 for (uint32_t i
=0; i
<settingCount
; i
++) {
8584 if (publishedFeatureID
[i
]) {
8585 parent
->removePublishedFeature( publishedFeatureID
[i
] );
8589 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
8595 void PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
8597 (*func
)(target
, type
, object
, refcon
);
8600 void PMSettingObject::clientHandleFreed( void )
8602 parent
->deregisterPMSettingObject(this);
8606 // MARK: PMAssertionsTracker
8608 //*********************************************************************************
8609 //*********************************************************************************
8610 //*********************************************************************************
8611 // class PMAssertionsTracker Implementation
8613 #define kAssertUniqueIDStart 500
8615 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
8617 PMAssertionsTracker
*myself
;
8619 myself
= new PMAssertionsTracker
;
8623 myself
->owner
= rootDomain
;
8624 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
8625 myself
->assertionsArray
= OSArray::withCapacity(5);
8626 myself
->assertionsKernel
= 0;
8627 myself
->assertionsUser
= 0;
8628 myself
->assertionsCombined
= 0;
8629 myself
->assertionsArrayLock
= IOLockAlloc();
8630 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
8632 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
8640 * - Update assertionsKernel to reflect the state of all
8641 * assertions in the kernel.
8642 * - Update assertionsCombined to reflect both kernel & user space.
8644 void PMAssertionsTracker::tabulate(void)
8648 PMAssertStruct
*_a
= NULL
;
8651 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
8652 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
8656 assertionsKernel
= 0;
8657 assertionsCombined
= 0;
8659 if (!assertionsArray
)
8662 if ((count
= assertionsArray
->getCount()))
8664 for (i
=0; i
<count
; i
++)
8666 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8669 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
8670 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
8671 assertionsKernel
|= _a
->assertionBits
;
8676 tabulateProducerCount
++;
8677 assertionsCombined
= assertionsKernel
| assertionsUser
;
8679 if ((assertionsKernel
!= oldKernel
) ||
8680 (assertionsCombined
!= oldCombined
))
8682 owner
->evaluateAssertions(assertionsCombined
, oldCombined
);
8686 void PMAssertionsTracker::publishProperties( void )
8688 OSArray
*assertionsSummary
= NULL
;
8690 if (tabulateConsumerCount
!= tabulateProducerCount
)
8692 IOLockLock(assertionsArrayLock
);
8694 tabulateConsumerCount
= tabulateProducerCount
;
8696 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
8698 assertionsSummary
= copyAssertionsArray();
8699 if (assertionsSummary
)
8701 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
8702 assertionsSummary
->release();
8706 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
8709 /* Publish the IOPMrootDomain property "DriverPMAssertions"
8711 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
8713 IOLockUnlock(assertionsArrayLock
);
8717 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
8719 PMAssertStruct
*_a
= NULL
;
8726 && (count
= assertionsArray
->getCount()))
8728 for (i
=0; i
<count
; i
++)
8730 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8733 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
8734 if (_a
&& (_id
== _a
->id
)) {
8751 /* PMAssertionsTracker::handleCreateAssertion
8752 * Perform assertion work on the PM workloop. Do not call directly.
8754 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
8760 IOLockLock(assertionsArrayLock
);
8761 assertionsArray
->setObject(newAssertion
);
8762 IOLockUnlock(assertionsArrayLock
);
8763 newAssertion
->release();
8767 return kIOReturnSuccess
;
8770 /* PMAssertionsTracker::createAssertion
8771 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
8774 IOReturn
PMAssertionsTracker::createAssertion(
8775 IOPMDriverAssertionType which
,
8776 IOPMDriverAssertionLevel level
,
8777 IOService
*serviceID
,
8778 const char *whoItIs
,
8779 IOPMDriverAssertionID
*outID
)
8781 OSData
*dataStore
= NULL
;
8782 PMAssertStruct track
;
8784 // Warning: trillions and trillions of created assertions may overflow the unique ID.
8785 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
8786 track
.level
= level
;
8787 track
.assertionBits
= which
;
8788 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
):0;
8789 track
.ownerService
= serviceID
;
8790 track
.registryEntryID
= serviceID
? serviceID
->getRegistryEntryID():0;
8791 track
.modifiedTime
= 0;
8792 pmEventTimeStamp(&track
.createdTime
);
8794 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
8797 if (track
.ownerString
)
8798 track
.ownerString
->release();
8799 return kIOReturnNoMemory
;
8804 if (owner
&& owner
->pmPowerStateQueue
) {
8805 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
8808 return kIOReturnSuccess
;
8811 /* PMAssertionsTracker::handleReleaseAssertion
8812 * Runs in PM workloop. Do not call directly.
8814 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
8815 IOPMDriverAssertionID _id
)
8820 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
8823 return kIOReturnNotFound
;
8825 IOLockLock(assertionsArrayLock
);
8826 if (assertStruct
->ownerString
)
8827 assertStruct
->ownerString
->release();
8829 assertionsArray
->removeObject(index
);
8830 IOLockUnlock(assertionsArrayLock
);
8833 return kIOReturnSuccess
;
8836 /* PMAssertionsTracker::releaseAssertion
8837 * Releases an assertion and affects system behavior if appropiate.
8838 * Actual work happens on PM workloop.
8840 IOReturn
PMAssertionsTracker::releaseAssertion(
8841 IOPMDriverAssertionID _id
)
8843 if (owner
&& owner
->pmPowerStateQueue
) {
8844 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
8846 return kIOReturnSuccess
;
8849 /* PMAssertionsTracker::handleSetAssertionLevel
8850 * Runs in PM workloop. Do not call directly.
8852 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
8853 IOPMDriverAssertionID _id
,
8854 IOPMDriverAssertionLevel _level
)
8856 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
8860 if (!assertStruct
) {
8861 return kIOReturnNotFound
;
8864 IOLockLock(assertionsArrayLock
);
8865 pmEventTimeStamp(&assertStruct
->modifiedTime
);
8866 assertStruct
->level
= _level
;
8867 IOLockUnlock(assertionsArrayLock
);
8870 return kIOReturnSuccess
;
8873 /* PMAssertionsTracker::setAssertionLevel
8875 IOReturn
PMAssertionsTracker::setAssertionLevel(
8876 IOPMDriverAssertionID _id
,
8877 IOPMDriverAssertionLevel _level
)
8879 if (owner
&& owner
->pmPowerStateQueue
) {
8880 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
8881 (void *)(uintptr_t)_level
, _id
);
8884 return kIOReturnSuccess
;
8887 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
8889 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
8893 if (new_user_levels
!= assertionsUser
)
8895 assertionsUser
= new_user_levels
;
8896 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
8900 return kIOReturnSuccess
;
8903 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
8904 IOPMDriverAssertionType new_user_levels
)
8906 if (gIOPMWorkLoop
) {
8907 gIOPMWorkLoop
->runAction(
8908 OSMemberFunctionCast(
8911 &PMAssertionsTracker::handleSetUserAssertionLevels
),
8913 (void *) &new_user_levels
, 0, 0, 0);
8916 return kIOReturnSuccess
;
8920 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
8924 OSArray
*outArray
= NULL
;
8926 if (!assertionsArray
||
8927 (0 == (count
= assertionsArray
->getCount())) ||
8928 (NULL
== (outArray
= OSArray::withCapacity(count
))))
8933 for (i
=0; i
<count
; i
++)
8935 PMAssertStruct
*_a
= NULL
;
8937 OSDictionary
*details
= NULL
;
8939 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8940 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
8942 OSNumber
*_n
= NULL
;
8944 details
= OSDictionary::withCapacity(7);
8948 outArray
->setObject(details
);
8951 _n
= OSNumber::withNumber(_a
->id
, 64);
8953 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
8956 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
8958 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
8961 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
8963 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
8966 _n
= OSNumber::withNumber((uintptr_t)_a
->registryEntryID
, 64);
8968 details
->setObject(kIOPMDriverAssertionRegistryEntryIDKey
, _n
);
8971 _n
= OSNumber::withNumber(_a
->level
, 64);
8973 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
8976 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
8978 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
8982 if (_a
->ownerString
) {
8983 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
8992 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
8994 return assertionsCombined
;
8997 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
8998 IOPMDriverAssertionType type
)
9000 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
9002 return kIOPMDriverAssertionLevelOn
;
9004 return kIOPMDriverAssertionLevelOff
;
9008 //*********************************************************************************
9009 //*********************************************************************************
9010 //*********************************************************************************
9013 static void pmEventTimeStamp(uint64_t *recordTS
)
9021 // We assume tsec fits into 32 bits; 32 bits holds enough
9022 // seconds for 136 years since the epoch in 1970.
9023 clock_get_calendar_microtime(&tsec
, &tusec
);
9026 // Pack the sec & microsec calendar time into a uint64_t, for fun.
9028 *recordTS
|= (uint32_t)tusec
;
9029 *recordTS
|= ((uint64_t)tsec
<< 32);
9035 // MARK: IORootParent
9037 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9039 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
9041 // The reason that root domain needs a root parent is to facilitate demand
9042 // sleep, since a power change from the root parent cannot be vetoed.
9044 // The above statement is no longer true since root domain now performs
9045 // demand sleep using overrides. But root parent remains to avoid changing
9046 // the power tree stacking. Root parent is parked at the max power state.
9049 static IOPMPowerState patriarchPowerStates
[2] =
9051 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9052 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9055 void IORootParent::initialize( void )
9059 bool IORootParent::start( IOService
* nub
)
9061 IOService::start(nub
);
9062 attachToParent( getRegistryRoot(), gIOPowerPlane
);
9064 registerPowerDriver(this, patriarchPowerStates
, 2);
9069 void IORootParent::shutDownSystem( void )
9073 void IORootParent::restartSystem( void )
9077 void IORootParent::sleepSystem( void )
9081 void IORootParent::dozeSystem( void )
9085 void IORootParent::sleepToDoze( void )
9089 void IORootParent::wakeSystem( void )
9093 OSObject
* IORootParent::copyProperty( const char * aKey
) const
9095 return (IOService::copyProperty(aKey
));
9099 #if defined(__i386__) || defined(__x86_64__)
9100 IOReturn
IOPMrootDomain::restartWithStackshot()
9102 if ((swd_flags
& SWD_WDOG_ENABLED
) == 0)
9103 return kIOReturnError
;
9105 takeStackshot(true, true, false);
9107 return kIOReturnSuccess
;
9110 void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger
)
9112 takeStackshot(wdogTrigger
, false, false);
9115 void IOPMrootDomain::takeStackshot(bool wdogTrigger
, bool isOSXWatchdog
, bool isSpinDump
)
9117 swd_hdr
* hdr
= NULL
;
9119 uint32_t wdog_panic
= 0;
9126 uint32_t bytesRemaining
;
9128 OSString
* UUIDstring
= NULL
;
9130 IOMemoryMap
* logBufMap
= NULL
;
9132 swd_stackshot_hdr
*stackshotHdr
= NULL
;
9135 uint32_t initialStackSize
;
9138 if (_systemTransitionType
!= kSystemTransitionSleep
&&
9139 _systemTransitionType
!= kSystemTransitionWake
)
9142 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
9147 if (PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
)) &&
9148 (wdog_panic
== 1)) {
9149 // If boot-arg is set to panic on sleep/wake hang, call panic
9150 panic("Sleep/Wake hang detected\n");
9153 else if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
9154 // If current boot is due to this watch dog trigger restart in previous boot,
9155 // then don't trigger again until at least 1 successful sleep & wake.
9156 if (!(sleepCnt
&& (displayWakeCnt
|| darkWakeCnt
))) {
9157 IOLog("Shutting down due to repeated Sleep/Wake failures\n");
9158 PEHaltRestart(kPEHaltCPU
);
9166 if (gSpinDumpBufferFull
)
9168 if (swd_spindump_buffer
== NULL
) {
9169 sleepWakeDebugSpinDumpMemAlloc();
9170 if (swd_spindump_buffer
== NULL
) return;
9173 bufSize
= SWD_SPINDUMP_SIZE
;
9174 initialStackSize
= SWD_INITIAL_SPINDUMP_SIZE
;
9176 if (sleepWakeDebugIsWdogEnabled() == false)
9179 if (swd_buffer
== NULL
) {
9180 sleepWakeDebugMemAlloc();
9181 if (swd_buffer
== NULL
) return;
9184 bufSize
= SWD_BUF_SIZE
;
9185 initialStackSize
= SWD_INITIAL_STACK_SIZE
;
9188 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9192 hdr
= (swd_hdr
*)swd_spindump_buffer
;
9194 hdr
= (swd_hdr
*)swd_buffer
;
9195 memset(hdr
->UUID
, 0x20, sizeof(hdr
->UUID
));
9196 if ((UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))) != NULL
) {
9198 if (wdogTrigger
|| (!UUIDstring
->isEqualTo(hdr
->UUID
))) {
9199 const char *str
= UUIDstring
->getCStringNoCopy();
9200 snprintf(hdr
->UUID
, sizeof(hdr
->UUID
), "UUID: %s", str
);
9203 DLOG("Data for current UUID already exists\n");
9208 dstAddr
= (char*)hdr
+ hdr
->spindump_offset
;
9209 bytesRemaining
= bufSize
- hdr
->spindump_offset
;
9211 /* if AppleOSXWatchdog triggered the stackshot, set the flag in the heaer */
9212 hdr
->is_osx_watchdog
= isOSXWatchdog
;
9214 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining
);
9216 while (bytesRemaining
> sizeof(swd_stackshot_hdr
)) {
9218 stackshotHdr
= (swd_stackshot_hdr
*)dstAddr
;
9219 stackshotHdr
->magic
= SWD_STACKSHOTHDR_MAGIC
;
9220 stackshotHdr
->size
= 0;
9221 bytesRemaining
-= sizeof(swd_stackshot_hdr
);
9222 dstAddr
+= sizeof(swd_stackshot_hdr
);
9224 if (isOSXWatchdog
) {
9226 size
= bytesRemaining
;
9227 flags
= STACKSHOT_SAVE_LOADINFO
| STACKSHOT_SAVE_KEXT_LOADINFO
;
9229 else if (cnt
== 0) {
9231 * Take stackshot of all process on first sample. Size is restricted
9232 * to SWD_INITIAL_STACK_SIZE
9235 size
= (bytesRemaining
> initialStackSize
) ? initialStackSize
: bytesRemaining
;
9236 flags
= STACKSHOT_SAVE_LOADINFO
| STACKSHOT_SAVE_KEXT_LOADINFO
|STACKSHOT_SAVE_KERNEL_FRAMES_ONLY
;
9239 /* Take sample of kernel threads only */
9241 size
= bytesRemaining
;
9245 stack_snapshot_from_kernel(pid
, dstAddr
, size
, flags
, &stackshotHdr
->size
);
9247 dstAddr
+= stackshotHdr
->size
;
9248 bytesRemaining
-= stackshotHdr
->size
;
9250 DLOG("Sample: %d size: %d bytesRemaining: %d\n", cnt
, stackshotHdr
->size
, bytesRemaining
);
9251 if ((stackshotHdr
->size
== 0) || (++cnt
== 10))
9253 IOSleep(10); // 10 ms
9256 hdr
->spindump_size
= (bufSize
- bytesRemaining
- hdr
->spindump_offset
);
9259 memset(hdr
->cps
, 0x20, sizeof(hdr
->cps
));
9260 snprintf(hdr
->cps
, sizeof(hdr
->cps
), "\ncps: %d", ((IOService
*)this)->getPowerState());
9261 code
= pmTracer
->getPMStatusCode();
9262 memset(hdr
->PMStatusCode
, 0x20, sizeof(hdr
->PMStatusCode
));
9263 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: %08x %08x",
9264 (uint32_t)((code
>> 32) & 0xffffffff), (uint32_t)(code
& 0xffffffff));
9265 memset(hdr
->reason
, 0x20, sizeof(hdr
->reason
));
9267 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: PSC Delay\n\n");
9268 gRootDomain
->swd_lock
= 0;
9269 gSpinDumpBufferFull
= true;
9272 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
9275 data
[0] = round_page(sizeof(swd_hdr
) + hdr
->spindump_size
);
9276 /* Header & rootdomain log is constantly changing and is not covered by CRC */
9277 data
[1] = hdr
->crc
= crc32(0, ((char*)swd_buffer
+hdr
->spindump_offset
), hdr
->spindump_size
);
9278 data
[2] = kvtophys((vm_offset_t
)swd_buffer
);
9279 len
= sizeof(addr64_t
)*3;
9280 DLOG("bytes: 0x%llx crc:0x%llx paddr:0x%llx\n",
9281 data
[0], data
[1], data
[2]);
9283 if (PEWriteNVRAMProperty(kIOSleepWakeDebugKey
, data
, len
) == false)
9285 DLOG("Failed to update nvram boot-args\n");
9291 gRootDomain
->swd_lock
= 0;
9294 IOLog("Restarting to collect Sleep wake debug logs\n");
9295 PEHaltRestart(kPERestartCPU
);
9298 logBufMap
= sleepWakeDebugRetrieve();
9300 sleepWakeDebugDumpFromMem(logBufMap
);
9301 logBufMap
->release();
9307 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9309 vm_size_t size
= SWD_BUF_SIZE
;
9311 swd_hdr
*hdr
= NULL
;
9313 IOBufferMemoryDescriptor
*memDesc
= NULL
;
9316 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
9319 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9322 // Try allocating above 4GB. If that fails, try at 2GB
9323 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9324 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
9325 size
, 0xFFFFFFFF00000000ULL
);
9327 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9328 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
9329 size
, 0xFFFFFFFF10000000ULL
);
9332 if (memDesc
== NULL
)
9334 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
9339 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
9340 memset(hdr
, 0, sizeof(swd_hdr
));
9342 hdr
->signature
= SWD_HDR_SIGNATURE
;
9343 hdr
->alloc_size
= size
;
9345 hdr
->spindump_offset
= sizeof(swd_hdr
);
9346 swd_buffer
= (void *)hdr
;
9347 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr
->alloc_size
, hdr
->spindump_offset
);
9350 gRootDomain
->swd_lock
= 0;
9353 void IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc( )
9355 vm_size_t size
= SWD_SPINDUMP_SIZE
;
9357 swd_hdr
*hdr
= NULL
;
9359 IOBufferMemoryDescriptor
*memDesc
= NULL
;
9361 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9364 memDesc
= IOBufferMemoryDescriptor::inTaskWithOptions(
9365 kernel_task
, kIODirectionIn
|kIOMemoryMapperNone
,
9368 if (memDesc
== NULL
)
9370 DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
9375 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
9376 memset(hdr
, 0, sizeof(swd_hdr
));
9378 hdr
->signature
= SWD_HDR_SIGNATURE
;
9379 hdr
->alloc_size
= size
;
9381 hdr
->spindump_offset
= sizeof(swd_hdr
);
9382 swd_spindump_buffer
= (void *)hdr
;
9385 gRootDomain
->swd_lock
= 0;
9388 void IOPMrootDomain::sleepWakeDebugEnableWdog()
9390 swd_flags
|= SWD_WDOG_ENABLED
;
9392 sleepWakeDebugMemAlloc();
9395 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
9397 return ((swd_flags
& SWD_WDOG_ENABLED
) &&
9398 !systemBooting
&& !systemShutdown
&& !gWillShutdown
);
9401 void IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
9403 swd_hdr
*hdr
= NULL
;
9404 errno_t error
= EIO
;
9406 if (swd_spindump_buffer
&& gSpinDumpBufferFull
) {
9407 hdr
= (swd_hdr
*)swd_spindump_buffer
;
9409 error
= sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
9410 (char*)hdr
+hdr
->spindump_offset
, hdr
->spindump_size
);
9414 sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
9415 (char*)hdr
+offsetof(swd_hdr
, UUID
),
9416 sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
));
9418 gSpinDumpBufferFull
= false;
9422 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)
9424 struct vnode
*vp
= NULL
;
9425 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
9426 kauth_cred_t cred
= vfs_context_ucred(ctx
);
9427 struct vnode_attr va
;
9428 errno_t error
= EIO
;
9430 if (vnode_open(name
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
9431 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
9433 IOLog("Failed to open the file %s\n", name
);
9437 VATTR_WANTED(&va
, va_nlink
);
9438 /* Don't dump to non-regular files or files with links. */
9439 if (vp
->v_type
!= VREG
||
9440 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
9441 IOLog("Bailing as this is not a regular file\n");
9445 VATTR_SET(&va
, va_data_size
, 0);
9446 vnode_setattr(vp
, &va
, ctx
);
9449 error
= vn_rdwr(UIO_WRITE
, vp
, buf
, len
, 0,
9450 UIO_SYSSPACE
, IO_NODELOCKED
|IO_UNIT
, cred
, (int *) 0, vfs_context_proc(ctx
));
9452 IOLog("Failed to save sleep wake log. err 0x%x\n", error
);
9454 DLOG("Saved %d bytes to file %s\n",len
, name
);
9457 if (vp
) vnode_close(vp
, FWRITE
, ctx
);
9458 if (ctx
) vfs_context_rele(ctx
);
9464 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
9465 struct vnode
*srcVp
,
9466 vfs_context_t srcCtx
,
9467 char *tmpBuf
, uint64_t tmpBufSize
,
9469 const char *dstFname
,
9473 struct vnode
*vp
= NULL
;
9474 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
9475 struct vnode_attr va
;
9476 errno_t error
= EIO
;
9477 uint64_t bytesToRead
, bytesToWrite
;
9478 uint64_t readFileOffset
, writeFileOffset
, srcDataOffset
;
9479 uint32_t newcrc
= 0;
9481 if (vnode_open(dstFname
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
9482 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
9484 DLOG("Failed to open the file %s\n", dstFname
);
9488 VATTR_WANTED(&va
, va_nlink
);
9489 /* Don't dump to non-regular files or files with links. */
9490 if (vp
->v_type
!= VREG
||
9491 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
9492 DLOG("Bailing as this is not a regular file\n");
9496 VATTR_SET(&va
, va_data_size
, 0);
9497 vnode_setattr(vp
, &va
, ctx
);
9499 writeFileOffset
= 0;
9501 bytesToRead
= (round_page(numBytes
) > tmpBufSize
) ? tmpBufSize
: round_page(numBytes
);
9502 readFileOffset
= trunc_page(srcOffset
);
9504 DLOG("Read file (numBytes:0x%llx offset:0x%llx)\n", bytesToRead
, readFileOffset
);
9505 error
= vn_rdwr(UIO_READ
, srcVp
, tmpBuf
, bytesToRead
, readFileOffset
,
9506 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
9507 vfs_context_ucred(srcCtx
), (int *) 0,
9508 vfs_context_proc(srcCtx
));
9510 DLOG("Failed to read file(numBytes:0x%llx)\n", bytesToRead
);
9514 srcDataOffset
= (uint64_t)tmpBuf
+ (srcOffset
- readFileOffset
);
9515 bytesToWrite
= bytesToRead
- (srcOffset
- readFileOffset
);
9516 if (bytesToWrite
> numBytes
) bytesToWrite
= numBytes
;
9519 newcrc
= crc32(newcrc
, (void *)srcDataOffset
, bytesToWrite
);
9521 DLOG("Write file (numBytes:0x%llx offset:0x%llx)\n", bytesToWrite
, writeFileOffset
);
9522 error
= vn_rdwr(UIO_WRITE
, vp
, (char *)srcDataOffset
, bytesToWrite
, writeFileOffset
,
9523 UIO_SYSSPACE
, IO_SYNC
|IO_NODELOCKED
|IO_UNIT
,
9524 vfs_context_ucred(ctx
), (int *) 0,
9525 vfs_context_proc(ctx
));
9527 DLOG("Failed to write file(numBytes:0x%llx)\n", bytesToWrite
);
9531 writeFileOffset
+= bytesToWrite
;
9532 numBytes
-= bytesToWrite
;
9533 srcOffset
+= bytesToWrite
;
9536 if (crc
!= newcrc
) {
9537 swd_stackshot_hdr
*shdr
= (swd_stackshot_hdr
*)tmpBuf
;;
9539 /* Set statckshot size to 0 if crc doesn't match */
9540 shdr
->magic
= SWD_STACKSHOTHDR_MAGIC
;
9543 assert(tmpBufSize
> sizeof(swd_stackshot_hdr
));
9544 bytesToWrite
= round_page(sizeof(swd_stackshot_hdr
));
9545 vn_rdwr(UIO_WRITE
, vp
, (char *)tmpBuf
, bytesToWrite
, 0,
9546 UIO_SYSSPACE
, IO_SYNC
|IO_NODELOCKED
|IO_UNIT
,
9547 vfs_context_ucred(ctx
), (int *) 0,
9548 vfs_context_proc(ctx
));
9550 DLOG("CRC check failed. expected:0x%x actual:0x%x\n", crc
, newcrc
);
9555 error
= vnode_close(vp
, FWRITE
, ctx
);
9556 DLOG("vnode_close returned 0x%x\n", error
);
9558 if (ctx
) vfs_context_rele(ctx
);
9565 void IOPMrootDomain::checkForValidDebugData(const char *fname
, vfs_context_t
*ctx
,
9566 void *tmpBuf
, struct vnode
**vp
)
9571 struct vnode_attr va
;
9572 IOHibernateImageHeader
*imageHdr
;
9575 if (vnode_open(fname
, (FREAD
| O_NOFOLLOW
), 0,
9576 VNODE_LOOKUP_NOFOLLOW
, vp
, *ctx
) != 0)
9578 DMSG("sleepWakeDebugDumpFromFile: Failed to open the file %s\n", fname
);
9582 VATTR_WANTED(&va
, va_nlink
);
9583 VATTR_WANTED(&va
, va_data_alloc
);
9584 if ((*vp
)->v_type
!= VREG
||
9585 vnode_getattr((*vp
), &va
, *ctx
) || va
.va_nlink
!= 1) {
9586 DMSG("sleepWakeDebugDumpFromFile: Bailing as %s is not a regular file\n", fname
);
9590 /* Read the sleepimage file header */
9591 rc
= vn_rdwr(UIO_READ
, *vp
, (char *)tmpBuf
, round_page(sizeof(IOHibernateImageHeader
)), 0,
9592 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
9593 vfs_context_ucred(*ctx
), (int *) 0,
9594 vfs_context_proc(*ctx
));
9596 DMSG("sleepWakeDebugDumpFromFile: Failed to read header size %lu(rc=%d) from %s\n",
9597 round_page(sizeof(IOHibernateImageHeader
)), rc
, fname
);
9601 imageHdr
= ((IOHibernateImageHeader
*)tmpBuf
);
9602 if (imageHdr
->signature
!= kIOHibernateHeaderDebugDataSignature
) {
9603 DMSG("sleepWakeDebugDumpFromFile: File %s header has unexpected value 0x%x\n",
9604 fname
, imageHdr
->signature
);
9608 /* Sleep/Wake debug header(swd_hdr) is at the beggining of the second block */
9609 hdrOffset
= imageHdr
->deviceBlockSize
;
9610 if (hdrOffset
+ sizeof(swd_hdr
) >= va
.va_data_alloc
) {
9611 DMSG("sleepWakeDebugDumpFromFile: header is crossing file size(0x%llx) in file %s\n",
9612 va
.va_data_alloc
, fname
);
9619 if (*vp
) vnode_close(*vp
, FREAD
, *ctx
);
9625 void IOPMrootDomain::sleepWakeDebugDumpFromFile( )
9629 char hibernateFilename
[MAXPATHLEN
+1];
9630 char PMStatusCode
[100];
9632 swd_hdr
*hdr
= NULL
;
9633 uint32_t stacksSize
, logSize
;
9634 uint64_t tmpBufSize
;
9635 uint64_t hdrOffset
, stacksOffset
, logOffset
;
9636 errno_t error
= EIO
;
9637 OSObject
*obj
= NULL
;
9638 OSString
*str
= NULL
;
9639 OSNumber
*failStat
= NULL
;
9640 struct vnode
*vp
= NULL
;
9641 vfs_context_t ctx
= NULL
;
9643 IOBufferMemoryDescriptor
*tmpBufDesc
= NULL
;
9645 DLOG("sleepWakeDebugDumpFromFile\n");
9646 if ((swd_flags
& SWD_LOGS_IN_FILE
) == 0)
9649 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9653 /* Allocate a temp buffer to copy data between files */
9654 tmpBufSize
= 2*4096;
9655 tmpBufDesc
= IOBufferMemoryDescriptor::
9656 inTaskWithOptions(kernel_task
, kIODirectionOutIn
| kIOMemoryMapperNone
,
9657 tmpBufSize
, PAGE_SIZE
);
9660 DMSG("sleepWakeDebugDumpFromFile: Fail to allocate temp buf\n");
9664 tmpBuf
= tmpBufDesc
->getBytesNoCopy();
9666 ctx
= vfs_context_create(vfs_context_current());
9668 /* First check if 'kSleepWakeStackBinFilename' has valid data */
9669 checkForValidDebugData(kSleepWakeStackBinFilename
, &ctx
, tmpBuf
, &vp
);
9671 /* Check if the debug data is saved to hibernation file */
9672 hibernateFilename
[0] = 0;
9673 if ((obj
= copyProperty(kIOHibernateFileKey
)))
9675 if ((str
= OSDynamicCast(OSString
, obj
)))
9676 strlcpy(hibernateFilename
, str
->getCStringNoCopy(),
9677 sizeof(hibernateFilename
));
9680 if (!hibernateFilename
[0]) {
9681 DMSG("sleepWakeDebugDumpFromFile: Failed to get hibernation file name\n");
9685 checkForValidDebugData(hibernateFilename
, &ctx
, tmpBuf
, &vp
);
9687 DMSG("sleepWakeDebugDumpFromFile: No valid debug data is found\n");
9690 DLOG("Getting SW Stacks image from file %s\n", hibernateFilename
);
9693 DLOG("Getting SW Stacks image from file %s\n", kSleepWakeStackBinFilename
);
9696 hdrOffset
= ((IOHibernateImageHeader
*)tmpBuf
)->deviceBlockSize
;
9698 DLOG("Reading swd_hdr len 0x%lx offset 0x%lx\n", round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
));
9699 /* Read the sleep/wake debug header(swd_hdr) */
9700 rc
= vn_rdwr(UIO_READ
, vp
, (char *)tmpBuf
, round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
),
9701 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
9702 vfs_context_ucred(ctx
), (int *) 0,
9703 vfs_context_proc(ctx
));
9705 DMSG("sleepWakeDebugDumpFromFile: Failed to debug read header size %lu. rc=%d\n",
9706 round_page(sizeof(swd_hdr
)), rc
);
9710 hdr
= (swd_hdr
*)((char *)tmpBuf
+ (hdrOffset
- trunc_page(hdrOffset
)));
9711 if ((hdr
->signature
!= SWD_HDR_SIGNATURE
) || (hdr
->alloc_size
> SWD_BUF_SIZE
) ||
9712 (hdr
->spindump_offset
> SWD_BUF_SIZE
) || (hdr
->spindump_size
> SWD_BUF_SIZE
)) {
9713 DMSG("sleepWakeDebugDumpFromFile: Invalid data in debug header. sign:0x%x size:0x%x spindump_offset:0x%x spindump_size:0x%x\n",
9714 hdr
->signature
, hdr
->alloc_size
, hdr
->spindump_offset
, hdr
->spindump_size
);
9717 stacksSize
= hdr
->spindump_size
;
9719 /* Get stacks & log offsets in the image file */
9720 stacksOffset
= hdrOffset
+ hdr
->spindump_offset
;
9721 logOffset
= hdrOffset
+ offsetof(swd_hdr
, UUID
);
9722 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
9724 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, stacksOffset
,
9725 getDumpStackFilename(hdr
), stacksSize
, hdr
->crc
);
9726 if (error
== EFAULT
) {
9727 DMSG("sleepWakeDebugDumpFromFile: Stackshot CRC doesn't match\n");
9730 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, logOffset
,
9731 getDumpLogFilename(hdr
), logSize
, 0);
9733 DMSG("sleepWakeDebugDumpFromFile: Failed to write the log file(0x%x)\n", error
);
9738 // Write just the SleepWakeLog.dump with failure code
9741 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
9742 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
9743 fcode
= failStat
->unsigned64BitValue();
9744 fname
= kSleepWakeLogFilename
;
9747 fname
= kAppleOSXWatchdogLogFilename
;
9749 memset(PMStatusCode
, 0x20, sizeof(PMStatusCode
)); // Fill with spaces
9750 PMStatusCode
[sizeof(PMStatusCode
)-1] = 0xa; // And an end-of-line at the end
9751 snprintf(PMStatusCode
, sizeof(PMStatusCode
)-1, "Code: 0x%llx", fcode
);
9752 sleepWakeDebugSaveFile(fname
, PMStatusCode
, sizeof(PMStatusCode
));
9754 gRootDomain
->swd_lock
= 0;
9756 if (vp
) vnode_close(vp
, FREAD
, ctx
);
9757 if (ctx
) vfs_context_rele(ctx
);
9758 if (tmpBufDesc
) tmpBufDesc
->release();
9759 #endif /* HIBERNATION */
9762 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*logBufMap
)
9764 IOVirtualAddress srcBuf
= NULL
;
9765 char *stackBuf
= NULL
, *logOffset
= NULL
;
9768 errno_t error
= EIO
;
9769 uint64_t bufSize
= 0;
9770 swd_hdr
*hdr
= NULL
;
9771 char PMStatusCode
[100];
9772 OSNumber
*failStat
= NULL
;
9774 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9777 if ((logBufMap
== 0) || ( (srcBuf
= logBufMap
->getVirtualAddress()) == 0) )
9779 DLOG("Nothing saved to dump to file\n");
9783 hdr
= (swd_hdr
*)srcBuf
;
9784 bufSize
= logBufMap
->getLength();
9785 if (bufSize
<= sizeof(swd_hdr
))
9787 IOLog("SleepWake log buffer contents are invalid\n");
9791 stackBuf
= (char*)hdr
+hdr
->spindump_offset
;
9793 error
= sleepWakeDebugSaveFile(getDumpStackFilename(hdr
), stackBuf
, hdr
->spindump_size
);
9794 if (error
) goto exit
;
9796 logOffset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
9797 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
9799 error
= sleepWakeDebugSaveFile(getDumpLogFilename(hdr
), logOffset
, logSize
);
9800 if (error
) goto exit
;
9802 hdr
->spindump_size
= 0;
9807 // Write just the SleepWakeLog.dump with failure code
9809 const char *sname
, *lname
;
9810 swd_stackshot_hdr shdr
;
9812 /* Try writing an empty stacks file */
9813 shdr
.magic
= SWD_STACKSHOTHDR_MAGIC
;
9817 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
9818 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
9819 fcode
= failStat
->unsigned64BitValue();
9820 lname
= kSleepWakeLogFilename
;
9821 sname
= kSleepWakeStackFilename
;
9824 lname
= kAppleOSXWatchdogLogFilename
;
9825 sname
= kAppleOSXWatchdogStackFilename
;
9828 sleepWakeDebugSaveFile(sname
, (char*)(&shdr
), sizeof(shdr
));
9829 memset(PMStatusCode
, 0x20, sizeof(PMStatusCode
)); // Fill with spaces
9830 PMStatusCode
[sizeof(PMStatusCode
)-1] = 0xa; // And an end-of-line at the end
9831 snprintf(PMStatusCode
, sizeof(PMStatusCode
)-1, "Code: 0x%llx", fcode
);
9832 sleepWakeDebugSaveFile(lname
, PMStatusCode
, sizeof(PMStatusCode
));
9834 gRootDomain
->swd_lock
= 0;
9837 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
9839 IOVirtualAddress vaddr
= NULL
;
9840 IOMemoryDescriptor
* desc
= NULL
;
9841 IOMemoryMap
* logBufMap
= NULL
;
9845 uint64_t bufSize
= 0;
9847 uint64_t newcrc
= 0;
9849 swd_hdr
*hdr
= NULL
;
9854 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9857 if (!PEReadNVRAMProperty(kIOSleepWakeDebugKey
, 0, &len
)) {
9858 DLOG("No sleepWakeDebug note to read\n");
9862 if (len
== strlen("sleepimage")) {
9864 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, str
, &len
);
9866 if (!strncmp((char*)str
, "sleepimage", strlen("sleepimage"))) {
9867 DLOG("sleepWakeDebugRetrieve: in file logs\n");
9868 swd_flags
|= SWD_LOGS_IN_FILE
|SWD_VALID_LOGS
;
9872 else if (len
== sizeof(addr64_t
)*3)
9873 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, data
, &len
);
9875 DLOG("Invalid sleepWakeDebug note length(%d)\n", len
);
9881 DLOG("sleepWakeDebugRetrieve: data[0]:0x%llx data[1]:0x%llx data[2]:0x%llx\n",
9882 data
[0], data
[1], data
[2]);
9883 DLOG("sleepWakeDebugRetrieve: in mem logs\n");
9887 if ( (bufSize
<= sizeof(swd_hdr
)) ||(bufSize
> SWD_BUF_SIZE
) || (crc
== 0) )
9889 IOLog("SleepWake log buffer contents are invalid\n");
9893 DLOG("size:0x%llx crc:0x%llx paddr:0x%llx\n",
9894 bufSize
, crc
, paddr
);
9897 desc
= IOMemoryDescriptor::withAddressRange( paddr
, bufSize
,
9898 kIODirectionOutIn
| kIOMemoryMapperNone
, NULL
);
9901 IOLog("Fail to map SleepWake log buffer\n");
9905 logBufMap
= desc
->map();
9907 vaddr
= logBufMap
->getVirtualAddress();
9910 if ( (logBufMap
->getLength() <= sizeof(swd_hdr
)) || (vaddr
== NULL
) ) {
9911 IOLog("Fail to map SleepWake log buffer\n");
9915 hdr
= (swd_hdr
*)vaddr
;
9916 if (hdr
->spindump_offset
+hdr
->spindump_size
> bufSize
)
9918 IOLog("SleepWake log buffer contents are invalid\n");
9923 newcrc
= crc32(0, (void *)((char*)vaddr
+hdr
->spindump_offset
),
9924 hdr
->spindump_size
);
9925 if (newcrc
!= crc
) {
9926 IOLog("SleepWake log buffer contents are invalid\n");
9931 swd_flags
|= SWD_LOGS_IN_MEM
| SWD_VALID_LOGS
;
9935 PERemoveNVRAMProperty(kIOSleepWakeDebugKey
);
9937 if (logBufMap
) logBufMap
->release();
9940 if (desc
) desc
->release();
9941 gRootDomain
->swd_lock
= 0;
9948 void IOPMrootDomain::sleepWakeDebugTrig(bool restart
)
9952 void IOPMrootDomain::takeStackshot(bool restart
, bool isOSXWatchdog
, bool isSpinDump
)
9954 #pragma unused(restart)
9955 #pragma unused(isOSXWatchdog)
9958 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9961 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*map
)
9964 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
9965 struct vnode
*srcVp
,
9966 vfs_context_t srcCtx
,
9967 char *tmpBuf
, uint64_t tmpBufSize
,
9969 const char *dstFname
,
9976 void IOPMrootDomain::sleepWakeDebugDumpFromFile()
9980 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
9985 void IOPMrootDomain::sleepWakeDebugEnableWdog()
9989 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
9994 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)