2 * Copyright (c) 1998-2020 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@
29 #define IOKIT_ENABLE_SHARED_PTR
31 #include <libkern/c++/OSKext.h>
32 #include <libkern/c++/OSMetaClass.h>
33 #include <libkern/OSAtomic.h>
34 #include <libkern/OSDebug.h>
35 #include <IOKit/IOWorkLoop.h>
36 #include <IOKit/IOCommandGate.h>
37 #include <IOKit/IOTimerEventSource.h>
38 #include <IOKit/IOPlatformExpert.h>
39 #include <IOKit/IOCPU.h>
40 #include <IOKit/IOPlatformActions.h>
41 #include <IOKit/IOKitDebug.h>
42 #include <IOKit/IOTimeStamp.h>
43 #include <IOKit/pwr_mgt/IOPMlog.h>
44 #include <IOKit/pwr_mgt/RootDomain.h>
45 #include <IOKit/pwr_mgt/IOPMPrivate.h>
46 #include <IOKit/IODeviceTreeSupport.h>
47 #include <IOKit/IOMessage.h>
48 #include <IOKit/IOReturn.h>
49 #include <IOKit/IONVRAM.h>
50 #include "RootDomainUserClient.h"
51 #include "IOKit/pwr_mgt/IOPowerConnection.h"
52 #include "IOPMPowerStateQueue.h"
53 #include <IOKit/IOCatalogue.h>
54 #include <IOKit/IOReportMacros.h>
55 #include <IOKit/IOLib.h>
56 #include <IOKit/IOKitKeys.h>
57 #include "IOKitKernelInternal.h"
59 #include <IOKit/IOHibernatePrivate.h>
60 #endif /* HIBERNATION */
61 #include <console/video_console.h>
62 #include <sys/syslog.h>
63 #include <sys/sysctl.h>
64 #include <sys/vnode.h>
65 #include <sys/vnode_internal.h>
66 #include <sys/fcntl.h>
68 #include <pexpert/protos.h>
69 #include <AssertMacros.h>
72 #include "IOServicePrivate.h" // _IOServiceInterestNotifier
73 #include "IOServicePMPrivate.h"
75 #include <libkern/zlib.h>
76 #include <os/cpp_util.h>
77 #include <libkern/c++/OSBoundedArrayRef.h>
80 #include <mach/shared_region.h>
81 #include <kern/clock.h>
84 #if defined(__i386__) || defined(__x86_64__)
86 #include "IOPMrootDomainInternal.h"
87 const char *processor_to_datastring(const char *prefix
, processor_t target_processor
);
91 #define kIOPMrootDomainClass "IOPMrootDomain"
92 #define LOG_PREFIX "PMRD: "
96 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
99 do { kprintf(LOG_PREFIX x); } while (false)
101 #if DEVELOPMENT || DEBUG
102 #define DEBUG_LOG(x...) do { \
103 if (kIOLogPMRootDomain & gIOKitDebug) \
104 kprintf(LOG_PREFIX x); \
105 os_log_debug(OS_LOG_DEFAULT, LOG_PREFIX x); \
108 #define DEBUG_LOG(x...)
111 #define DLOG(x...) do { \
112 if (kIOLogPMRootDomain & gIOKitDebug) \
113 kprintf(LOG_PREFIX x); \
115 os_log(OS_LOG_DEFAULT, LOG_PREFIX x); \
118 #define DMSG(x...) do { \
119 if (kIOLogPMRootDomain & gIOKitDebug) { \
120 kprintf(LOG_PREFIX x); \
127 #define CHECK_THREAD_CONTEXT
128 #ifdef CHECK_THREAD_CONTEXT
129 static IOWorkLoop
* gIOPMWorkLoop
= NULL
;
130 #define ASSERT_GATED() \
132 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
133 panic("RootDomain: not inside PM gate"); \
137 #define ASSERT_GATED()
138 #endif /* CHECK_THREAD_CONTEXT */
140 #define CAP_LOSS(c) \
141 (((_pendingCapability & (c)) == 0) && \
142 ((_currentCapability & (c)) != 0))
144 #define CAP_GAIN(c) \
145 (((_currentCapability & (c)) == 0) && \
146 ((_pendingCapability & (c)) != 0))
148 #define CAP_CHANGE(c) \
149 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
151 #define CAP_CURRENT(c) \
152 ((_currentCapability & (c)) != 0)
154 #define CAP_HIGHEST(c) \
155 ((_highestCapability & (c)) != 0)
157 #define CAP_PENDING(c) \
158 ((_pendingCapability & (c)) != 0)
160 // rdar://problem/9157444
161 #if defined(__i386__) || defined(__x86_64__)
162 #define DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY 20
165 // Event types for IOPMPowerStateQueue::submitPowerEvent()
167 kPowerEventFeatureChanged
= 1, // 1
168 kPowerEventReceivedPowerNotification
, // 2
169 kPowerEventSystemBootCompleted
, // 3
170 kPowerEventSystemShutdown
, // 4
171 kPowerEventUserDisabledSleep
, // 5
172 kPowerEventRegisterSystemCapabilityClient
, // 6
173 kPowerEventRegisterKernelCapabilityClient
, // 7
174 kPowerEventPolicyStimulus
, // 8
175 kPowerEventAssertionCreate
, // 9
176 kPowerEventAssertionRelease
, // 10
177 kPowerEventAssertionSetLevel
, // 11
178 kPowerEventQueueSleepWakeUUID
, // 12
179 kPowerEventPublishSleepWakeUUID
, // 13
180 kPowerEventSetDisplayPowerOn
, // 14
181 kPowerEventPublishWakeType
, // 15
182 kPowerEventAOTEvaluate
// 16
185 // For evaluatePolicy()
186 // List of stimuli that affects the root domain policy.
188 kStimulusDisplayWranglerSleep
, // 0
189 kStimulusDisplayWranglerWake
, // 1
190 kStimulusAggressivenessChanged
, // 2
191 kStimulusDemandSystemSleep
, // 3
192 kStimulusAllowSystemSleepChanged
, // 4
193 kStimulusDarkWakeActivityTickle
, // 5
194 kStimulusDarkWakeEntry
, // 6
195 kStimulusDarkWakeReentry
, // 7
196 kStimulusDarkWakeEvaluate
, // 8
197 kStimulusNoIdleSleepPreventers
, // 9
198 kStimulusEnterUserActiveState
, // 10
199 kStimulusLeaveUserActiveState
// 11
202 // Internal power state change reasons
203 // Must be less than kIOPMSleepReasonClamshell=101
205 kCPSReasonNone
= 0, // 0
208 kCPSReasonIdleSleepPrevent
, // 3
209 kCPSReasonIdleSleepAllow
, // 4
210 kCPSReasonPowerOverride
, // 5
211 kCPSReasonPowerDownCancel
, // 6
212 kCPSReasonAOTExit
, // 7
213 kCPSReasonAdjustPowerState
, // 8
214 kCPSReasonDarkWakeCannotSleep
, // 9
215 kCPSReasonIdleSleepEnabled
, // 10
216 kCPSReasonEvaluatePolicy
, // 11
217 kCPSReasonSustainFullWake
, // 12
218 kCPSReasonPMInternals
= (kIOPMSleepReasonClamshell
- 1)
222 IOReturn
OSKextSystemSleepOrWake( UInt32
);
224 extern "C" ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
);
225 extern "C" addr64_t
kvtophys(vm_offset_t va
);
226 extern "C" boolean_t
kdp_has_polled_corefile();
228 static void idleSleepTimerExpired( thread_call_param_t
, thread_call_param_t
);
229 static void notifySystemShutdown( IOService
* root
, uint32_t messageType
);
230 static void handleAggressivesFunction( thread_call_param_t
, thread_call_param_t
);
231 static void pmEventTimeStamp(uint64_t *recordTS
);
232 static void powerButtonUpCallout( thread_call_param_t
, thread_call_param_t
);
233 static void powerButtonDownCallout( thread_call_param_t
, thread_call_param_t
);
234 static OSPtr
<const OSSymbol
> copyKextIdentifierWithAddress(vm_address_t address
);
236 static int IOPMConvertSecondsToCalendar(clock_sec_t secs
, IOPMCalendarStruct
* dt
);
237 static clock_sec_t
IOPMConvertCalendarToSeconds(const IOPMCalendarStruct
* dt
);
238 #define YMDTF "%04d/%02d/%d %02d:%02d:%02d"
239 #define YMDT(cal) ((int)(cal)->year), (cal)->month, (cal)->day, (cal)->hour, (cal)->minute, (cal)->second
241 // "IOPMSetSleepSupported" callPlatformFunction name
242 static OSSharedPtr
<const OSSymbol
> sleepSupportedPEFunction
;
243 static OSSharedPtr
<const OSSymbol
> sleepMessagePEFunction
;
244 static OSSharedPtr
<const OSSymbol
> gIOPMWakeTypeUserKey
;
246 static OSSharedPtr
<const OSSymbol
> gIOPMPSExternalConnectedKey
;
247 static OSSharedPtr
<const OSSymbol
> gIOPMPSExternalChargeCapableKey
;
248 static OSSharedPtr
<const OSSymbol
> gIOPMPSBatteryInstalledKey
;
249 static OSSharedPtr
<const OSSymbol
> gIOPMPSIsChargingKey
;
250 static OSSharedPtr
<const OSSymbol
> gIOPMPSAtWarnLevelKey
;
251 static OSSharedPtr
<const OSSymbol
> gIOPMPSAtCriticalLevelKey
;
252 static OSSharedPtr
<const OSSymbol
> gIOPMPSCurrentCapacityKey
;
253 static OSSharedPtr
<const OSSymbol
> gIOPMPSMaxCapacityKey
;
254 static OSSharedPtr
<const OSSymbol
> gIOPMPSDesignCapacityKey
;
255 static OSSharedPtr
<const OSSymbol
> gIOPMPSTimeRemainingKey
;
256 static OSSharedPtr
<const OSSymbol
> gIOPMPSAmperageKey
;
257 static OSSharedPtr
<const OSSymbol
> gIOPMPSVoltageKey
;
258 static OSSharedPtr
<const OSSymbol
> gIOPMPSCycleCountKey
;
259 static OSSharedPtr
<const OSSymbol
> gIOPMPSMaxErrKey
;
260 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterInfoKey
;
261 static OSSharedPtr
<const OSSymbol
> gIOPMPSLocationKey
;
262 static OSSharedPtr
<const OSSymbol
> gIOPMPSErrorConditionKey
;
263 static OSSharedPtr
<const OSSymbol
> gIOPMPSManufacturerKey
;
264 static OSSharedPtr
<const OSSymbol
> gIOPMPSManufactureDateKey
;
265 static OSSharedPtr
<const OSSymbol
> gIOPMPSModelKey
;
266 static OSSharedPtr
<const OSSymbol
> gIOPMPSSerialKey
;
267 static OSSharedPtr
<const OSSymbol
> gIOPMPSLegacyBatteryInfoKey
;
268 static OSSharedPtr
<const OSSymbol
> gIOPMPSBatteryHealthKey
;
269 static OSSharedPtr
<const OSSymbol
> gIOPMPSHealthConfidenceKey
;
270 static OSSharedPtr
<const OSSymbol
> gIOPMPSCapacityEstimatedKey
;
271 static OSSharedPtr
<const OSSymbol
> gIOPMPSBatteryChargeStatusKey
;
272 static OSSharedPtr
<const OSSymbol
> gIOPMPSBatteryTemperatureKey
;
273 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsKey
;
274 static OSSharedPtr
<const OSSymbol
> gIOPMPSChargerConfigurationKey
;
275 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsIDKey
;
276 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsWattsKey
;
277 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsRevisionKey
;
278 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsSerialNumberKey
;
279 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsFamilyKey
;
280 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsAmperageKey
;
281 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsDescriptionKey
;
282 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsPMUConfigurationKey
;
283 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsSourceIDKey
;
284 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsErrorFlagsKey
;
285 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsSharedSourceKey
;
286 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsCloakedKey
;
287 static OSSharedPtr
<const OSSymbol
> gIOPMPSInvalidWakeSecondsKey
;
288 static OSSharedPtr
<const OSSymbol
> gIOPMPSPostChargeWaitSecondsKey
;
289 static OSSharedPtr
<const OSSymbol
> gIOPMPSPostDishargeWaitSecondsKey
;
291 #define kIOSleepSupportedKey "IOSleepSupported"
292 #define kIOPMSystemCapabilitiesKey "System Capabilities"
293 #define kIOPMSystemDefaultOverrideKey "SystemPowerProfileOverrideDict"
295 #define kIORequestWranglerIdleKey "IORequestIdle"
296 #define kDefaultWranglerIdlePeriod 1000 // in milliseconds
298 #define kIOSleepWakeFailureString "SleepWakeFailureString"
299 #define kIOEFIBootRomFailureKey "wake-failure"
300 #define kIOSleepWakeFailurePanic "SleepWakeFailurePanic"
302 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
303 | kIOPMSupportedOnBatt \
304 | kIOPMSupportedOnUPS)
306 #define kLocalEvalClamshellCommand (1 << 15)
307 #define kIdleSleepRetryInterval (3 * 60)
309 #define DISPLAY_WRANGLER_PRESENT (!NO_KERNEL_HID)
312 kWranglerPowerStateMin
= 0,
313 kWranglerPowerStateSleep
= 2,
314 kWranglerPowerStateDim
= 3,
315 kWranglerPowerStateMax
= 4
328 getPowerStateString( uint32_t state
)
330 #define POWER_STATE(x) {(uint32_t) x, #x}
332 static const IONamedValue powerStates
[] = {
333 POWER_STATE( OFF_STATE
),
334 POWER_STATE( RESTART_STATE
),
335 POWER_STATE( SLEEP_STATE
),
336 POWER_STATE( AOT_STATE
),
337 POWER_STATE( ON_STATE
),
340 return IOFindNameForValue(state
, powerStates
);
343 #define ON_POWER kIOPMPowerOn
344 #define RESTART_POWER kIOPMRestart
345 #define SLEEP_POWER kIOPMAuxPowerOn
347 static IOPMPowerState
348 ourPowerStates
[NUM_POWER_STATES
] =
351 .capabilityFlags
= 0,
352 .outputPowerCharacter
= 0,
353 .inputPowerRequirement
= 0 },
355 .capabilityFlags
= kIOPMRestartCapability
,
356 .outputPowerCharacter
= kIOPMRestart
,
357 .inputPowerRequirement
= RESTART_POWER
},
359 .capabilityFlags
= kIOPMSleepCapability
,
360 .outputPowerCharacter
= kIOPMSleep
,
361 .inputPowerRequirement
= SLEEP_POWER
},
363 .capabilityFlags
= kIOPMAOTCapability
,
364 .outputPowerCharacter
= kIOPMAOTPower
,
365 .inputPowerRequirement
= ON_POWER
},
367 .capabilityFlags
= kIOPMPowerOn
,
368 .outputPowerCharacter
= kIOPMPowerOn
,
369 .inputPowerRequirement
= ON_POWER
},
372 #define kIOPMRootDomainWakeTypeSleepService "SleepService"
373 #define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
374 #define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
375 #define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
376 #define kIOPMRootDomainWakeTypeUser "User"
377 #define kIOPMRootDomainWakeTypeAlarm "Alarm"
378 #define kIOPMRootDomainWakeTypeNetwork "Network"
379 #define kIOPMRootDomainWakeTypeHIDActivity "HID Activity"
380 #define kIOPMRootDomainWakeTypeNotification "Notification"
381 #define kIOPMRootDomainWakeTypeHibernateError "HibernateError"
383 // Special interest that entitles the interested client from receiving
384 // all system messages. Only used by powerd.
386 #define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
388 // Entitlement required for root domain clients
389 #define kRootDomainEntitlementSetProperty "com.apple.private.iokit.rootdomain-set-property"
391 #define WAKEEVENT_LOCK() IOLockLock(wakeEventLock)
392 #define WAKEEVENT_UNLOCK() IOLockUnlock(wakeEventLock)
397 #define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
398 #define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
400 #define kAggressivesMinValue 1
403 getAggressivenessTypeString( uint32_t type
)
405 #define AGGRESSIVENESS_TYPE(x) {(uint32_t) x, #x}
407 static const IONamedValue aggressivenessTypes
[] = {
408 AGGRESSIVENESS_TYPE( kPMGeneralAggressiveness
),
409 AGGRESSIVENESS_TYPE( kPMMinutesToDim
),
410 AGGRESSIVENESS_TYPE( kPMMinutesToSpinDown
),
411 AGGRESSIVENESS_TYPE( kPMMinutesToSleep
),
412 AGGRESSIVENESS_TYPE( kPMEthernetWakeOnLANSettings
),
413 AGGRESSIVENESS_TYPE( kPMSetProcessorSpeed
),
414 AGGRESSIVENESS_TYPE( kPMPowerSource
),
415 AGGRESSIVENESS_TYPE( kPMMotionSensor
),
416 AGGRESSIVENESS_TYPE( kPMLastAggressivenessType
),
419 return IOFindNameForValue(type
, aggressivenessTypes
);
423 kAggressivesStateBusy
= 0x01,
424 kAggressivesStateQuickSpindown
= 0x02
427 struct AggressivesRecord
{
433 struct AggressivesRequest
{
438 OSSharedPtr
<IOService
> service
;
439 AggressivesRecord record
;
444 kAggressivesRequestTypeService
= 1,
445 kAggressivesRequestTypeRecord
449 kAggressivesOptionSynchronous
= 0x00000001,
450 kAggressivesOptionQuickSpindownEnable
= 0x00000100,
451 kAggressivesOptionQuickSpindownDisable
= 0x00000200,
452 kAggressivesOptionQuickSpindownMask
= 0x00000300
456 kAggressivesRecordFlagModified
= 0x00000001,
457 kAggressivesRecordFlagMinValue
= 0x00000002
460 // System Sleep Preventers
463 kPMUserDisabledAllSleep
= 1,
464 kPMSystemRestartBootingInProgress
,
465 kPMConfigPreventSystemSleep
,
466 kPMChildPreventSystemSleep
,
472 getSystemSleepPreventerString( uint32_t preventer
)
474 #define SYSTEM_SLEEP_PREVENTER(x) {(int) x, #x}
475 static const IONamedValue systemSleepPreventers
[] = {
476 SYSTEM_SLEEP_PREVENTER( kPMUserDisabledAllSleep
),
477 SYSTEM_SLEEP_PREVENTER( kPMSystemRestartBootingInProgress
),
478 SYSTEM_SLEEP_PREVENTER( kPMConfigPreventSystemSleep
),
479 SYSTEM_SLEEP_PREVENTER( kPMChildPreventSystemSleep
),
480 SYSTEM_SLEEP_PREVENTER( kPMCPUAssertion
),
481 SYSTEM_SLEEP_PREVENTER( kPMPCIUnsupported
),
484 return IOFindNameForValue(preventer
, systemSleepPreventers
);
489 kDarkWakeFlagPromotionNone
= 0x0000,
490 kDarkWakeFlagPromotionEarly
= 0x0001, // promote before gfx clamp
491 kDarkWakeFlagPromotionLate
= 0x0002, // promote after gfx clamp
492 kDarkWakeFlagPromotionMask
= 0x0003,
493 kDarkWakeFlagAlarmIsDark
= 0x0100,
494 kDarkWakeFlagAudioNotSuppressed
= 0x0200,
495 kDarkWakeFlagUserWakeWorkaround
= 0x1000
499 // The workaround for 9157444 is enabled at compile time using the
500 // DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY macro and is not represented below.
502 kClamshell_WAR_38378787
= 0x00000001,
503 kClamshell_WAR_47715679
= 0x00000002,
504 kClamshell_WAR_58009435
= 0x00000004
507 // acceptSystemWakeEvents()
509 kAcceptSystemWakeEvents_Disable
= 0,
510 kAcceptSystemWakeEvents_Enable
,
511 kAcceptSystemWakeEvents_Reenable
514 static IOPMrootDomain
* gRootDomain
;
515 static IORootParent
* gPatriarch
;
516 static IONotifier
* gSysPowerDownNotifier
= NULL
;
517 static UInt32 gSleepOrShutdownPending
= 0;
518 static UInt32 gWillShutdown
= 0;
519 static UInt32 gPagingOff
= 0;
520 static UInt32 gSleepWakeUUIDIsSet
= false;
521 static uint32_t gAggressivesState
= 0;
522 static uint32_t gHaltTimeMaxLog
;
523 static uint32_t gHaltTimeMaxPanic
;
524 IOLock
* gHaltLogLock
;
525 static char * gHaltLog
;
526 enum { kHaltLogSize
= 2048 };
527 static size_t gHaltLogPos
;
528 static uint64_t gHaltStartTime
;
529 static char gKextNameBuf
[64];
530 static size_t gKextNamePos
;
531 static bool gKextNameEnd
;
533 uuid_string_t bootsessionuuid_string
;
535 #if defined(XNU_TARGET_OS_OSX)
536 #if DISPLAY_WRANGLER_PRESENT
537 static uint32_t gDarkWakeFlags
= kDarkWakeFlagPromotionNone
;
539 // Enable temporary full wake promotion workarounds
540 static uint32_t gDarkWakeFlags
= kDarkWakeFlagUserWakeWorkaround
;
542 // Enable full wake promotion workarounds
543 static uint32_t gDarkWakeFlags
= kDarkWakeFlagUserWakeWorkaround
;
545 #else /* !defined(XNU_TARGET_OS_OSX) */
546 static uint32_t gDarkWakeFlags
= kDarkWakeFlagPromotionEarly
;
547 #endif /* !defined(XNU_TARGET_OS_OSX) */
549 static uint32_t gNoIdleFlag
= 0;
550 static uint32_t gSwdPanic
= 1;
551 static uint32_t gSwdSleepTimeout
= 0;
552 static uint32_t gSwdWakeTimeout
= 0;
553 static uint32_t gSwdSleepWakeTimeout
= 0;
554 static PMStatsStruct gPMStats
;
555 #if DEVELOPMENT || DEBUG
556 static uint32_t swd_panic_phase
;
559 static uint32_t gClamshellFlags
= 0
560 #if defined(__i386__) || defined(__x86_64__)
561 | kClamshell_WAR_58009435
567 #if defined(__arm64__)
569 defaultSleepPolicyHandler(void *ctx
, const IOPMSystemSleepPolicyVariables
*vars
, IOPMSystemSleepParameters
*params
)
571 uint32_t sleepType
= kIOPMSleepTypeDeepIdle
;
573 assert(vars
->signature
== kIOPMSystemSleepPolicySignature
);
574 assert(vars
->version
== kIOPMSystemSleepPolicyVersion
);
576 // Hibernation enabled and either user forced hibernate or low battery sleep
577 if ((vars
->hibernateMode
& kIOHibernateModeOn
) &&
578 (((vars
->hibernateMode
& kIOHibernateModeSleep
) == 0) ||
579 (vars
->sleepFactors
& kIOPMSleepFactorBatteryLow
))) {
580 sleepType
= kIOPMSleepTypeHibernate
;
582 params
->version
= kIOPMSystemSleepParametersVersion
;
583 params
->sleepType
= sleepType
;
584 return kIOReturnSuccess
;
586 static IOPMSystemSleepPolicyHandler gSleepPolicyHandler
= &defaultSleepPolicyHandler
;
587 #else /* defined(__arm64__) */
588 static IOPMSystemSleepPolicyHandler gSleepPolicyHandler
= NULL
;
589 #endif /* defined(__arm64__) */
591 static IOPMSystemSleepPolicyVariables
* gSleepPolicyVars
= NULL
;
592 static void * gSleepPolicyTarget
;
595 struct timeval gIOLastSleepTime
;
596 struct timeval gIOLastWakeTime
;
597 AbsoluteTime gIOLastWakeAbsTime
;
598 AbsoluteTime gIOLastSleepAbsTime
;
600 struct timeval gIOLastUserSleepTime
;
602 static char gWakeReasonString
[128];
603 static char gBootReasonString
[80];
604 static char gShutdownReasonString
[80];
605 static bool gWakeReasonSysctlRegistered
= false;
606 static bool gBootReasonSysctlRegistered
= false;
607 static bool gShutdownReasonSysctlRegistered
= false;
608 static AbsoluteTime gUserActiveAbsTime
;
609 static AbsoluteTime gUserInactiveAbsTime
;
611 #if defined(__i386__) || defined(__x86_64__) || (defined(__arm64__) && HIBERNATION)
612 static bool gSpinDumpBufferFull
= false;
616 vm_offset_t swd_zs_zmem
;
617 //size_t swd_zs_zsize;
618 size_t swd_zs_zoffset
;
619 #if defined(__i386__) || defined(__x86_64__)
620 IOCPU
*currentShutdownTarget
= NULL
;
623 static unsigned int gPMHaltBusyCount
;
624 static unsigned int gPMHaltIdleCount
;
625 static int gPMHaltDepth
;
626 static uint32_t gPMHaltMessageType
;
627 static IOLock
* gPMHaltLock
= NULL
;
628 static OSSharedPtr
<OSArray
> gPMHaltArray
;
629 static OSSharedPtr
<const OSSymbol
> gPMHaltClientAcknowledgeKey
;
630 static bool gPMQuiesced
;
632 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
633 #define kCPUUnknownIndex 9999999
640 OSSharedPtr
<const OSSymbol
> gIOPMStatsResponseTimedOut
;
641 OSSharedPtr
<const OSSymbol
> gIOPMStatsResponseCancel
;
642 OSSharedPtr
<const OSSymbol
> gIOPMStatsResponseSlow
;
643 OSSharedPtr
<const OSSymbol
> gIOPMStatsResponsePrompt
;
644 OSSharedPtr
<const OSSymbol
> gIOPMStatsDriverPSChangeSlow
;
646 #define kBadPMFeatureID 0
650 * Opaque handle passed to clients of registerPMSettingController()
652 class PMSettingHandle
: public OSObject
654 OSDeclareFinalStructors( PMSettingHandle
);
655 friend class PMSettingObject
;
658 PMSettingObject
*pmso
;
659 void free(void) APPLE_KEXT_OVERRIDE
;
664 * Internal object to track each PM setting controller
666 class PMSettingObject
: public OSObject
668 OSDeclareFinalStructors( PMSettingObject
);
669 friend class IOPMrootDomain
;
672 queue_head_t calloutQueue
;
674 IOPMrootDomain
*parent
;
675 PMSettingHandle
*pmsh
;
676 IOPMSettingControllerCallback func
;
679 uint32_t *publishedFeatureID
;
680 uint32_t settingCount
;
683 void free(void) APPLE_KEXT_OVERRIDE
;
686 static PMSettingObject
*pmSettingObject(
687 IOPMrootDomain
*parent_arg
,
688 IOPMSettingControllerCallback handler_arg
,
689 OSObject
*target_arg
,
690 uintptr_t refcon_arg
,
691 uint32_t supportedPowerSources
,
692 const OSSymbol
*settings
[],
693 OSObject
**handle_obj
);
695 IOReturn
dispatchPMSetting(const OSSymbol
*type
, OSObject
*object
);
696 void clientHandleFreed(void);
699 struct PMSettingCallEntry
{
704 #define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
705 #define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
706 #define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
707 #define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
711 * Internal helper object for logging trace points to RTC
712 * IOPMrootDomain and only IOPMrootDomain should instantiate
713 * exactly one of these.
716 typedef void (*IOPMTracePointHandler
)(
717 void * target
, uint32_t code
, uint32_t data
);
719 class PMTraceWorker
: public OSObject
721 OSDeclareDefaultStructors(PMTraceWorker
);
723 typedef enum { kPowerChangeStart
, kPowerChangeCompleted
} change_t
;
725 static OSPtr
<PMTraceWorker
> tracer( IOPMrootDomain
* );
726 void tracePCIPowerChange(change_t
, IOService
*, uint32_t, uint32_t);
727 void tracePoint(uint8_t phase
);
728 void traceDetail(uint32_t detail
);
729 void traceComponentWakeProgress(uint32_t component
, uint32_t data
);
730 int recordTopLevelPCIDevice(IOService
*);
731 void RTC_TRACE(void);
732 virtual bool serialize(OSSerialize
*s
) const APPLE_KEXT_OVERRIDE
;
734 IOPMTracePointHandler tracePointHandler
;
735 void * tracePointTarget
;
736 uint64_t getPMStatusCode();
737 uint8_t getTracePhase();
738 uint32_t getTraceData();
740 IOPMrootDomain
*owner
;
741 IOLock
*pmTraceWorkerLock
;
742 OSSharedPtr
<OSArray
> pciDeviceBitMappings
;
744 uint8_t addedToRegistry
;
746 uint32_t traceData32
;
747 uint8_t loginWindowData
;
748 uint8_t coreDisplayData
;
749 uint8_t coreGraphicsData
;
753 * PMAssertionsTracker
754 * Tracks kernel and user space PM assertions
756 class PMAssertionsTracker
: public OSObject
758 OSDeclareFinalStructors(PMAssertionsTracker
);
760 static PMAssertionsTracker
*pmAssertionsTracker( IOPMrootDomain
* );
762 IOReturn
createAssertion(IOPMDriverAssertionType
, IOPMDriverAssertionLevel
, IOService
*, const char *, IOPMDriverAssertionID
*);
763 IOReturn
releaseAssertion(IOPMDriverAssertionID
);
764 IOReturn
setAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
765 IOReturn
setUserAssertionLevels(IOPMDriverAssertionType
);
767 OSSharedPtr
<OSArray
> copyAssertionsArray(void);
768 IOPMDriverAssertionType
getActivatedAssertions(void);
769 IOPMDriverAssertionLevel
getAssertionLevel(IOPMDriverAssertionType
);
771 IOReturn
handleCreateAssertion(OSData
*);
772 IOReturn
handleReleaseAssertion(IOPMDriverAssertionID
);
773 IOReturn
handleSetAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
774 IOReturn
handleSetUserAssertionLevels(void * arg0
);
775 void publishProperties(void);
776 void reportCPUBitAccounting(void);
780 * this should be treated as POD, as it's byte-copied around
781 * and we cannot rely on d'tor firing at the right time
784 IOPMDriverAssertionID id
;
785 IOPMDriverAssertionType assertionBits
;
786 uint64_t createdTime
;
787 uint64_t modifiedTime
;
788 const OSSymbol
*ownerString
;
789 IOService
*ownerService
;
790 uint64_t registryEntryID
;
791 IOPMDriverAssertionLevel level
;
792 uint64_t assertCPUStartTime
;
793 uint64_t assertCPUDuration
;
796 uint32_t tabulateProducerCount
;
797 uint32_t tabulateConsumerCount
;
799 uint64_t maxAssertCPUDuration
;
800 uint64_t maxAssertCPUEntryId
;
802 PMAssertStruct
*detailsForID(IOPMDriverAssertionID
, int *);
804 void updateCPUBitAccounting(PMAssertStruct
* assertStruct
);
806 IOPMrootDomain
*owner
;
807 OSSharedPtr
<OSArray
> assertionsArray
;
808 IOLock
*assertionsArrayLock
;
809 IOPMDriverAssertionID issuingUniqueID
__attribute__((aligned(8)));/* aligned for atomic access */
810 IOPMDriverAssertionType assertionsKernel
;
811 IOPMDriverAssertionType assertionsUser
;
812 IOPMDriverAssertionType assertionsCombined
;
815 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker
, OSObject
);
819 * Internal helper object for Shutdown/Restart notifications.
821 #define kPMHaltMaxWorkers 8
822 #define kPMHaltTimeoutMS 100
824 class PMHaltWorker
: public OSObject
826 OSDeclareFinalStructors( PMHaltWorker
);
829 IOService
* service
;// service being worked on
830 AbsoluteTime startTime
; // time when work started
831 int depth
; // work on nubs at this PM-tree depth
832 int visits
; // number of nodes visited (debug)
834 bool timeout
;// service took too long
836 static PMHaltWorker
* worker( void );
837 static void main( void * arg
, wait_result_t waitResult
);
838 static void work( PMHaltWorker
* me
);
839 static void checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
);
840 virtual void free( void ) APPLE_KEXT_OVERRIDE
;
843 OSDefineMetaClassAndFinalStructors( PMHaltWorker
, OSObject
)
846 #define super IOService
847 OSDefineMetaClassAndFinalStructors(IOPMrootDomain
, IOService
)
850 IOPMRootDomainGetWillShutdown(void)
852 return gWillShutdown
!= 0;
856 IOPMRootDomainWillShutdown(void)
858 if (OSCompareAndSwap(0, 1, &gWillShutdown
)) {
859 IOService::willShutdown();
860 for (int i
= 0; i
< 100; i
++) {
861 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending
)) {
869 extern "C" IONotifier
*
870 registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
872 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
).detach();
875 extern "C" IONotifier
*
876 registerPrioritySleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
878 return gRootDomain
->registerInterest( gIOPriorityPowerStateInterest
, handler
, self
, ref
).detach();
882 acknowledgeSleepWakeNotification(void * PMrefcon
)
884 return gRootDomain
->allowPowerChange((unsigned long)PMrefcon
);
888 vetoSleepWakeNotification(void * PMrefcon
)
890 return gRootDomain
->cancelPowerChange((unsigned long)PMrefcon
);
894 rootDomainRestart( void )
896 return gRootDomain
->restartSystem();
900 rootDomainShutdown( void )
902 return gRootDomain
->shutdownSystem();
906 halt_log_putc(char c
)
908 if (gHaltLogPos
>= (kHaltLogSize
- 2)) {
911 gHaltLog
[gHaltLogPos
++] = c
;
915 _doprnt_log(const char *fmt
,
921 halt_log(const char *fmt
, ...)
925 va_start(listp
, fmt
);
926 _doprnt_log(fmt
, &listp
, &halt_log_putc
, 16);
933 halt_log_enter(const char * what
, const void * pc
, uint64_t time
)
935 uint64_t nano
, millis
;
940 absolutetime_to_nanoseconds(time
, &nano
);
941 millis
= nano
/ NSEC_PER_MSEC
;
946 IOLockLock(gHaltLogLock
);
948 halt_log("%s: %qd ms @ 0x%lx, ", what
, millis
, VM_KERNEL_UNSLIDE(pc
));
949 OSKext::printKextsInBacktrace((vm_offset_t
*) &pc
, 1, &halt_log
,
950 OSKext::kPrintKextsLock
| OSKext::kPrintKextsUnslide
| OSKext::kPrintKextsTerse
);
952 halt_log("%s: %qd ms\n", what
, millis
);
955 gHaltLog
[gHaltLogPos
] = 0;
956 IOLockUnlock(gHaltLogLock
);
959 extern uint32_t gFSState
;
962 IOSystemShutdownNotification(int stage
)
966 if (kIOSystemShutdownNotificationStageRootUnmount
== stage
) {
967 #if defined(XNU_TARGET_OS_OSX)
968 uint64_t nano
, millis
;
969 startTime
= mach_absolute_time();
970 IOService::getPlatform()->waitQuiet(30 * NSEC_PER_SEC
);
971 absolutetime_to_nanoseconds(mach_absolute_time() - startTime
, &nano
);
972 millis
= nano
/ NSEC_PER_MSEC
;
973 if (gHaltTimeMaxLog
&& (millis
>= gHaltTimeMaxLog
)) {
974 printf("waitQuiet() for unmount %qd ms\n", millis
);
976 #endif /* defined(XNU_TARGET_OS_OSX) */
980 assert(kIOSystemShutdownNotificationStageProcessExit
== stage
);
982 IOLockLock(gHaltLogLock
);
984 gHaltLog
= IONew(char, kHaltLogSize
);
985 gHaltStartTime
= mach_absolute_time();
990 IOLockUnlock(gHaltLogLock
);
992 startTime
= mach_absolute_time();
993 IOPMRootDomainWillShutdown();
994 halt_log_enter("IOPMRootDomainWillShutdown", NULL
, mach_absolute_time() - startTime
);
996 startTime
= mach_absolute_time();
997 IOHibernateSystemPostWake(true);
998 halt_log_enter("IOHibernateSystemPostWake", NULL
, mach_absolute_time() - startTime
);
1000 if (OSCompareAndSwap(0, 1, &gPagingOff
)) {
1001 gRootDomain
->handlePlatformHaltRestart(kPEPagingOff
);
1006 extern "C" int sync_internal(void);
1009 * A device is always in the highest power state which satisfies its driver,
1010 * its policy-maker, and any power children it has, but within the constraint
1011 * of the power state provided by its parent. The driver expresses its desire by
1012 * calling changePowerStateTo(), the policy-maker expresses its desire by calling
1013 * changePowerStateToPriv(), and the children express their desires by calling
1014 * requestPowerDomainState().
1016 * The Root Power Domain owns the policy for idle and demand sleep for the system.
1017 * It is a power-managed IOService just like the others in the system.
1018 * It implements several power states which map to what we see as Sleep and On.
1020 * The sleep policy is as follows:
1021 * 1. Sleep is prevented if the case is open so that nobody will think the machine
1022 * is off and plug/unplug cards.
1023 * 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
1024 * 3. System cannot Sleep if some object in the tree is in a power state marked
1025 * kIOPMPreventSystemSleep.
1027 * These three conditions are enforced using the "driver clamp" by calling
1028 * changePowerStateTo(). For example, if the case is opened,
1029 * changePowerStateTo(ON_STATE) is called to hold the system on regardless
1030 * of the desires of the children of the root or the state of the other clamp.
1032 * Demand Sleep is initiated by pressing the front panel power button, closing
1033 * the clamshell, or selecting the menu item. In this case the root's parent
1034 * actually initiates the power state change so that the root domain has no
1035 * choice and does not give applications the opportunity to veto the change.
1037 * Idle Sleep occurs if no objects in the tree are in a state marked
1038 * kIOPMPreventIdleSleep. When this is true, the root's children are not holding
1039 * the root on, so it sets the "policy-maker clamp" by calling
1040 * changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
1041 * This timer is set for the difference between the sleep timeout slider and the
1042 * display dim timeout slider. When the timer expires, it releases its clamp and
1043 * now nothing is holding it awake, so it falls asleep.
1045 * Demand sleep is prevented when the system is booting. When preferences are
1046 * transmitted by the loginwindow at the end of boot, a flag is cleared,
1047 * and this allows subsequent Demand Sleep.
1050 //******************************************************************************
1053 IOPMrootDomain::construct( void )
1055 IOPMrootDomain
*root
;
1057 root
= new IOPMrootDomain
;
1065 //******************************************************************************
1066 // updateConsoleUsersCallout
1068 //******************************************************************************
1071 updateConsoleUsersCallout(thread_call_param_t p0
, thread_call_param_t p1
)
1073 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
1074 rootDomain
->updateConsoleUsers();
1078 IOPMrootDomain::updateConsoleUsers(void)
1080 IOService::updateConsoleUsers(NULL
, kIOMessageSystemHasPoweredOn
);
1081 if (tasksSuspended
) {
1082 tasksSuspended
= FALSE
;
1083 updateTasksSuspend();
1088 IOPMrootDomain::updateTasksSuspend(void)
1092 newSuspend
= (tasksSuspended
|| _aotTasksSuspended
);
1093 if (newSuspend
== tasksSuspendState
) {
1096 tasksSuspendState
= newSuspend
;
1097 tasks_system_suspend(newSuspend
);
1100 //******************************************************************************
1103 disk_sync_callout( thread_call_param_t p0
, thread_call_param_t p1
)
1105 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
1106 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
1107 uint32_t powerState
= rootDomain
->getPowerState();
1109 DLOG("disk_sync_callout ps=%u\n", powerState
);
1111 if (ON_STATE
== powerState
) {
1115 // Block sleep until trim issued on previous wake path is completed.
1116 IOHibernateSystemPostWake(true);
1121 IOHibernateSystemPostWake(false);
1123 rootDomain
->sleepWakeDebugSaveSpinDumpFile();
1127 rootDomain
->allowPowerChange(notifyRef
);
1128 DLOG("disk_sync_callout finish\n");
1131 //******************************************************************************
1133 computeDeltaTimeMS( const AbsoluteTime
* startTime
, AbsoluteTime
* elapsedTime
)
1135 AbsoluteTime endTime
;
1138 clock_get_uptime(&endTime
);
1139 if (CMP_ABSOLUTETIME(&endTime
, startTime
) <= 0) {
1142 SUB_ABSOLUTETIME(&endTime
, startTime
);
1143 absolutetime_to_nanoseconds(endTime
, &nano
);
1144 *elapsedTime
= endTime
;
1147 return (UInt32
)(nano
/ NSEC_PER_MSEC
);
1150 //******************************************************************************
1153 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
1155 struct timeval
*swt
= (struct timeval
*)arg1
;
1156 struct proc
*p
= req
->p
;
1158 if (p
== kernproc
) {
1159 return sysctl_io_opaque(req
, swt
, sizeof(*swt
), NULL
);
1160 } else if (proc_is64bit(p
)) {
1161 struct user64_timeval t
= {};
1162 t
.tv_sec
= swt
->tv_sec
;
1163 t
.tv_usec
= swt
->tv_usec
;
1164 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
1166 struct user32_timeval t
= {};
1167 t
.tv_sec
= (typeof(t
.tv_sec
))swt
->tv_sec
;
1168 t
.tv_usec
= swt
->tv_usec
;
1169 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
1173 static SYSCTL_PROC(_kern
, OID_AUTO
, sleeptime
,
1174 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1175 &gIOLastUserSleepTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
1177 static SYSCTL_PROC(_kern
, OID_AUTO
, waketime
,
1178 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1179 &gIOLastWakeTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
1181 SYSCTL_QUAD(_kern
, OID_AUTO
, wake_abs_time
, CTLFLAG_RD
| CTLFLAG_LOCKED
, &gIOLastWakeAbsTime
, "");
1182 SYSCTL_QUAD(_kern
, OID_AUTO
, sleep_abs_time
, CTLFLAG_RD
| CTLFLAG_LOCKED
, &gIOLastSleepAbsTime
, "");
1183 SYSCTL_QUAD(_kern
, OID_AUTO
, useractive_abs_time
, CTLFLAG_RD
| CTLFLAG_LOCKED
, &gUserActiveAbsTime
, "");
1184 SYSCTL_QUAD(_kern
, OID_AUTO
, userinactive_abs_time
, CTLFLAG_RD
| CTLFLAG_LOCKED
, &gUserInactiveAbsTime
, "");
1188 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
1190 int new_value
, changed
;
1191 int error
= sysctl_io_number(req
, gWillShutdown
, sizeof(int), &new_value
, &changed
);
1193 if (!gWillShutdown
&& (new_value
== 1)) {
1194 IOPMRootDomainWillShutdown();
1202 static SYSCTL_PROC(_kern
, OID_AUTO
, willshutdown
,
1203 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1204 NULL
, 0, sysctl_willshutdown
, "I", "");
1206 extern struct sysctl_oid sysctl__kern_iokittest
;
1207 extern struct sysctl_oid sysctl__debug_iokit
;
1209 #if defined(XNU_TARGET_OS_OSX)
1212 sysctl_progressmeterenable
1213 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
1216 int new_value
, changed
;
1218 error
= sysctl_io_number(req
, vc_progressmeter_enable
, sizeof(int), &new_value
, &changed
);
1221 vc_enable_progressmeter(new_value
);
1228 sysctl_progressmeter
1229 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
1232 int new_value
, changed
;
1234 error
= sysctl_io_number(req
, vc_progressmeter_value
, sizeof(int), &new_value
, &changed
);
1237 vc_set_progressmeter(new_value
);
1243 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeterenable
,
1244 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1245 NULL
, 0, sysctl_progressmeterenable
, "I", "");
1247 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeter
,
1248 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1249 NULL
, 0, sysctl_progressmeter
, "I", "");
1251 #endif /* defined(XNU_TARGET_OS_OSX) */
1256 sysctl_consoleoptions
1257 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
1262 error
= sysctl_io_number(req
, vc_user_options
.options
, sizeof(uint32_t), &new_value
, &changed
);
1265 vc_user_options
.options
= new_value
;
1271 static SYSCTL_PROC(_kern
, OID_AUTO
, consoleoptions
,
1272 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1273 NULL
, 0, sysctl_consoleoptions
, "I", "");
1277 sysctl_progressoptions SYSCTL_HANDLER_ARGS
1279 return sysctl_io_opaque(req
, &vc_user_options
, sizeof(vc_user_options
), NULL
);
1282 static SYSCTL_PROC(_kern
, OID_AUTO
, progressoptions
,
1283 CTLTYPE_STRUCT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
| CTLFLAG_ANYBODY
,
1284 NULL
, 0, sysctl_progressoptions
, "S,vc_progress_user_options", "");
1288 sysctl_wakereason SYSCTL_HANDLER_ARGS
1290 char wr
[sizeof(gWakeReasonString
)];
1294 gRootDomain
->copyWakeReasonString(wr
, sizeof(wr
));
1297 return sysctl_io_string(req
, wr
, 0, 0, NULL
);
1300 SYSCTL_PROC(_kern
, OID_AUTO
, wakereason
,
1301 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1302 NULL
, 0, sysctl_wakereason
, "A", "wakereason");
1304 SYSCTL_STRING(_kern
, OID_AUTO
, bootreason
,
1305 CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1306 gBootReasonString
, sizeof(gBootReasonString
), "");
1309 sysctl_shutdownreason SYSCTL_HANDLER_ARGS
1311 char sr
[sizeof(gShutdownReasonString
)];
1315 gRootDomain
->copyShutdownReasonString(sr
, sizeof(sr
));
1318 return sysctl_io_string(req
, sr
, 0, 0, NULL
);
1321 SYSCTL_PROC(_kern
, OID_AUTO
, shutdownreason
,
1322 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1323 NULL
, 0, sysctl_shutdownreason
, "A", "shutdownreason");
1326 sysctl_targettype SYSCTL_HANDLER_ARGS
1329 OSSharedPtr
<OSObject
> obj
;
1334 root
= IOService::getServiceRoot();
1335 if (root
&& (obj
= root
->copyProperty(gIODTTargetTypeKey
))) {
1336 if ((data
= OSDynamicCast(OSData
, obj
.get()))) {
1337 strlcpy(tt
, (const char *) data
->getBytesNoCopy(), sizeof(tt
));
1340 return sysctl_io_string(req
, tt
, 0, 0, NULL
);
1343 SYSCTL_PROC(_hw
, OID_AUTO
, targettype
,
1344 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1345 NULL
, 0, sysctl_targettype
, "A", "targettype");
1347 static SYSCTL_INT(_debug
, OID_AUTO
, noidle
, CTLFLAG_RW
, &gNoIdleFlag
, 0, "");
1348 static SYSCTL_INT(_debug
, OID_AUTO
, swd_sleep_timeout
, CTLFLAG_RW
, &gSwdSleepTimeout
, 0, "");
1349 static SYSCTL_INT(_debug
, OID_AUTO
, swd_wake_timeout
, CTLFLAG_RW
, &gSwdWakeTimeout
, 0, "");
1350 static SYSCTL_INT(_debug
, OID_AUTO
, swd_timeout
, CTLFLAG_RW
, &gSwdSleepWakeTimeout
, 0, "");
1351 static SYSCTL_INT(_debug
, OID_AUTO
, swd_panic
, CTLFLAG_RW
, &gSwdPanic
, 0, "");
1352 #if DEVELOPMENT || DEBUG
1353 static SYSCTL_INT(_debug
, OID_AUTO
, swd_panic_phase
, CTLFLAG_RW
, &swd_panic_phase
, 0, "");
1354 #if defined(XNU_TARGET_OS_OSX)
1355 static SYSCTL_INT(_debug
, OID_AUTO
, clamshell
, CTLFLAG_RW
, &gClamshellFlags
, 0, "");
1356 static SYSCTL_INT(_debug
, OID_AUTO
, darkwake
, CTLFLAG_RW
, &gDarkWakeFlags
, 0, "");
1357 #endif /* defined(XNU_TARGET_OS_OSX) */
1358 #endif /* DEVELOPMENT || DEBUG */
1360 //******************************************************************************
1364 sysctl_aotmetrics SYSCTL_HANDLER_ARGS
1366 if (NULL
== gRootDomain
) {
1369 if (NULL
== gRootDomain
->_aotMetrics
) {
1372 return sysctl_io_opaque(req
, gRootDomain
->_aotMetrics
, sizeof(IOPMAOTMetrics
), NULL
);
1375 static SYSCTL_PROC(_kern
, OID_AUTO
, aotmetrics
,
1376 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
| CTLFLAG_ANYBODY
,
1377 NULL
, 0, sysctl_aotmetrics
, "S,IOPMAOTMetrics", "");
1381 update_aotmode(uint32_t mode
)
1385 if (!gIOPMWorkLoop
) {
1388 result
= gIOPMWorkLoop
->runActionBlock(^IOReturn (void) {
1389 unsigned int oldCount
;
1391 if (mode
&& !gRootDomain
->_aotMetrics
) {
1392 gRootDomain
->_aotMetrics
= IONewZero(IOPMAOTMetrics
, 1);
1393 if (!gRootDomain
->_aotMetrics
) {
1398 oldCount
= gRootDomain
->idleSleepPreventersCount();
1399 gRootDomain
->_aotMode
= (mode
& kIOPMAOTModeMask
);
1400 gRootDomain
->updatePreventIdleSleepListInternal(NULL
, false, oldCount
);
1408 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
1413 if (NULL
== gRootDomain
) {
1416 error
= sysctl_io_number(req
, gRootDomain
->_aotMode
, sizeof(uint32_t), &new_value
, &changed
);
1417 if (changed
&& gIOPMWorkLoop
) {
1418 error
= update_aotmode(new_value
);
1424 static SYSCTL_PROC(_kern
, OID_AUTO
, aotmodebits
,
1425 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1426 NULL
, 0, sysctl_aotmodebits
, "I", "");
1430 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
1435 if (NULL
== gRootDomain
) {
1438 error
= sysctl_io_number(req
, gRootDomain
->_aotMode
, sizeof(uint32_t), &new_value
, &changed
);
1439 if (changed
&& gIOPMWorkLoop
) {
1441 new_value
= kIOPMAOTModeDefault
; // & ~kIOPMAOTModeRespectTimers;
1443 error
= update_aotmode(new_value
);
1449 static SYSCTL_PROC(_kern
, OID_AUTO
, aotmode
,
1450 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
| CTLFLAG_ANYBODY
,
1451 NULL
, 0, sysctl_aotmode
, "I", "");
1453 //******************************************************************************
1455 static OSSharedPtr
<const OSSymbol
> gIOPMSettingAutoWakeCalendarKey
;
1456 static OSSharedPtr
<const OSSymbol
> gIOPMSettingAutoWakeSecondsKey
;
1457 static OSSharedPtr
<const OSSymbol
> gIOPMSettingAutoPowerCalendarKey
;
1458 static OSSharedPtr
<const OSSymbol
> gIOPMSettingAutoPowerSecondsKey
;
1459 static OSSharedPtr
<const OSSymbol
> gIOPMSettingDebugWakeRelativeKey
;
1460 static OSSharedPtr
<const OSSymbol
> gIOPMSettingDebugPowerRelativeKey
;
1461 static OSSharedPtr
<const OSSymbol
> gIOPMSettingMaintenanceWakeCalendarKey
;
1462 static OSSharedPtr
<const OSSymbol
> gIOPMSettingSleepServiceWakeCalendarKey
;
1463 static OSSharedPtr
<const OSSymbol
> gIOPMSettingSilentRunningKey
;
1464 static OSSharedPtr
<const OSSymbol
> gIOPMUserTriggeredFullWakeKey
;
1465 static OSSharedPtr
<const OSSymbol
> gIOPMUserIsActiveKey
;
1466 static OSSharedPtr
<const OSSymbol
> gIOPMSettingLowLatencyAudioModeKey
;
1468 //******************************************************************************
1471 //******************************************************************************
1473 #define kRootDomainSettingsCount 20
1474 #define kRootDomainNoPublishSettingsCount 4
1477 IOPMrootDomain::start( IOService
* nub
)
1479 OSSharedPtr
<OSIterator
> psIterator
;
1480 OSSharedPtr
<OSDictionary
> tmpDict
;
1485 gIOPMSettingAutoWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
);
1486 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
1487 gIOPMSettingAutoPowerCalendarKey
= OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
);
1488 gIOPMSettingAutoPowerSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
);
1489 gIOPMSettingDebugWakeRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
);
1490 gIOPMSettingDebugPowerRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
);
1491 gIOPMSettingMaintenanceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
1492 gIOPMSettingSleepServiceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey
);
1493 gIOPMSettingSilentRunningKey
= OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey
);
1494 gIOPMUserTriggeredFullWakeKey
= OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey
);
1495 gIOPMUserIsActiveKey
= OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey
);
1496 gIOPMSettingLowLatencyAudioModeKey
= OSSymbol::withCStringNoCopy(kIOPMSettingLowLatencyAudioModeKey
);
1498 gIOPMStatsResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
1499 gIOPMStatsResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
1500 gIOPMStatsResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
1501 gIOPMStatsResponsePrompt
= OSSymbol::withCString(kIOPMStatsResponsePrompt
);
1502 gIOPMStatsDriverPSChangeSlow
= OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow
);
1504 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
1505 sleepMessagePEFunction
= OSSymbol::withCString("IOPMSystemSleepMessage");
1506 gIOPMWakeTypeUserKey
= OSSymbol::withCStringNoCopy(kIOPMRootDomainWakeTypeUser
);
1508 OSSharedPtr
<const OSSymbol
> settingsArr
[kRootDomainSettingsCount
] =
1510 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
1511 gIOPMSettingAutoWakeSecondsKey
,
1512 gIOPMSettingAutoPowerSecondsKey
,
1513 gIOPMSettingAutoWakeCalendarKey
,
1514 gIOPMSettingAutoPowerCalendarKey
,
1515 gIOPMSettingDebugWakeRelativeKey
,
1516 gIOPMSettingDebugPowerRelativeKey
,
1517 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
1518 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
1519 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
1520 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
1521 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
1522 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
1523 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
1524 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
1525 OSSymbol::withCString(kIOPMStateConsoleShutdown
),
1526 OSSymbol::withCString(kIOPMSettingProModeControl
),
1527 OSSymbol::withCString(kIOPMSettingProModeDefer
),
1528 gIOPMSettingSilentRunningKey
,
1529 gIOPMSettingLowLatencyAudioModeKey
,
1532 OSSharedPtr
<const OSSymbol
> noPublishSettingsArr
[kRootDomainNoPublishSettingsCount
] =
1534 OSSymbol::withCString(kIOPMSettingProModeControl
),
1535 OSSymbol::withCString(kIOPMSettingProModeDefer
),
1536 gIOPMSettingSilentRunningKey
,
1537 gIOPMSettingLowLatencyAudioModeKey
,
1540 #if DEVELOPMENT || DEBUG
1541 #if defined(XNU_TARGET_OS_OSX)
1542 PE_parse_boot_argn("darkwake", &gDarkWakeFlags
, sizeof(gDarkWakeFlags
));
1543 PE_parse_boot_argn("clamshell", &gClamshellFlags
, sizeof(gClamshellFlags
));
1544 #endif /* defined(XNU_TARGET_OS_OSX) */
1545 #endif /* DEVELOPMENT || DEBUG */
1547 PE_parse_boot_argn("noidle", &gNoIdleFlag
, sizeof(gNoIdleFlag
));
1548 PE_parse_boot_argn("swd_sleeptimeout", &gSwdSleepTimeout
, sizeof(gSwdSleepTimeout
));
1549 PE_parse_boot_argn("swd_waketimeout", &gSwdWakeTimeout
, sizeof(gSwdWakeTimeout
));
1550 PE_parse_boot_argn("swd_timeout", &gSwdSleepWakeTimeout
, sizeof(gSwdSleepWakeTimeout
));
1551 PE_parse_boot_argn("haltmspanic", &gHaltTimeMaxPanic
, sizeof(gHaltTimeMaxPanic
));
1552 PE_parse_boot_argn("haltmslog", &gHaltTimeMaxLog
, sizeof(gHaltTimeMaxLog
));
1554 queue_init(&aggressivesQueue
);
1555 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
1556 aggressivesData
= OSData::withCapacity(
1557 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
1559 featuresDictLock
= IOLockAlloc();
1560 settingsCtrlLock
= IOLockAlloc();
1561 wakeEventLock
= IOLockAlloc();
1562 gHaltLogLock
= IOLockAlloc();
1563 setPMRootDomain(this);
1565 extraSleepTimer
= thread_call_allocate(
1566 idleSleepTimerExpired
,
1567 (thread_call_param_t
) this);
1569 powerButtonDown
= thread_call_allocate(
1570 powerButtonDownCallout
,
1571 (thread_call_param_t
) this);
1573 powerButtonUp
= thread_call_allocate(
1574 powerButtonUpCallout
,
1575 (thread_call_param_t
) this);
1577 diskSyncCalloutEntry
= thread_call_allocate(
1579 (thread_call_param_t
) this);
1580 updateConsoleUsersEntry
= thread_call_allocate(
1581 &updateConsoleUsersCallout
,
1582 (thread_call_param_t
) this);
1584 #if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
1585 fullWakeThreadCall
= thread_call_allocate_with_options(
1586 OSMemberFunctionCast(thread_call_func_t
, this,
1587 &IOPMrootDomain::fullWakeDelayedWork
),
1588 (thread_call_param_t
) this, THREAD_CALL_PRIORITY_KERNEL
,
1589 THREAD_CALL_OPTIONS_ONCE
);
1592 setProperty(kIOSleepSupportedKey
, true);
1594 bzero(&gPMStats
, sizeof(gPMStats
));
1596 pmTracer
= PMTraceWorker::tracer(this);
1598 pmAssertions
= PMAssertionsTracker::pmAssertionsTracker(this);
1600 userDisabledAllSleep
= false;
1601 systemBooting
= true;
1602 idleSleepEnabled
= false;
1604 idleSleepTimerPending
= false;
1606 clamshellClosed
= false;
1607 clamshellExists
= false;
1608 #if DISPLAY_WRANGLER_PRESENT
1609 clamshellDisabled
= true;
1611 clamshellDisabled
= false;
1613 clamshellIgnoreClose
= false;
1614 acAdaptorConnected
= true;
1615 clamshellSleepDisableMask
= 0;
1616 gWakeReasonString
[0] = '\0';
1618 // Initialize to user active.
1619 // Will never transition to user inactive w/o wrangler.
1620 fullWakeReason
= kFullWakeReasonLocalUser
;
1621 userIsActive
= userWasActive
= true;
1622 clock_get_uptime(&gUserActiveAbsTime
);
1623 setProperty(gIOPMUserIsActiveKey
.get(), kOSBooleanTrue
);
1625 // Set the default system capabilities at boot.
1626 _currentCapability
= kIOPMSystemCapabilityCPU
|
1627 kIOPMSystemCapabilityGraphics
|
1628 kIOPMSystemCapabilityAudio
|
1629 kIOPMSystemCapabilityNetwork
;
1631 _pendingCapability
= _currentCapability
;
1632 _desiredCapability
= _currentCapability
;
1633 _highestCapability
= _currentCapability
;
1634 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
1636 queuedSleepWakeUUIDString
= NULL
;
1637 initializeBootSessionUUID();
1638 pmStatsAppResponses
= OSArray::withCapacity(5);
1639 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
1640 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
1641 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
1642 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
1643 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
1644 _statsPowerCapsKey
= OSSymbol::withCString(kIOPMStatsPowerCapabilityKey
);
1645 assertOnWakeSecs
= -1;// Invalid value to prevent updates
1647 pmStatsLock
= IOLockAlloc();
1648 idxPMCPUClamshell
= kCPUUnknownIndex
;
1649 idxPMCPULimitedPower
= kCPUUnknownIndex
;
1651 tmpDict
= OSDictionary::withCapacity(1);
1652 setProperty(kRootDomainSupportedFeatures
, tmpDict
.get());
1654 // Set a default "SystemPowerProfileOverrideDict" for platform
1655 // drivers without any overrides.
1656 if (!propertyExists(kIOPMSystemDefaultOverrideKey
)) {
1657 tmpDict
= OSDictionary::withCapacity(1);
1658 setProperty(kIOPMSystemDefaultOverrideKey
, tmpDict
.get());
1661 settingsCallbacks
= OSDictionary::withCapacity(1);
1663 // Create a list of the valid PM settings that we'll relay to
1664 // interested clients in setProperties() => setPMSetting()
1665 allowedPMSettings
= OSArray::withObjects(
1666 (const OSObject
**)settingsArr
,
1667 kRootDomainSettingsCount
,
1670 // List of PM settings that should not automatically publish itself
1671 // as a feature when registered by a listener.
1672 noPublishPMSettings
= OSArray::withObjects(
1673 (const OSObject
**)noPublishSettingsArr
,
1674 kRootDomainNoPublishSettingsCount
,
1677 fPMSettingsDict
= OSDictionary::withCapacity(5);
1678 preventIdleSleepList
= OSSet::withCapacity(8);
1679 preventSystemSleepList
= OSSet::withCapacity(2);
1681 PMinit(); // creates gIOPMWorkLoop
1682 gIOPMWorkLoop
= getIOPMWorkloop();
1684 // Create IOPMPowerStateQueue used to queue external power
1685 // events, and to handle those events on the PM work loop.
1686 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
1687 this, OSMemberFunctionCast(IOEventSource::Action
, this,
1688 &IOPMrootDomain::dispatchPowerEvent
));
1689 gIOPMWorkLoop
->addEventSource(pmPowerStateQueue
);
1692 _aotTimerES
= IOTimerEventSource::timerEventSource(this,
1693 OSMemberFunctionCast(IOTimerEventSource::Action
,
1694 this, &IOPMrootDomain::aotEvaluate
));
1695 gIOPMWorkLoop
->addEventSource(_aotTimerES
.get());
1697 // create our power parent
1698 gPatriarch
= new IORootParent
;
1700 gPatriarch
->attach(this);
1701 gPatriarch
->start(this);
1702 gPatriarch
->addPowerChild(this);
1704 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
1705 changePowerStateWithTagToPriv(ON_STATE
, kCPSReasonInit
);
1707 // install power change handler
1708 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, NULL
);
1710 #if DISPLAY_WRANGLER_PRESENT
1711 wranglerIdleSettings
= OSDictionary::withCapacity(1);
1712 OSSharedPtr
<OSNumber
> wranglerIdlePeriod
= OSNumber::withNumber(kDefaultWranglerIdlePeriod
, 32);
1714 if (wranglerIdleSettings
&& wranglerIdlePeriod
) {
1715 wranglerIdleSettings
->setObject(kIORequestWranglerIdleKey
,
1716 wranglerIdlePeriod
.get());
1719 #endif /* DISPLAY_WRANGLER_PRESENT */
1721 lowLatencyAudioNotifierDict
= OSDictionary::withCapacity(2);
1722 lowLatencyAudioNotifyStateSym
= OSSymbol::withCString("LowLatencyAudioNotifyState");
1723 lowLatencyAudioNotifyTimestampSym
= OSSymbol::withCString("LowLatencyAudioNotifyTimestamp");
1724 lowLatencyAudioNotifyStateVal
= OSNumber::withNumber(0ull, 32);
1725 lowLatencyAudioNotifyTimestampVal
= OSNumber::withNumber(0ull, 64);
1727 if (lowLatencyAudioNotifierDict
&& lowLatencyAudioNotifyStateSym
&& lowLatencyAudioNotifyTimestampSym
&&
1728 lowLatencyAudioNotifyStateVal
&& lowLatencyAudioNotifyTimestampVal
) {
1729 lowLatencyAudioNotifierDict
->setObject(lowLatencyAudioNotifyStateSym
.get(), lowLatencyAudioNotifyStateVal
.get());
1730 lowLatencyAudioNotifierDict
->setObject(lowLatencyAudioNotifyTimestampSym
.get(), lowLatencyAudioNotifyTimestampVal
.get());
1733 OSSharedPtr
<const OSSymbol
> ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
1734 setProperty(gIOUserClientClassKey
, const_cast<OSObject
*>(static_cast<const OSObject
*>(ucClassName
.get())));
1736 // IOBacklightDisplay can take a long time to load at boot, or it may
1737 // not load at all if you're booting with clamshell closed. We publish
1738 // 'DisplayDims' here redundantly to get it published early and at all.
1739 OSSharedPtr
<OSDictionary
> matching
;
1740 matching
= serviceMatching("IOPMPowerSource");
1741 psIterator
= getMatchingServices(matching
.get());
1743 if (psIterator
&& psIterator
->getNextObject()) {
1744 // There's at least one battery on the system, so we publish
1745 // 'DisplayDims' support for the LCD.
1746 publishFeature("DisplayDims");
1749 // read swd_panic boot-arg
1750 PE_parse_boot_argn("swd_panic", &gSwdPanic
, sizeof(gSwdPanic
));
1751 sysctl_register_oid(&sysctl__kern_sleeptime
);
1752 sysctl_register_oid(&sysctl__kern_waketime
);
1753 sysctl_register_oid(&sysctl__kern_willshutdown
);
1754 sysctl_register_oid(&sysctl__kern_iokittest
);
1755 sysctl_register_oid(&sysctl__debug_iokit
);
1756 sysctl_register_oid(&sysctl__hw_targettype
);
1758 #if defined(XNU_TARGET_OS_OSX)
1759 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
1760 sysctl_register_oid(&sysctl__kern_progressmeter
);
1761 sysctl_register_oid(&sysctl__kern_wakereason
);
1762 #endif /* defined(XNU_TARGET_OS_OSX) */
1763 sysctl_register_oid(&sysctl__kern_consoleoptions
);
1764 sysctl_register_oid(&sysctl__kern_progressoptions
);
1766 sysctl_register_oid(&sysctl__kern_aotmode
);
1767 sysctl_register_oid(&sysctl__kern_aotmodebits
);
1768 sysctl_register_oid(&sysctl__kern_aotmetrics
);
1771 #if defined(__arm64__)
1772 #endif /* defined(__arm64__) */
1773 IOHibernateSystemInit(this);
1776 registerService(); // let clients find us
1781 //******************************************************************************
1784 // Receive a setProperty call
1785 // The "System Boot" property means the system is completely booted.
1786 //******************************************************************************
1789 IOPMrootDomain::setProperties( OSObject
* props_obj
)
1791 IOReturn return_value
= kIOReturnSuccess
;
1792 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
1793 OSBoolean
*b
= NULL
;
1795 const OSSymbol
*key
= NULL
;
1796 OSObject
*obj
= NULL
;
1797 OSSharedPtr
<OSCollectionIterator
> iter
;
1800 return kIOReturnBadArgument
;
1803 bool clientEntitled
= false;
1805 OSSharedPtr
<OSObject
> obj
= IOUserClient::copyClientEntitlement(current_task(), kRootDomainEntitlementSetProperty
);
1806 clientEntitled
= (obj
== kOSBooleanTrue
);
1809 if (!clientEntitled
) {
1810 const char * errorSuffix
= NULL
;
1812 // IOPMSchedulePowerEvent() clients may not be entitled, but must be root.
1813 // That API can set 6 possible keys that are checked below.
1814 if ((dict
->getCount() == 1) &&
1815 (dict
->getObject(gIOPMSettingAutoWakeSecondsKey
.get()) ||
1816 dict
->getObject(gIOPMSettingAutoPowerSecondsKey
.get()) ||
1817 dict
->getObject(gIOPMSettingAutoWakeCalendarKey
.get()) ||
1818 dict
->getObject(gIOPMSettingAutoPowerCalendarKey
.get()) ||
1819 dict
->getObject(gIOPMSettingDebugWakeRelativeKey
.get()) ||
1820 dict
->getObject(gIOPMSettingDebugPowerRelativeKey
.get()))) {
1821 return_value
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
1822 if (return_value
!= kIOReturnSuccess
) {
1823 errorSuffix
= "privileged";
1826 return_value
= kIOReturnNotPermitted
;
1827 errorSuffix
= "entitled";
1830 if (return_value
!= kIOReturnSuccess
) {
1831 OSSharedPtr
<OSString
> procName(IOCopyLogNameForPID(proc_selfpid()), OSNoRetain
);
1832 DLOG("%s failed, process %s is not %s\n", __func__
,
1833 procName
? procName
->getCStringNoCopy() : "", errorSuffix
);
1834 return return_value
;
1838 OSSharedPtr
<const OSSymbol
> publish_simulated_battery_string
= OSSymbol::withCString("SoftwareSimulatedBatteries");
1839 OSSharedPtr
<const OSSymbol
> boot_complete_string
= OSSymbol::withCString("System Boot Complete");
1840 OSSharedPtr
<const OSSymbol
> sys_shutdown_string
= OSSymbol::withCString("System Shutdown");
1841 OSSharedPtr
<const OSSymbol
> stall_halt_string
= OSSymbol::withCString("StallSystemAtHalt");
1842 OSSharedPtr
<const OSSymbol
> battery_warning_disabled_string
= OSSymbol::withCString("BatteryWarningsDisabled");
1843 OSSharedPtr
<const OSSymbol
> idle_seconds_string
= OSSymbol::withCString("System Idle Seconds");
1844 OSSharedPtr
<const OSSymbol
> sleepdisabled_string
= OSSymbol::withCString("SleepDisabled");
1845 OSSharedPtr
<const OSSymbol
> ondeck_sleepwake_uuid_string
= OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
1846 OSSharedPtr
<const OSSymbol
> loginwindow_progress_string
= OSSymbol::withCString(kIOPMLoginWindowProgressKey
);
1847 OSSharedPtr
<const OSSymbol
> coredisplay_progress_string
= OSSymbol::withCString(kIOPMCoreDisplayProgressKey
);
1848 OSSharedPtr
<const OSSymbol
> coregraphics_progress_string
= OSSymbol::withCString(kIOPMCoreGraphicsProgressKey
);
1849 #if DEBUG || DEVELOPMENT
1850 OSSharedPtr
<const OSSymbol
> clamshell_close_string
= OSSymbol::withCString("IOPMTestClamshellClose");
1851 OSSharedPtr
<const OSSymbol
> clamshell_open_string
= OSSymbol::withCString("IOPMTestClamshellOpen");
1852 OSSharedPtr
<const OSSymbol
> ac_detach_string
= OSSymbol::withCString("IOPMTestACDetach");
1853 OSSharedPtr
<const OSSymbol
> ac_attach_string
= OSSymbol::withCString("IOPMTestACAttach");
1854 OSSharedPtr
<const OSSymbol
> desktopmode_set_string
= OSSymbol::withCString("IOPMTestDesktopModeSet");
1855 OSSharedPtr
<const OSSymbol
> desktopmode_remove_string
= OSSymbol::withCString("IOPMTestDesktopModeRemove");
1859 OSSharedPtr
<const OSSymbol
> hibernatemode_string
= OSSymbol::withCString(kIOHibernateModeKey
);
1860 OSSharedPtr
<const OSSymbol
> hibernatefile_string
= OSSymbol::withCString(kIOHibernateFileKey
);
1861 OSSharedPtr
<const OSSymbol
> hibernatefilemin_string
= OSSymbol::withCString(kIOHibernateFileMinSizeKey
);
1862 OSSharedPtr
<const OSSymbol
> hibernatefilemax_string
= OSSymbol::withCString(kIOHibernateFileMaxSizeKey
);
1863 OSSharedPtr
<const OSSymbol
> hibernatefreeratio_string
= OSSymbol::withCString(kIOHibernateFreeRatioKey
);
1864 OSSharedPtr
<const OSSymbol
> hibernatefreetime_string
= OSSymbol::withCString(kIOHibernateFreeTimeKey
);
1867 iter
= OSCollectionIterator::withCollection(dict
);
1869 return_value
= kIOReturnNoMemory
;
1873 while ((key
= (const OSSymbol
*) iter
->getNextObject()) &&
1874 (obj
= dict
->getObject(key
))) {
1875 if (key
->isEqualTo(publish_simulated_battery_string
.get())) {
1876 if (OSDynamicCast(OSBoolean
, obj
)) {
1877 publishResource(key
, kOSBooleanTrue
);
1879 } else if (key
->isEqualTo(idle_seconds_string
.get())) {
1880 if ((n
= OSDynamicCast(OSNumber
, obj
))) {
1881 setProperty(key
, n
);
1882 idleSeconds
= n
->unsigned32BitValue();
1884 } else if (key
->isEqualTo(boot_complete_string
.get())) {
1885 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemBootCompleted
);
1886 } else if (key
->isEqualTo(sys_shutdown_string
.get())) {
1887 if ((b
= OSDynamicCast(OSBoolean
, obj
))) {
1888 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
1890 } else if (key
->isEqualTo(battery_warning_disabled_string
.get())) {
1891 setProperty(key
, obj
);
1894 else if (key
->isEqualTo(hibernatemode_string
.get()) ||
1895 key
->isEqualTo(hibernatefilemin_string
.get()) ||
1896 key
->isEqualTo(hibernatefilemax_string
.get()) ||
1897 key
->isEqualTo(hibernatefreeratio_string
.get()) ||
1898 key
->isEqualTo(hibernatefreetime_string
.get())) {
1899 if ((n
= OSDynamicCast(OSNumber
, obj
))) {
1900 setProperty(key
, n
);
1902 } else if (key
->isEqualTo(hibernatefile_string
.get())) {
1903 OSString
* str
= OSDynamicCast(OSString
, obj
);
1905 setProperty(key
, str
);
1909 else if (key
->isEqualTo(sleepdisabled_string
.get())) {
1910 if ((b
= OSDynamicCast(OSBoolean
, obj
))) {
1911 setProperty(key
, b
);
1912 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
1914 } else if (key
->isEqualTo(ondeck_sleepwake_uuid_string
.get())) {
1916 pmPowerStateQueue
->submitPowerEvent(kPowerEventQueueSleepWakeUUID
, (void *)obj
);
1917 } else if (key
->isEqualTo(loginwindow_progress_string
.get())) {
1918 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1919 uint32_t data
= n
->unsigned32BitValue();
1920 pmTracer
->traceComponentWakeProgress(kIOPMLoginWindowProgress
, data
);
1921 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMLoginWindowProgress
, data
);
1923 } else if (key
->isEqualTo(coredisplay_progress_string
.get())) {
1924 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1925 uint32_t data
= n
->unsigned32BitValue();
1926 pmTracer
->traceComponentWakeProgress(kIOPMCoreDisplayProgress
, data
);
1927 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMCoreDisplayProgress
, data
);
1929 } else if (key
->isEqualTo(coregraphics_progress_string
.get())) {
1930 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1931 uint32_t data
= n
->unsigned32BitValue();
1932 pmTracer
->traceComponentWakeProgress(kIOPMCoreGraphicsProgress
, data
);
1933 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMCoreGraphicsProgress
, data
);
1935 } else if (key
->isEqualTo(kIOPMDeepSleepEnabledKey
) ||
1936 key
->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey
) ||
1937 key
->isEqualTo(kIOPMAutoPowerOffEnabledKey
) ||
1938 key
->isEqualTo(stall_halt_string
.get())) {
1939 if ((b
= OSDynamicCast(OSBoolean
, obj
))) {
1940 setProperty(key
, b
);
1942 } else if (key
->isEqualTo(kIOPMDeepSleepDelayKey
) ||
1943 key
->isEqualTo(kIOPMDeepSleepTimerKey
) ||
1944 key
->isEqualTo(kIOPMAutoPowerOffDelayKey
) ||
1945 key
->isEqualTo(kIOPMAutoPowerOffTimerKey
)) {
1946 if ((n
= OSDynamicCast(OSNumber
, obj
))) {
1947 setProperty(key
, n
);
1949 } else if (key
->isEqualTo(kIOPMUserWakeAlarmScheduledKey
)) {
1950 if (kOSBooleanTrue
== obj
) {
1951 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_userScheduledAlarmMask
);
1953 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_userScheduledAlarmMask
);
1955 DLOG("_userScheduledAlarmMask 0x%x\n", (uint32_t) _userScheduledAlarmMask
);
1957 #if DEBUG || DEVELOPMENT
1958 else if (key
->isEqualTo(clamshell_close_string
.get())) {
1959 DLOG("SetProperties: setting clamshell close\n");
1960 UInt32 msg
= kIOPMClamshellClosed
;
1961 pmPowerStateQueue
->submitPowerEvent(kPowerEventReceivedPowerNotification
, (void *)(uintptr_t)msg
);
1962 } else if (key
->isEqualTo(clamshell_open_string
.get())) {
1963 DLOG("SetProperties: setting clamshell open\n");
1964 UInt32 msg
= kIOPMClamshellOpened
;
1965 pmPowerStateQueue
->submitPowerEvent(kPowerEventReceivedPowerNotification
, (void *)(uintptr_t)msg
);
1966 } else if (key
->isEqualTo(ac_detach_string
.get())) {
1967 DLOG("SetProperties: setting ac detach\n");
1968 UInt32 msg
= kIOPMSetACAdaptorConnected
;
1969 pmPowerStateQueue
->submitPowerEvent(kPowerEventReceivedPowerNotification
, (void *)(uintptr_t)msg
);
1970 } else if (key
->isEqualTo(ac_attach_string
.get())) {
1971 DLOG("SetProperties: setting ac attach\n");
1972 UInt32 msg
= kIOPMSetACAdaptorConnected
| kIOPMSetValue
;
1973 pmPowerStateQueue
->submitPowerEvent(kPowerEventReceivedPowerNotification
, (void *)(uintptr_t)msg
);
1974 } else if (key
->isEqualTo(desktopmode_set_string
.get())) {
1975 DLOG("SetProperties: setting desktopmode");
1976 UInt32 msg
= kIOPMSetDesktopMode
| kIOPMSetValue
;
1977 pmPowerStateQueue
->submitPowerEvent(kPowerEventReceivedPowerNotification
, (void *)(uintptr_t)msg
);
1978 } else if (key
->isEqualTo(desktopmode_remove_string
.get())) {
1979 DLOG("SetProperties: removing desktopmode\n");
1980 UInt32 msg
= kIOPMSetDesktopMode
;
1981 pmPowerStateQueue
->submitPowerEvent(kPowerEventReceivedPowerNotification
, (void *)(uintptr_t)msg
);
1984 // Relay our allowed PM settings onto our registered PM clients
1985 else if ((allowedPMSettings
->getNextIndexOfObject(key
, 0) != (unsigned int) -1)) {
1986 return_value
= setPMSetting(key
, obj
);
1987 if (kIOReturnSuccess
!= return_value
) {
1991 DLOG("setProperties(%s) not handled\n", key
->getCStringNoCopy());
1996 return return_value
;
2000 // MARK: Aggressiveness
2002 //******************************************************************************
2003 // setAggressiveness
2005 // Override IOService::setAggressiveness()
2006 //******************************************************************************
2009 IOPMrootDomain::setAggressiveness(
2011 unsigned long value
)
2013 return setAggressiveness( type
, value
, 0 );
2017 * Private setAggressiveness() with an internal options argument.
2020 IOPMrootDomain::setAggressiveness(
2022 unsigned long value
,
2023 IOOptionBits options
)
2025 AggressivesRequest
* entry
;
2026 AggressivesRequest
* request
;
2029 if ((type
> UINT_MAX
) || (value
> UINT_MAX
)) {
2030 return kIOReturnBadArgument
;
2033 if (type
== kPMMinutesToDim
|| type
== kPMMinutesToSleep
) {
2034 DLOG("setAggressiveness(%x) %s = %u\n",
2035 (uint32_t) options
, getAggressivenessTypeString((uint32_t) type
), (uint32_t) value
);
2037 DEBUG_LOG("setAggressiveness(%x) %s = %u\n",
2038 (uint32_t) options
, getAggressivenessTypeString((uint32_t) type
), (uint32_t) value
);
2041 request
= IONew(AggressivesRequest
, 1);
2043 return kIOReturnNoMemory
;
2046 memset(request
, 0, sizeof(*request
));
2047 request
->options
= options
;
2048 request
->dataType
= kAggressivesRequestTypeRecord
;
2049 request
->data
.record
.type
= (uint32_t) type
;
2050 request
->data
.record
.value
= (uint32_t) value
;
2054 // Update disk quick spindown flag used by getAggressiveness().
2055 // Never merge requests with quick spindown flags set.
2057 if (options
& kAggressivesOptionQuickSpindownEnable
) {
2058 gAggressivesState
|= kAggressivesStateQuickSpindown
;
2059 } else if (options
& kAggressivesOptionQuickSpindownDisable
) {
2060 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
2062 // Coalesce requests with identical aggressives types.
2063 // Deal with callers that calls us too "aggressively".
2065 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
2067 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
2068 (entry
->data
.record
.type
== type
) &&
2069 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0)) {
2070 entry
->data
.record
.value
= (uint32_t) value
;
2078 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
2081 AGGRESSIVES_UNLOCK();
2084 IODelete(request
, AggressivesRequest
, 1);
2087 if (options
& kAggressivesOptionSynchronous
) {
2088 handleAggressivesRequests(); // not truly synchronous
2090 thread_call_enter(aggressivesThreadCall
);
2093 return kIOReturnSuccess
;
2096 //******************************************************************************
2097 // getAggressiveness
2099 // Override IOService::setAggressiveness()
2100 // Fetch the aggressiveness factor with the given type.
2101 //******************************************************************************
2104 IOPMrootDomain::getAggressiveness(
2106 unsigned long * outLevel
)
2111 if (!outLevel
|| (type
> UINT_MAX
)) {
2112 return kIOReturnBadArgument
;
2117 // Disk quick spindown in effect, report value = 1
2119 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
2120 (type
== kPMMinutesToSpinDown
)) {
2121 value
= kAggressivesMinValue
;
2125 // Consult the pending request queue.
2128 AggressivesRequest
* entry
;
2130 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
2132 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
2133 (entry
->data
.record
.type
== type
) &&
2134 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0)) {
2135 value
= entry
->data
.record
.value
;
2142 // Consult the backend records.
2144 if (!source
&& aggressivesData
) {
2145 AggressivesRecord
* record
;
2148 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
2149 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
2151 for (i
= 0; i
< count
; i
++, record
++) {
2152 if (record
->type
== type
) {
2153 value
= record
->value
;
2160 AGGRESSIVES_UNLOCK();
2163 *outLevel
= (unsigned long) value
;
2164 return kIOReturnSuccess
;
2166 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
2167 *outLevel
= 0; // default return = 0, driver may not check for error
2168 return kIOReturnInvalid
;
2172 //******************************************************************************
2173 // joinAggressiveness
2175 // Request from IOService to join future aggressiveness broadcasts.
2176 //******************************************************************************
2179 IOPMrootDomain::joinAggressiveness(
2180 IOService
* service
)
2182 AggressivesRequest
* request
;
2184 if (!service
|| (service
== this)) {
2185 return kIOReturnBadArgument
;
2188 DEBUG_LOG("joinAggressiveness %s %p\n", service
->getName(), OBFUSCATE(service
));
2190 request
= IONew(AggressivesRequest
, 1);
2192 return kIOReturnNoMemory
;
2195 memset(request
, 0, sizeof(*request
));
2196 request
->dataType
= kAggressivesRequestTypeService
;
2197 request
->data
.service
.reset(service
, OSRetain
); // released by synchronizeAggressives()
2200 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
2201 AGGRESSIVES_UNLOCK();
2203 thread_call_enter(aggressivesThreadCall
);
2205 return kIOReturnSuccess
;
2208 //******************************************************************************
2209 // handleAggressivesRequests
2211 // Backend thread processes all incoming aggressiveness requests in the queue.
2212 //******************************************************************************
2215 handleAggressivesFunction(
2216 thread_call_param_t param1
,
2217 thread_call_param_t param2
)
2220 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
2225 IOPMrootDomain::handleAggressivesRequests( void )
2227 AggressivesRecord
* start
;
2228 AggressivesRecord
* record
;
2229 AggressivesRequest
* request
;
2230 queue_head_t joinedQueue
;
2234 bool pingSelf
= false;
2238 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
2239 queue_empty(&aggressivesQueue
)) {
2243 gAggressivesState
|= kAggressivesStateBusy
;
2244 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
2245 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
2249 queue_init(&joinedQueue
);
2252 // Remove request from the incoming queue in FIFO order.
2253 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
2254 switch (request
->dataType
) {
2255 case kAggressivesRequestTypeRecord
:
2256 // Update existing record if found.
2258 for (i
= 0, record
= start
; i
< count
; i
++, record
++) {
2259 if (record
->type
== request
->data
.record
.type
) {
2262 if (request
->options
& kAggressivesOptionQuickSpindownEnable
) {
2263 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0) {
2265 record
->flags
|= (kAggressivesRecordFlagMinValue
|
2266 kAggressivesRecordFlagModified
);
2267 DLOG("disk spindown accelerated, was %u min\n",
2270 } else if (request
->options
& kAggressivesOptionQuickSpindownDisable
) {
2271 if (record
->flags
& kAggressivesRecordFlagMinValue
) {
2273 record
->flags
|= kAggressivesRecordFlagModified
;
2274 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
2275 DLOG("disk spindown restored to %u min\n",
2278 } else if (record
->value
!= request
->data
.record
.value
) {
2279 record
->value
= request
->data
.record
.value
;
2280 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0) {
2282 record
->flags
|= kAggressivesRecordFlagModified
;
2289 // No matching record, append a new record.
2291 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0)) {
2292 AggressivesRecord newRecord
;
2294 newRecord
.flags
= kAggressivesRecordFlagModified
;
2295 newRecord
.type
= request
->data
.record
.type
;
2296 newRecord
.value
= request
->data
.record
.value
;
2297 if (request
->options
& kAggressivesOptionQuickSpindownEnable
) {
2298 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
2299 DLOG("disk spindown accelerated\n");
2302 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
2304 // OSData may have switched to another (larger) buffer.
2305 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
2306 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
2310 // Finished processing the request, release it.
2311 IODelete(request
, AggressivesRequest
, 1);
2314 case kAggressivesRequestTypeService
:
2315 // synchronizeAggressives() will free request.
2316 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
2320 panic("bad aggressives request type %x\n", request
->dataType
);
2323 } while (!queue_empty(&aggressivesQueue
));
2325 // Release the lock to perform work, with busy flag set.
2326 if (!queue_empty(&joinedQueue
) || broadcast
) {
2327 AGGRESSIVES_UNLOCK();
2328 if (!queue_empty(&joinedQueue
)) {
2329 synchronizeAggressives(&joinedQueue
, start
, count
);
2332 broadcastAggressives(start
, count
);
2337 // Remove the modified flag from all records.
2338 for (i
= 0, record
= start
; i
< count
; i
++, record
++) {
2339 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
2340 ((record
->type
== kPMMinutesToDim
) ||
2341 (record
->type
== kPMMinutesToSleep
))) {
2345 record
->flags
&= ~kAggressivesRecordFlagModified
;
2348 // Check the incoming queue again since new entries may have been
2349 // added while lock was released above.
2350 } while (!queue_empty(&aggressivesQueue
));
2352 gAggressivesState
&= ~kAggressivesStateBusy
;
2355 AGGRESSIVES_UNLOCK();
2357 // Root domain is interested in system and display sleep slider changes.
2358 // Submit a power event to handle those changes on the PM work loop.
2360 if (pingSelf
&& pmPowerStateQueue
) {
2361 pmPowerStateQueue
->submitPowerEvent(
2362 kPowerEventPolicyStimulus
,
2363 (void *) kStimulusAggressivenessChanged
);
2367 //******************************************************************************
2368 // synchronizeAggressives
2370 // Push all known aggressiveness records to one or more IOService.
2371 //******************************************************************************
2374 IOPMrootDomain::synchronizeAggressives(
2375 queue_head_t
* joinedQueue
,
2376 const AggressivesRecord
* array
,
2379 OSSharedPtr
<IOService
> service
;
2380 AggressivesRequest
* request
;
2381 const AggressivesRecord
* record
;
2382 IOPMDriverCallEntry callEntry
;
2386 while (!queue_empty(joinedQueue
)) {
2387 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
2388 if (request
->dataType
== kAggressivesRequestTypeService
) {
2389 // retained by joinAggressiveness(), so take ownership
2390 service
= os::move(request
->data
.service
);
2395 IODelete(request
, AggressivesRequest
, 1);
2399 if (service
->assertPMDriverCall(&callEntry
, kIOPMDriverCallMethodSetAggressive
)) {
2400 for (i
= 0, record
= array
; i
< count
; i
++, record
++) {
2401 value
= record
->value
;
2402 if (record
->flags
& kAggressivesRecordFlagMinValue
) {
2403 value
= kAggressivesMinValue
;
2406 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
2407 record
->type
, value
, service
->getName());
2408 service
->setAggressiveness(record
->type
, value
);
2410 service
->deassertPMDriverCall(&callEntry
);
2416 //******************************************************************************
2417 // broadcastAggressives
2419 // Traverse PM tree and call setAggressiveness() for records that have changed.
2420 //******************************************************************************
2423 IOPMrootDomain::broadcastAggressives(
2424 const AggressivesRecord
* array
,
2427 OSSharedPtr
<IORegistryIterator
> iter
;
2428 IORegistryEntry
*entry
;
2429 OSSharedPtr
<IORegistryEntry
> child
;
2430 IOPowerConnection
*connect
;
2432 const AggressivesRecord
*record
;
2433 IOPMDriverCallEntry callEntry
;
2437 iter
= IORegistryIterator::iterateOver(
2438 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
2441 // !! reset the iterator
2443 while ((entry
= iter
->getNextObject())) {
2444 connect
= OSDynamicCast(IOPowerConnection
, entry
);
2445 if (!connect
|| !connect
->getReadyFlag()) {
2449 child
= connect
->copyChildEntry(gIOPowerPlane
);
2451 if ((service
= OSDynamicCast(IOService
, child
.get()))) {
2452 if (service
->assertPMDriverCall(&callEntry
, kIOPMDriverCallMethodSetAggressive
)) {
2453 for (i
= 0, record
= array
; i
< count
; i
++, record
++) {
2454 if (record
->flags
& kAggressivesRecordFlagModified
) {
2455 value
= record
->value
;
2456 if (record
->flags
& kAggressivesRecordFlagMinValue
) {
2457 value
= kAggressivesMinValue
;
2459 _LOG("broadcastAggressives %x = %u to %s\n",
2460 record
->type
, value
, service
->getName());
2461 service
->setAggressiveness(record
->type
, value
);
2464 service
->deassertPMDriverCall(&callEntry
);
2469 }while (!entry
&& !iter
->isValid());
2473 //*****************************************
2474 // stackshot on power button press
2475 // ***************************************
2477 powerButtonDownCallout(thread_call_param_t us
, thread_call_param_t
)
2479 /* Power button pressed during wake
2482 DEBUG_LOG("Powerbutton: down. Taking stackshot\n");
2483 ((IOPMrootDomain
*)us
)->takeStackshot(false);
2487 powerButtonUpCallout(thread_call_param_t us
, thread_call_param_t
)
2489 /* Power button released.
2490 * Delete any stackshot data
2492 DEBUG_LOG("PowerButton: up callout. Delete stackshot\n");
2493 ((IOPMrootDomain
*)us
)->deleteStackshot();
2495 //*************************************************************************
2499 // MARK: System Sleep
2501 //******************************************************************************
2502 // startIdleSleepTimer
2504 //******************************************************************************
2507 IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
2509 AbsoluteTime deadline
;
2513 DLOG("idle timer not set (noidle=%d)\n", gNoIdleFlag
);
2517 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
2518 thread_call_enter_delayed(extraSleepTimer
, deadline
);
2519 idleSleepTimerPending
= true;
2521 thread_call_enter(extraSleepTimer
);
2523 DLOG("idle timer set for %u seconds\n", inSeconds
);
2526 //******************************************************************************
2527 // cancelIdleSleepTimer
2529 //******************************************************************************
2532 IOPMrootDomain::cancelIdleSleepTimer( void )
2535 if (idleSleepTimerPending
) {
2536 DLOG("idle timer cancelled\n");
2537 thread_call_cancel(extraSleepTimer
);
2538 idleSleepTimerPending
= false;
2540 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
2542 clock_usec_t microsecs
;
2543 clock_get_uptime(&now
);
2544 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
2545 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
2546 if (assertOnWakeReport
) {
2547 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
2548 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
2554 //******************************************************************************
2555 // idleSleepTimerExpired
2557 //******************************************************************************
2560 idleSleepTimerExpired(
2561 thread_call_param_t us
, thread_call_param_t
)
2563 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
2566 //******************************************************************************
2567 // handleSleepTimerExpiration
2569 // The time between the sleep idle timeout and the next longest one has elapsed.
2570 // It's time to sleep. Start that by removing the clamp that's holding us awake.
2571 //******************************************************************************
2574 IOPMrootDomain::handleSleepTimerExpiration( void )
2576 if (!gIOPMWorkLoop
->inGate()) {
2577 gIOPMWorkLoop
->runAction(
2578 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2579 &IOPMrootDomain::handleSleepTimerExpiration
),
2584 DLOG("sleep timer expired\n");
2587 idleSleepTimerPending
= false;
2588 setQuickSpinDownTimeout();
2589 adjustPowerState(true);
2592 //******************************************************************************
2593 // getTimeToIdleSleep
2595 // Returns number of seconds left before going into idle sleep.
2596 // Caller has to make sure that idle sleep is allowed at the time of calling
2598 //******************************************************************************
2601 IOPMrootDomain::getTimeToIdleSleep( void )
2603 AbsoluteTime now
, lastActivityTime
;
2605 uint32_t minutesSinceUserInactive
= 0;
2606 uint32_t sleepDelay
= 0;
2608 if (!idleSleepEnabled
) {
2612 if (userActivityTime
) {
2613 lastActivityTime
= userActivityTime
;
2615 lastActivityTime
= userBecameInactiveTime
;
2618 // Ignore any lastActivityTime that predates the last system wake.
2619 // The goal is to avoid a sudden idle sleep right after a dark wake
2620 // due to sleepDelay=0 computed below. The alternative 60s minimum
2621 // timeout should be large enough to allow dark wake to complete,
2622 // at which point the idle timer will be promptly cancelled.
2623 clock_get_uptime(&now
);
2624 if ((CMP_ABSOLUTETIME(&lastActivityTime
, &gIOLastWakeAbsTime
) >= 0) &&
2625 (CMP_ABSOLUTETIME(&now
, &lastActivityTime
) > 0)) {
2626 SUB_ABSOLUTETIME(&now
, &lastActivityTime
);
2627 absolutetime_to_nanoseconds(now
, &nanos
);
2628 minutesSinceUserInactive
= nanos
/ (60000000000ULL);
2630 if (minutesSinceUserInactive
>= sleepSlider
) {
2633 sleepDelay
= sleepSlider
- minutesSinceUserInactive
;
2636 DLOG("ignoring lastActivityTime 0x%qx, now 0x%qx, wake 0x%qx\n",
2637 lastActivityTime
, now
, gIOLastWakeAbsTime
);
2638 sleepDelay
= sleepSlider
;
2641 DLOG("user inactive %u min, time to idle sleep %u min\n",
2642 minutesSinceUserInactive
, sleepDelay
);
2644 return sleepDelay
* 60;
2647 //******************************************************************************
2648 // setQuickSpinDownTimeout
2650 //******************************************************************************
2653 IOPMrootDomain::setQuickSpinDownTimeout( void )
2657 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
2660 //******************************************************************************
2661 // restoreUserSpinDownTimeout
2663 //******************************************************************************
2666 IOPMrootDomain::restoreUserSpinDownTimeout( void )
2670 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
2673 //******************************************************************************
2676 //******************************************************************************
2680 IOPMrootDomain::sleepSystem( void )
2682 return sleepSystemOptions(NULL
);
2687 IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
2689 OSObject
*obj
= NULL
;
2690 OSString
*reason
= NULL
;
2691 /* sleepSystem is a public function, and may be called by any kernel driver.
2692 * And that's bad - drivers should sleep the system by calling
2693 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2695 * Note that user space app calls to IOPMSleepSystem() will also travel
2696 * this code path and thus be correctly identified as software sleeps.
2699 if (options
&& options
->getObject("OSSwitch")) {
2700 // Log specific sleep cause for OS Switch hibernation
2701 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate
);
2704 if (options
&& (obj
= options
->getObject("Sleep Reason"))) {
2705 reason
= OSDynamicCast(OSString
, obj
);
2706 if (reason
&& reason
->isEqualTo(kIOPMDarkWakeThermalEmergencyKey
)) {
2707 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
2709 if (reason
&& reason
->isEqualTo(kIOPMNotificationWakeExitKey
)) {
2710 return privateSleepSystem(kIOPMSleepReasonNotificationWakeExit
);
2714 return privateSleepSystem( kIOPMSleepReasonSoftware
);
2719 IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
2721 /* Called from both gated and non-gated context */
2723 if (!checkSystemSleepEnabled() || !pmPowerStateQueue
) {
2724 return kIOReturnNotPermitted
;
2727 pmPowerStateQueue
->submitPowerEvent(
2728 kPowerEventPolicyStimulus
,
2729 (void *) kStimulusDemandSystemSleep
,
2732 return kIOReturnSuccess
;
2735 //******************************************************************************
2738 // This overrides powerChangeDone in IOService.
2739 //******************************************************************************
2741 IOPMrootDomain::powerChangeDone( unsigned long previousPowerState
)
2743 #if !__i386__ && !__x86_64__
2744 uint64_t timeSinceReset
= 0;
2747 unsigned long newState
;
2749 clock_usec_t microsecs
;
2750 uint32_t lastDebugWakeSeconds
;
2751 clock_sec_t adjWakeTime
;
2752 IOPMCalendarStruct nowCalendar
;
2755 newState
= getPowerState();
2756 DLOG("PowerChangeDone: %s->%s\n",
2757 getPowerStateString((uint32_t) previousPowerState
), getPowerStateString((uint32_t) getPowerState()));
2759 if (previousPowerState
== newState
) {
2763 notifierThread
= current_thread();
2764 switch (getPowerState()) {
2766 if (kPMCalendarTypeInvalid
!= _aotWakeTimeCalendar
.selector
) {
2769 PEGetUTCTimeOfDay(&secs
, µsecs
);
2772 if ((kIOPMAOTModeRespectTimers
& _aotMode
) && (_calendarWakeAlarmUTC
< _aotWakeTimeUTC
)) {
2773 IOLog("use _calendarWakeAlarmUTC\n");
2774 adjWakeTime
= _calendarWakeAlarmUTC
;
2775 } else if (_aotExit
|| (kIOPMWakeEventAOTExitFlags
& _aotPendingFlags
)) {
2776 IOLog("accelerate _aotWakeTime for exit\n");
2778 } else if (kIOPMDriverAssertionLevelOn
== getPMAssertionLevel(kIOPMDriverAssertionCPUBit
)) {
2779 IOLog("accelerate _aotWakeTime for assertion\n");
2783 IOPMConvertSecondsToCalendar(adjWakeTime
, &_aotWakeTimeCalendar
);
2786 IOPMConvertSecondsToCalendar(secs
, &nowCalendar
);
2787 IOLog("aotSleep at " YMDTF
" sched: " YMDTF
"\n", YMDT(&nowCalendar
), YMDT(&_aotWakeTimeCalendar
));
2789 IOReturn __unused ret
= setMaintenanceWakeCalendar(&_aotWakeTimeCalendar
);
2790 assert(kIOReturnSuccess
== ret
);
2792 if (_aotLastWakeTime
) {
2793 _aotMetrics
->totalTime
+= mach_absolute_time() - _aotLastWakeTime
;
2794 if (_aotMetrics
->sleepCount
&& (_aotMetrics
->sleepCount
<= kIOPMAOTMetricsKernelWakeCountMax
)) {
2795 strlcpy(&_aotMetrics
->kernelWakeReason
[_aotMetrics
->sleepCount
- 1][0],
2797 sizeof(_aotMetrics
->kernelWakeReason
[_aotMetrics
->sleepCount
]));
2800 _aotPendingFlags
&= ~kIOPMWakeEventAOTPerCycleFlags
;
2801 if (_aotTimerScheduled
) {
2802 _aotTimerES
->cancelTimeout();
2803 _aotTimerScheduled
= false;
2805 acceptSystemWakeEvents(kAcceptSystemWakeEvents_Enable
);
2807 // re-enable this timer for next sleep
2808 cancelIdleSleepTimer();
2810 if (clamshellExists
) {
2811 #if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
2812 if (gClamshellFlags
& kClamshell_WAR_58009435
) {
2813 // Disable clamshell sleep until system has completed full wake.
2814 // This prevents a system sleep request (due to a clamshell close)
2815 // from being queued until the end of system full wake - even if
2816 // other clamshell disable bits outside of our control is wrong.
2817 setClamShellSleepDisable(true, kClamshellSleepDisableInternal
);
2821 // Log the last known clamshell state before system sleep
2822 DLOG("clamshell closed %d, disabled %d/%x, desktopMode %d, ac %d\n",
2823 clamshellClosed
, clamshellDisabled
, clamshellSleepDisableMask
,
2824 desktopMode
, acAdaptorConnected
);
2827 clock_get_calendar_absolute_and_microtime(&secs
, µsecs
, &now
);
2829 gIOLastSleepTime
.tv_sec
= secs
;
2830 gIOLastSleepTime
.tv_usec
= microsecs
;
2831 if (!_aotLastWakeTime
) {
2832 gIOLastUserSleepTime
= gIOLastSleepTime
;
2835 gIOLastWakeTime
.tv_sec
= 0;
2836 gIOLastWakeTime
.tv_usec
= 0;
2837 gIOLastSleepAbsTime
= now
;
2839 if (wake2DarkwakeDelay
&& sleepDelaysReport
) {
2840 clock_sec_t wake2DarkwakeSecs
, darkwake2SleepSecs
;
2841 // Update 'wake2DarkwakeDelay' histogram if this is a fullwake->sleep transition
2843 SUB_ABSOLUTETIME(&now
, &ts_sleepStart
);
2844 absolutetime_to_microtime(now
, &darkwake2SleepSecs
, µsecs
);
2845 absolutetime_to_microtime(wake2DarkwakeDelay
, &wake2DarkwakeSecs
, µsecs
);
2846 HISTREPORT_TALLYVALUE(sleepDelaysReport
,
2847 (int64_t)(wake2DarkwakeSecs
+ darkwake2SleepSecs
));
2849 DLOG("Updated sleepDelaysReport %lu %lu\n", (unsigned long)wake2DarkwakeSecs
, (unsigned long)darkwake2SleepSecs
);
2850 wake2DarkwakeDelay
= 0;
2853 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
2855 IOHibernateSystemHasSlept();
2857 evaluateSystemSleepPolicyFinal();
2859 LOG("System Sleep\n");
2861 if (thermalWarningState
) {
2862 OSSharedPtr
<const OSSymbol
> event
= OSSymbol::withCString(kIOPMThermalLevelWarningKey
);
2864 systemPowerEventOccurred(event
.get(), kIOPMThermalLevelUnknown
);
2867 assertOnWakeSecs
= 0;
2868 lowBatteryCondition
= false;
2869 thermalEmergencyState
= false;
2871 #if DEVELOPMENT || DEBUG
2872 extern int g_should_log_clock_adjustments
;
2873 if (g_should_log_clock_adjustments
) {
2874 clock_sec_t secs
= 0;
2875 clock_usec_t microsecs
= 0;
2876 uint64_t now_b
= mach_absolute_time();
2880 PEGetUTCTimeOfDay(&secs
, µsecs
);
2882 uint64_t now_a
= mach_absolute_time();
2883 os_log(OS_LOG_DEFAULT
, "%s PMU before going to sleep %lu s %d u %llu abs_b_PEG %llu abs_a_PEG \n",
2884 __func__
, (unsigned long)secs
, microsecs
, now_b
, now_a
);
2888 getPlatform()->sleepKernel();
2890 // The CPU(s) are off at this point,
2891 // Code will resume execution here upon wake.
2893 clock_get_uptime(&gIOLastWakeAbsTime
);
2894 IOLog("gIOLastWakeAbsTime: %lld\n", gIOLastWakeAbsTime
);
2895 _highestCapability
= 0;
2898 IOHibernateSystemWake();
2901 // sleep transition complete
2902 gSleepOrShutdownPending
= 0;
2904 // trip the reset of the calendar clock
2905 clock_wakeup_calendar();
2906 clock_get_calendar_microtime(&secs
, µsecs
);
2907 gIOLastWakeTime
.tv_sec
= secs
;
2908 gIOLastWakeTime
.tv_usec
= microsecs
;
2911 if (_aotWakeTimeCalendar
.selector
!= kPMCalendarTypeInvalid
) {
2912 _aotWakeTimeCalendar
.selector
= kPMCalendarTypeInvalid
;
2915 PEGetUTCTimeOfDay(&secs
, µsecs
);
2916 IOPMConvertSecondsToCalendar(secs
, &nowCalendar
);
2917 IOLog("aotWake at " YMDTF
" sched: " YMDTF
"\n", YMDT(&nowCalendar
), YMDT(&_aotWakeTimeCalendar
));
2918 _aotMetrics
->sleepCount
++;
2919 _aotLastWakeTime
= gIOLastWakeAbsTime
;
2920 if (_aotMetrics
->sleepCount
<= kIOPMAOTMetricsKernelWakeCountMax
) {
2921 _aotMetrics
->kernelSleepTime
[_aotMetrics
->sleepCount
- 1]
2922 = (((uint64_t) gIOLastSleepTime
.tv_sec
) << 10) + (gIOLastSleepTime
.tv_usec
/ 1000);
2923 _aotMetrics
->kernelWakeTime
[_aotMetrics
->sleepCount
- 1]
2924 = (((uint64_t) gIOLastWakeTime
.tv_sec
) << 10) + (gIOLastWakeTime
.tv_usec
/ 1000);
2928 if (_aotWakeTimeUTC
<= secs
) {
2929 _aotTestTime
= _aotTestTime
+ _aotTestInterval
;
2931 setWakeTime(_aotTestTime
);
2936 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
2939 lastSleepReason
= 0;
2941 lastDebugWakeSeconds
= _debugWakeSeconds
;
2942 _debugWakeSeconds
= 0;
2943 _scheduledAlarmMask
= 0;
2944 _nextScheduledAlarmType
= NULL
;
2946 darkWakeExit
= false;
2947 darkWakePowerClamped
= false;
2948 darkWakePostTickle
= false;
2949 darkWakeHibernateError
= false;
2950 darkWakeToSleepASAP
= true;
2951 darkWakeLogClamp
= true;
2952 sleepTimerMaintenance
= false;
2953 sleepToStandby
= false;
2954 wranglerTickled
= false;
2955 userWasActive
= false;
2956 isRTCAlarmWake
= false;
2957 clamshellIgnoreClose
= false;
2958 fullWakeReason
= kFullWakeReasonNone
;
2960 #if defined(__i386__) || defined(__x86_64__)
2961 kdebugTrace(kPMLogSystemWake
, 0, 0, 0);
2963 OSSharedPtr
<OSObject
> wakeTypeProp
= copyProperty(kIOPMRootDomainWakeTypeKey
);
2964 OSSharedPtr
<OSObject
> wakeReasonProp
= copyProperty(kIOPMRootDomainWakeReasonKey
);
2965 OSString
* wakeType
= OSDynamicCast(OSString
, wakeTypeProp
.get());
2966 OSString
* wakeReason
= OSDynamicCast(OSString
, wakeReasonProp
.get());
2968 if (wakeReason
&& (wakeReason
->getLength() >= 2) &&
2969 gWakeReasonString
[0] == '\0') {
2971 // Until the platform driver can claim its wake reasons
2972 strlcat(gWakeReasonString
, wakeReason
->getCStringNoCopy(),
2973 sizeof(gWakeReasonString
));
2977 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
)) {
2978 lowBatteryCondition
= true;
2979 darkWakeMaintenance
= true;
2982 OSSharedPtr
<OSObject
> hibOptionsProp
= copyProperty(kIOHibernateOptionsKey
);
2983 OSNumber
* hibOptions
= OSDynamicCast( OSNumber
, hibOptionsProp
.get());
2984 if (hibernateAborted
|| ((hibOptions
&&
2985 !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
)))) {
2986 // Hibernate aborted, or EFI brought up graphics
2987 darkWakeExit
= true;
2988 if (hibernateAborted
) {
2989 DLOG("Hibernation aborted\n");
2991 DLOG("EFI brought up graphics. Going to full wake. HibOptions: 0x%x\n", hibOptions
->unsigned32BitValue());
2996 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeUser
) ||
2997 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
))) {
2998 // User wake or RTC alarm
2999 darkWakeExit
= true;
3000 if (wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
)) {
3001 isRTCAlarmWake
= true;
3003 } else if (wakeType
&&
3004 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
)) {
3005 // SMC standby timer trumps SleepX
3006 darkWakeMaintenance
= true;
3007 sleepTimerMaintenance
= true;
3008 } else if ((lastDebugWakeSeconds
!= 0) &&
3009 ((gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
) == 0)) {
3010 // SleepX before maintenance
3011 darkWakeExit
= true;
3012 } else if (wakeType
&&
3013 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
)) {
3014 darkWakeMaintenance
= true;
3015 } else if (wakeType
&&
3016 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepService
)) {
3017 darkWakeMaintenance
= true;
3018 darkWakeSleepService
= true;
3020 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) {
3021 sleepToStandby
= true;
3024 } else if (wakeType
&&
3025 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeHibernateError
)) {
3026 darkWakeMaintenance
= true;
3027 darkWakeHibernateError
= true;
3029 // Unidentified wake source, resume to full wake if debug
3030 // alarm is pending.
3032 if (lastDebugWakeSeconds
&&
3033 (!wakeReason
|| wakeReason
->isEqualTo(""))) {
3034 darkWakeExit
= true;
3040 darkWakeToSleepASAP
= false;
3041 fullWakeReason
= kFullWakeReasonLocalUser
;
3043 } else if (displayPowerOnRequested
&& checkSystemCanSustainFullWake()) {
3044 handleSetDisplayPowerOn(true);
3045 } else if (!darkWakeMaintenance
) {
3046 // Early/late tickle for non-maintenance wake.
3047 if ((gDarkWakeFlags
& kDarkWakeFlagPromotionMask
) != kDarkWakeFlagPromotionNone
) {
3048 darkWakePostTickle
= true;
3051 #else /* !__i386__ && !__x86_64__ */
3052 timeSinceReset
= ml_get_time_since_reset();
3053 kdebugTrace(kPMLogSystemWake
, 0, (uintptr_t)(timeSinceReset
>> 32), (uintptr_t) timeSinceReset
);
3055 if ((gDarkWakeFlags
& kDarkWakeFlagPromotionMask
) == kDarkWakeFlagPromotionEarly
) {
3056 wranglerTickled
= true;
3057 fullWakeReason
= kFullWakeReasonLocalUser
;
3058 requestUserActive(this, "Full wake on dark wake promotion boot-arg");
3059 } else if ((lastDebugWakeSeconds
!= 0) && !(gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
)) {
3060 isRTCAlarmWake
= true;
3061 fullWakeReason
= kFullWakeReasonLocalUser
;
3062 requestUserActive(this, "RTC debug alarm");
3065 // stay awake for at least 30 seconds
3066 startIdleSleepTimer(30);
3070 thread_call_enter(updateConsoleUsersEntry
);
3072 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonWake
);
3075 #if !__i386__ && !__x86_64__
3079 DLOG("Force re-evaluating aggressiveness\n");
3080 /* Force re-evaluate the aggressiveness values to set appropriate idle sleep timer */
3081 pmPowerStateQueue
->submitPowerEvent(
3082 kPowerEventPolicyStimulus
,
3083 (void *) kStimulusNoIdleSleepPreventers
);
3085 // After changing to ON_STATE, invalidate any previously queued
3086 // request to change to a state less than ON_STATE. This isn't
3087 // necessary for AOT_STATE or if the device has only one running
3088 // state since the changePowerStateToPriv() issued at the tail
3089 // end of SLEEP_STATE case should take care of that.
3090 if (getPowerState() == ON_STATE
) {
3091 changePowerStateWithTagToPriv(ON_STATE
, kCPSReasonWake
);
3095 #endif /* !__i386__ && !__x86_64__ */
3097 notifierThread
= NULL
;
3100 //******************************************************************************
3101 // requestPowerDomainState
3103 // Extend implementation in IOService. Running on PM work loop thread.
3104 //******************************************************************************
3107 IOPMrootDomain::requestPowerDomainState(
3108 IOPMPowerFlags childDesire
,
3109 IOPowerConnection
* childConnection
,
3110 unsigned long specification
)
3112 // Idle and system sleep prevention flags affects driver desire.
3113 // Children desire are irrelevant so they are cleared.
3115 return super::requestPowerDomainState(0, childConnection
, specification
);
3120 makeSleepPreventersListLog(const OSSharedPtr
<OSSet
> &preventers
, char *buf
, size_t buf_size
)
3122 if (!preventers
->getCount()) {
3126 char *buf_iter
= buf
+ strlen(buf
);
3127 char *buf_end
= buf
+ buf_size
;
3129 OSSharedPtr
<OSCollectionIterator
> iterator
= OSCollectionIterator::withCollection(preventers
.get());
3130 OSObject
*obj
= NULL
;
3132 while ((obj
= iterator
->getNextObject())) {
3133 IOService
*srv
= OSDynamicCast(IOService
, obj
);
3134 if (buf_iter
< buf_end
) {
3135 buf_iter
+= snprintf(buf_iter
, buf_end
- buf_iter
, " %s", srv
->getName());
3137 DLOG("Print buffer exhausted for sleep preventers list\n");
3143 //******************************************************************************
3144 // updatePreventIdleSleepList
3146 // Called by IOService on PM work loop.
3147 // Returns true if PM policy recognized the driver's desire to prevent idle
3148 // sleep and updated the list of idle sleep preventers. Returns false otherwise
3149 //******************************************************************************
3152 IOPMrootDomain::updatePreventIdleSleepList(
3153 IOService
* service
, bool addNotRemove
)
3155 unsigned int oldCount
;
3157 oldCount
= idleSleepPreventersCount();
3158 return updatePreventIdleSleepListInternal(service
, addNotRemove
, oldCount
);
3162 IOPMrootDomain::updatePreventIdleSleepListInternal(
3163 IOService
* service
, bool addNotRemove
, unsigned int oldCount
)
3165 unsigned int newCount
;
3169 #if defined(XNU_TARGET_OS_OSX)
3170 // Only the display wrangler and no-idle-sleep kernel assertions
3171 // can prevent idle sleep. The kIOPMPreventIdleSleep capability flag
3172 // reported by drivers in their power state table is ignored.
3173 if (service
&& (service
!= wrangler
) && (service
!= this)) {
3180 preventIdleSleepList
->setObject(service
);
3181 DLOG("Added %s to idle sleep preventers list (Total %u)\n",
3182 service
->getName(), preventIdleSleepList
->getCount());
3183 } else if (preventIdleSleepList
->member(service
)) {
3184 preventIdleSleepList
->removeObject(service
);
3185 DLOG("Removed %s from idle sleep preventers list (Total %u)\n",
3186 service
->getName(), preventIdleSleepList
->getCount());
3189 if (preventIdleSleepList
->getCount()) {
3190 char buf
[256] = "Idle Sleep Preventers:";
3191 makeSleepPreventersListLog(preventIdleSleepList
, buf
, sizeof(buf
));
3196 newCount
= idleSleepPreventersCount();
3198 if ((oldCount
== 0) && (newCount
!= 0)) {
3199 // Driver added to empty prevent list.
3200 // Update the driver desire to prevent idle sleep.
3201 // Driver desire does not prevent demand sleep.
3203 changePowerStateWithTagTo(getRUN_STATE(), kCPSReasonIdleSleepPrevent
);
3204 } else if ((oldCount
!= 0) && (newCount
== 0)) {
3205 // Last driver removed from prevent list.
3206 // Drop the driver clamp to allow idle sleep.
3208 changePowerStateWithTagTo(SLEEP_STATE
, kCPSReasonIdleSleepAllow
);
3209 evaluatePolicy( kStimulusNoIdleSleepPreventers
);
3211 messageClient(kIOPMMessageIdleSleepPreventers
, systemCapabilityNotifier
.get(),
3212 &newCount
, sizeof(newCount
));
3214 #if defined(XNU_TARGET_OS_OSX)
3215 if (addNotRemove
&& (service
== wrangler
) && !checkSystemCanSustainFullWake()) {
3216 DLOG("Cannot cancel idle sleep\n");
3217 return false; // do not idle-cancel
3224 //******************************************************************************
3226 //******************************************************************************
3229 IOPMrootDomain::startSpinDump(uint32_t spindumpKind
)
3231 messageClients(kIOPMMessageLaunchBootSpinDump
, (void *)(uintptr_t)spindumpKind
);
3234 //******************************************************************************
3235 // preventSystemSleepListUpdate
3237 // Called by IOService on PM work loop.
3238 //******************************************************************************
3241 IOPMrootDomain::updatePreventSystemSleepList(
3242 IOService
* service
, bool addNotRemove
)
3244 unsigned int oldCount
, newCount
;
3247 if (this == service
) {
3251 oldCount
= preventSystemSleepList
->getCount();
3253 preventSystemSleepList
->setObject(service
);
3254 DLOG("Added %s to system sleep preventers list (Total %u)\n",
3255 service
->getName(), preventSystemSleepList
->getCount());
3256 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
3258 clock_usec_t microsecs
;
3259 clock_get_uptime(&now
);
3260 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
3261 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
3262 if (assertOnWakeReport
) {
3263 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
3264 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
3267 } else if (preventSystemSleepList
->member(service
)) {
3268 preventSystemSleepList
->removeObject(service
);
3269 DLOG("Removed %s from system sleep preventers list (Total %u)\n",
3270 service
->getName(), preventSystemSleepList
->getCount());
3272 if ((oldCount
!= 0) && (preventSystemSleepList
->getCount() == 0)) {
3273 // Lost all system sleep preventers.
3274 // Send stimulus if system sleep was blocked, and is in dark wake.
3275 evaluatePolicy( kStimulusDarkWakeEvaluate
);
3279 newCount
= preventSystemSleepList
->getCount();
3281 char buf
[256] = "System Sleep Preventers:";
3282 makeSleepPreventersListLog(preventSystemSleepList
, buf
, sizeof(buf
));
3286 messageClient(kIOPMMessageSystemSleepPreventers
, systemCapabilityNotifier
.get(),
3287 &newCount
, sizeof(newCount
));
3291 IOPMrootDomain::copySleepPreventersList(OSArray
**idleSleepList
, OSArray
**systemSleepList
)
3293 OSSharedPtr
<OSCollectionIterator
> iterator
;
3294 OSObject
*object
= NULL
;
3295 OSSharedPtr
<OSArray
> array
;
3297 if (!gIOPMWorkLoop
->inGate()) {
3298 gIOPMWorkLoop
->runAction(
3299 OSMemberFunctionCast(IOWorkLoop::Action
, this,
3300 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersList
),
3301 this, (void *)idleSleepList
, (void *)systemSleepList
);
3305 if (idleSleepList
&& preventIdleSleepList
&& (preventIdleSleepList
->getCount() != 0)) {
3306 iterator
= OSCollectionIterator::withCollection(preventIdleSleepList
.get());
3307 array
= OSArray::withCapacity(5);
3309 if (iterator
&& array
) {
3310 while ((object
= iterator
->getNextObject())) {
3311 IOService
*service
= OSDynamicCast(IOService
, object
);
3313 OSSharedPtr
<const OSSymbol
> name
= service
->copyName();
3315 array
->setObject(name
.get());
3320 *idleSleepList
= array
.detach();
3323 if (systemSleepList
&& preventSystemSleepList
&& (preventSystemSleepList
->getCount() != 0)) {
3324 iterator
= OSCollectionIterator::withCollection(preventSystemSleepList
.get());
3325 array
= OSArray::withCapacity(5);
3327 if (iterator
&& array
) {
3328 while ((object
= iterator
->getNextObject())) {
3329 IOService
*service
= OSDynamicCast(IOService
, object
);
3331 OSSharedPtr
<const OSSymbol
> name
= service
->copyName();
3333 array
->setObject(name
.get());
3338 *systemSleepList
= array
.detach();
3343 IOPMrootDomain::copySleepPreventersListWithID(OSArray
**idleSleepList
, OSArray
**systemSleepList
)
3345 OSSharedPtr
<OSCollectionIterator
> iterator
;
3346 OSObject
*object
= NULL
;
3347 OSSharedPtr
<OSArray
> array
;
3349 if (!gIOPMWorkLoop
->inGate()) {
3350 gIOPMWorkLoop
->runAction(
3351 OSMemberFunctionCast(IOWorkLoop::Action
, this,
3352 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersListWithID
),
3353 this, (void *)idleSleepList
, (void *)systemSleepList
);
3357 if (idleSleepList
&& preventIdleSleepList
&& (preventIdleSleepList
->getCount() != 0)) {
3358 iterator
= OSCollectionIterator::withCollection(preventIdleSleepList
.get());
3359 array
= OSArray::withCapacity(5);
3361 if (iterator
&& array
) {
3362 while ((object
= iterator
->getNextObject())) {
3363 IOService
*service
= OSDynamicCast(IOService
, object
);
3365 OSSharedPtr
<OSDictionary
> dict
= OSDictionary::withCapacity(2);
3366 OSSharedPtr
<const OSSymbol
> name
= service
->copyName();
3367 OSSharedPtr
<OSNumber
> id
= OSNumber::withNumber(service
->getRegistryEntryID(), 64);
3368 if (dict
&& name
&& id
) {
3369 dict
->setObject(kIOPMDriverAssertionRegistryEntryIDKey
, id
.get());
3370 dict
->setObject(kIOPMDriverAssertionOwnerStringKey
, name
.get());
3371 array
->setObject(dict
.get());
3376 *idleSleepList
= array
.detach();
3379 if (systemSleepList
&& preventSystemSleepList
&& (preventSystemSleepList
->getCount() != 0)) {
3380 iterator
= OSCollectionIterator::withCollection(preventSystemSleepList
.get());
3381 array
= OSArray::withCapacity(5);
3383 if (iterator
&& array
) {
3384 while ((object
= iterator
->getNextObject())) {
3385 IOService
*service
= OSDynamicCast(IOService
, object
);
3387 OSSharedPtr
<OSDictionary
> dict
= OSDictionary::withCapacity(2);
3388 OSSharedPtr
<const OSSymbol
> name
= service
->copyName();
3389 OSSharedPtr
<OSNumber
> id
= OSNumber::withNumber(service
->getRegistryEntryID(), 64);
3390 if (dict
&& name
&& id
) {
3391 dict
->setObject(kIOPMDriverAssertionRegistryEntryIDKey
, id
.get());
3392 dict
->setObject(kIOPMDriverAssertionOwnerStringKey
, name
.get());
3393 array
->setObject(dict
.get());
3398 *systemSleepList
= array
.detach();
3402 //******************************************************************************
3405 // Override the superclass implementation to send a different message type.
3406 //******************************************************************************
3409 IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
3411 DLOG("tellChangeDown %s->%s\n",
3412 getPowerStateString((uint32_t) getPowerState()), getPowerStateString((uint32_t) stateNum
));
3414 if (SLEEP_STATE
== stateNum
) {
3415 // Legacy apps were already told in the full->dark transition
3416 if (!ignoreTellChangeDown
) {
3417 tracePoint( kIOPMTracePointSleepApplications
);
3419 tracePoint( kIOPMTracePointSleepPriorityClients
);
3423 if (!ignoreTellChangeDown
) {
3424 userActivityAtSleep
= userActivityCount
;
3425 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
3427 if (SLEEP_STATE
== stateNum
) {
3428 hibernateAborted
= false;
3430 // Direct callout into OSKext so it can disable kext unloads
3431 // during sleep/wake to prevent deadlocks.
3432 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
3434 IOService::updateConsoleUsers(NULL
, kIOMessageSystemWillSleep
);
3436 // Two change downs are sent by IOServicePM. Ignore the 2nd.
3437 // But tellClientsWithResponse() must be called for both.
3438 ignoreTellChangeDown
= true;
3442 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
3445 //******************************************************************************
3448 // Override the superclass implementation to send a different message type.
3449 // This must be idle sleep since we don't ask during any other power change.
3450 //******************************************************************************
3453 IOPMrootDomain::askChangeDown( unsigned long stateNum
)
3455 DLOG("askChangeDown %s->%s\n",
3456 getPowerStateString((uint32_t) getPowerState()), getPowerStateString((uint32_t) stateNum
));
3458 // Don't log for dark wake entry
3459 if (kSystemTransitionSleep
== _systemTransitionType
) {
3460 tracePoint( kIOPMTracePointSleepApplications
);
3463 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
3466 //******************************************************************************
3467 // askChangeDownDone
3469 // An opportunity for root domain to cancel the power transition,
3470 // possibily due to an assertion created by powerd in response to
3471 // kIOMessageCanSystemSleep.
3474 // full -> dark wake transition
3475 // 1. Notify apps and powerd with kIOMessageCanSystemSleep
3476 // 2. askChangeDownDone()
3477 // dark -> sleep transition
3478 // 1. Notify powerd with kIOMessageCanSystemSleep
3479 // 2. askChangeDownDone()
3482 // full -> dark wake transition
3483 // 1. Notify powerd with kIOMessageCanSystemSleep
3484 // 2. askChangeDownDone()
3485 // dark -> sleep transition
3486 // 1. Notify powerd with kIOMessageCanSystemSleep
3487 // 2. askChangeDownDone()
3488 //******************************************************************************
3491 IOPMrootDomain::askChangeDownDone(
3492 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
3494 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
3495 *inOutChangeFlags
, *cancel
,
3496 _systemTransitionType
,
3497 _currentCapability
, _pendingCapability
);
3499 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
)) {
3500 // Dark->Sleep transition.
3501 // Check if there are any deny sleep assertions.
3502 // lastSleepReason already set by handleOurPowerChangeStart()
3504 if (!checkSystemCanSleep(lastSleepReason
)) {
3505 // Cancel dark wake to sleep transition.
3506 // Must re-scan assertions upon entering dark wake.
3509 DLOG("cancel dark->sleep\n");
3511 if (_aotMode
&& (kPMCalendarTypeInvalid
!= _aotWakeTimeCalendar
.selector
)) {
3512 uint64_t now
= mach_continuous_time();
3513 if (((now
+ _aotWakePreWindow
) >= _aotWakeTimeContinuous
)
3514 && (now
< (_aotWakeTimeContinuous
+ _aotWakePostWindow
))) {
3516 IOLog("AOT wake window cancel: %qd, %qd\n", now
, _aotWakeTimeContinuous
);
3522 //******************************************************************************
3523 // systemDidNotSleep
3525 // Work common to both canceled or aborted sleep.
3526 //******************************************************************************
3529 IOPMrootDomain::systemDidNotSleep( void )
3531 // reset console lock state
3532 thread_call_enter(updateConsoleUsersEntry
);
3534 if (idleSleepEnabled
) {
3536 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
3537 startIdleSleepTimer(kIdleSleepRetryInterval
);
3539 startIdleSleepTimer(idleSeconds
);
3541 } else if (!userIsActive
) {
3542 // Manually start the idle sleep timer besides waiting for
3543 // the user to become inactive.
3544 startIdleSleepTimer(kIdleSleepRetryInterval
);
3548 preventTransitionToUserActive(false);
3549 IOService::setAdvisoryTickleEnable( true );
3551 // After idle revert and cancel, send a did-change message to powerd
3552 // to balance the previous will-change message. Kernel clients do not
3553 // need this since sleep cannot be canceled once they are notified.
3555 if (toldPowerdCapWillChange
&& systemCapabilityNotifier
&&
3556 (_pendingCapability
!= _currentCapability
) &&
3557 ((_systemMessageClientMask
& kSystemMessageClientPowerd
) != 0)) {
3558 // Differs from a real capability gain change where notifyRef != 0,
3559 // but it is zero here since no response is expected.
3561 IOPMSystemCapabilityChangeParameters params
;
3563 bzero(¶ms
, sizeof(params
));
3564 params
.fromCapabilities
= _pendingCapability
;
3565 params
.toCapabilities
= _currentCapability
;
3566 params
.changeFlags
= kIOPMSystemCapabilityDidChange
;
3568 DLOG("MESG cap %x->%x did change\n",
3569 params
.fromCapabilities
, params
.toCapabilities
);
3570 messageClient(kIOMessageSystemCapabilityChange
, systemCapabilityNotifier
.get(),
3571 ¶ms
, sizeof(params
));
3575 //******************************************************************************
3578 // Notify registered applications and kernel clients that we are not dropping
3581 // We override the superclass implementation so we can send a different message
3582 // type to the client or application being notified.
3584 // This must be a vetoed idle sleep, since no other power change can be vetoed.
3585 //******************************************************************************
3588 IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
3590 DLOG("tellNoChangeDown %s->%s\n",
3591 getPowerStateString((uint32_t) getPowerState()), getPowerStateString((uint32_t) stateNum
));
3593 // Sleep canceled, clear the sleep trace point.
3594 tracePoint(kIOPMTracePointSystemUp
);
3596 systemDidNotSleep();
3597 return tellClients( kIOMessageSystemWillNotSleep
);
3600 //******************************************************************************
3603 // Notify registered applications and kernel clients that we are raising power.
3605 // We override the superclass implementation so we can send a different message
3606 // type to the client or application being notified.
3607 //******************************************************************************
3610 IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
3612 DLOG("tellChangeUp %s->%s\n",
3613 getPowerStateString((uint32_t) getPowerState()), getPowerStateString((uint32_t) stateNum
));
3615 ignoreTellChangeDown
= false;
3617 if (stateNum
== ON_STATE
) {
3618 // Direct callout into OSKext so it can disable kext unloads
3619 // during sleep/wake to prevent deadlocks.
3620 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
3622 // Notify platform that sleep was cancelled or resumed.
3623 getPlatform()->callPlatformFunction(
3624 sleepMessagePEFunction
.get(), false,
3625 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
3628 if (getPowerState() == ON_STATE
) {
3629 // Sleep was cancelled by idle cancel or revert
3630 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
)) {
3631 // rdar://problem/50363791
3632 // If system is in dark wake and sleep is cancelled, do not
3633 // send SystemWillPowerOn/HasPoweredOn messages to kernel
3634 // priority clients. They haven't yet seen a SystemWillSleep
3635 // message before the cancellation. So make sure the kernel
3636 // client bit is cleared in _systemMessageClientMask before
3637 // invoking the tellClients() below. This bit may have been
3638 // set by handleOurPowerChangeStart() anticipating a successful
3639 // sleep and setting the filter mask ahead of time allows the
3640 // SystemWillSleep message to go through.
3641 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
3644 systemDidNotSleep();
3645 tellClients( kIOMessageSystemWillPowerOn
);
3648 tracePoint( kIOPMTracePointWakeApplications
);
3649 tellClients( kIOMessageSystemHasPoweredOn
);
3653 #define CAP_WILL_CHANGE_TO_OFF(params, flag) \
3654 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
3655 ((params)->fromCapabilities & (flag)) && \
3656 (((params)->toCapabilities & (flag)) == 0))
3658 #define CAP_DID_CHANGE_TO_ON(params, flag) \
3659 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
3660 ((params)->toCapabilities & (flag)) && \
3661 (((params)->fromCapabilities & (flag)) == 0))
3663 #define CAP_DID_CHANGE_TO_OFF(params, flag) \
3664 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
3665 ((params)->fromCapabilities & (flag)) && \
3666 (((params)->toCapabilities & (flag)) == 0))
3668 #define CAP_WILL_CHANGE_TO_ON(params, flag) \
3669 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
3670 ((params)->toCapabilities & (flag)) && \
3671 (((params)->fromCapabilities & (flag)) == 0))
3673 //******************************************************************************
3674 // sysPowerDownHandler
3676 // Perform a vfs sync before system sleep.
3677 //******************************************************************************
3680 IOPMrootDomain::sysPowerDownHandler(
3681 void * target
, void * refCon
,
3682 UInt32 messageType
, IOService
* service
,
3683 void * messageArgs
, vm_size_t argSize
)
3685 static UInt32 lastSystemMessageType
= 0;
3688 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
3690 // rdar://problem/50363791
3691 // Sanity check to make sure the SystemWill/Has message types are
3692 // received in the expected order for all kernel priority clients.
3693 if (messageType
== kIOMessageSystemWillSleep
||
3694 messageType
== kIOMessageSystemWillPowerOn
||
3695 messageType
== kIOMessageSystemHasPoweredOn
) {
3696 switch (messageType
) {
3697 case kIOMessageSystemWillPowerOn
:
3698 assert(lastSystemMessageType
== kIOMessageSystemWillSleep
);
3700 case kIOMessageSystemHasPoweredOn
:
3701 assert(lastSystemMessageType
== kIOMessageSystemWillPowerOn
);
3705 lastSystemMessageType
= messageType
;
3709 return kIOReturnUnsupported
;
3712 if (messageType
== kIOMessageSystemCapabilityChange
) {
3713 IOPMSystemCapabilityChangeParameters
* params
=
3714 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
3716 // Interested applications have been notified of an impending power
3717 // change and have acked (when applicable).
3718 // This is our chance to save whatever state we can before powering
3720 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
3723 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
3724 params
->fromCapabilities
, params
->toCapabilities
,
3725 params
->changeFlags
);
3727 if (CAP_WILL_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityCPU
)) {
3728 // We will ack within 20 seconds
3729 params
->maxWaitForReply
= 20 * 1000 * 1000;
3732 gRootDomain
->evaluateSystemSleepPolicyEarly();
3734 // add in time we could spend freeing pages
3735 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
) {
3736 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
3738 DLOG("sysPowerDownHandler max wait %d s\n",
3739 (int) (params
->maxWaitForReply
/ 1000 / 1000));
3742 // Notify platform that sleep has begun, after the early
3743 // sleep policy evaluation.
3744 getPlatform()->callPlatformFunction(
3745 sleepMessagePEFunction
.get(), false,
3746 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
3749 if (!OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
)) {
3750 // Purposely delay the ack and hope that shutdown occurs quickly.
3751 // Another option is not to schedule the thread and wait for
3753 AbsoluteTime deadline
;
3754 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
3755 thread_call_enter1_delayed(
3756 gRootDomain
->diskSyncCalloutEntry
,
3757 (thread_call_param_t
)(uintptr_t) params
->notifyRef
,
3761 gRootDomain
->diskSyncCalloutEntry
,
3762 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3766 else if (CAP_DID_CHANGE_TO_ON(params
, kIOPMSystemCapabilityCPU
)) {
3767 // We will ack within 110 seconds
3768 params
->maxWaitForReply
= 110 * 1000 * 1000;
3771 gRootDomain
->diskSyncCalloutEntry
,
3772 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3775 ret
= kIOReturnSuccess
;
3781 //******************************************************************************
3782 // handleQueueSleepWakeUUID
3784 // Called from IOPMrootDomain when we're initiating a sleep,
3785 // or indirectly from PM configd when PM decides to clear the UUID.
3786 // PM clears the UUID several minutes after successful wake from sleep,
3787 // so that we might associate App spindumps with the immediately previous
3790 // @param obj has a retain on it. We're responsible for releasing that retain.
3791 //******************************************************************************
3794 IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
3796 OSSharedPtr
<OSString
> str
;
3798 if (kOSBooleanFalse
== obj
) {
3799 handlePublishSleepWakeUUID(false);
3801 str
.reset(OSDynamicCast(OSString
, obj
), OSNoRetain
);
3803 // This branch caches the UUID for an upcoming sleep/wake
3804 queuedSleepWakeUUIDString
= str
;
3805 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
3809 //******************************************************************************
3810 // handlePublishSleepWakeUUID
3812 // Called from IOPMrootDomain when we're initiating a sleep,
3813 // or indirectly from PM configd when PM decides to clear the UUID.
3814 // PM clears the UUID several minutes after successful wake from sleep,
3815 // so that we might associate App spindumps with the immediately previous
3817 //******************************************************************************
3820 IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
3825 * Clear the current UUID
3827 if (gSleepWakeUUIDIsSet
) {
3828 DLOG("SleepWake UUID cleared\n");
3830 gSleepWakeUUIDIsSet
= false;
3832 removeProperty(kIOPMSleepWakeUUIDKey
);
3833 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
3837 * Optionally, publish a new UUID
3839 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
3840 OSSharedPtr
<OSString
> publishThisUUID
;
3842 publishThisUUID
= queuedSleepWakeUUIDString
;
3844 if (publishThisUUID
) {
3845 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
.get());
3848 gSleepWakeUUIDIsSet
= true;
3849 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
3851 queuedSleepWakeUUIDString
.reset();
3855 //******************************************************************************
3856 // IOPMGetSleepWakeUUIDKey
3858 // Return the truth value of gSleepWakeUUIDIsSet and optionally copy the key.
3859 // To get the full key -- a C string -- the buffer must large enough for
3860 // the end-of-string character.
3861 // The key is expected to be an UUID string
3862 //******************************************************************************
3865 IOPMCopySleepWakeUUIDKey(char *buffer
, size_t buf_len
)
3867 if (!gSleepWakeUUIDIsSet
) {
3871 if (buffer
!= NULL
) {
3872 OSSharedPtr
<OSString
> string
=
3873 OSDynamicPtrCast
<OSString
>(gRootDomain
->copyProperty(kIOPMSleepWakeUUIDKey
));
3878 strlcpy(buffer
, string
->getCStringNoCopy(), buf_len
);
3885 //******************************************************************************
3886 // lowLatencyAudioNotify
3888 // Used to send an update about low latency audio activity to interested
3889 // clients. To keep the overhead minimal the OSDictionary used here
3890 // is initialized at boot.
3891 //******************************************************************************
3894 IOPMrootDomain::lowLatencyAudioNotify(uint64_t time
, boolean_t state
)
3896 if (lowLatencyAudioNotifierDict
&& lowLatencyAudioNotifyStateSym
&& lowLatencyAudioNotifyTimestampSym
&&
3897 lowLatencyAudioNotifyStateVal
&& lowLatencyAudioNotifyTimestampVal
) {
3898 lowLatencyAudioNotifyTimestampVal
->setValue(time
);
3899 lowLatencyAudioNotifyStateVal
->setValue(state
);
3900 setPMSetting(gIOPMSettingLowLatencyAudioModeKey
.get(), lowLatencyAudioNotifierDict
.get());
3902 DLOG("LowLatencyAudioNotify error\n");
3907 //******************************************************************************
3908 // IOPMrootDomainRTNotifier
3910 // Used by performance controller to update the timestamp and state associated
3911 // with low latency audio activity in the system.
3912 //******************************************************************************
3915 IOPMrootDomainRTNotifier(uint64_t time
, boolean_t state
)
3917 gRootDomain
->lowLatencyAudioNotify(time
, state
);
3921 //******************************************************************************
3922 // initializeBootSessionUUID
3924 // Initialize the boot session uuid at boot up and sets it into registry.
3925 //******************************************************************************
3928 IOPMrootDomain::initializeBootSessionUUID(void)
3931 uuid_string_t new_uuid_string
;
3933 uuid_generate(new_uuid
);
3934 uuid_unparse_upper(new_uuid
, new_uuid_string
);
3935 memcpy(bootsessionuuid_string
, new_uuid_string
, sizeof(uuid_string_t
));
3937 setProperty(kIOPMBootSessionUUIDKey
, new_uuid_string
);
3940 //******************************************************************************
3941 // Root domain uses the private and tagged changePowerState methods for
3942 // tracking and logging purposes.
3943 //******************************************************************************
3945 #define REQUEST_TAG_TO_REASON(x) ((uint16_t)x)
3948 nextRequestTag( IOPMRequestTag tag
)
3950 static SInt16 msb16
= 1;
3951 uint16_t id
= OSAddAtomic16(1, &msb16
);
3952 return ((uint32_t)id
<< 16) | REQUEST_TAG_TO_REASON(tag
);
3955 // TODO: remove this shim function and exported symbol
3957 IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
3959 return changePowerStateWithTagTo(ordinal
, kCPSReasonNone
);
3962 // TODO: remove this shim function and exported symbol
3964 IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
3966 return changePowerStateWithTagToPriv(ordinal
, kCPSReasonNone
);
3970 IOPMrootDomain::changePowerStateWithOverrideTo(
3971 IOPMPowerStateIndex ordinal
, IOPMRequestTag reason
)
3973 uint32_t tag
= nextRequestTag(reason
);
3974 DLOG("%s(%s, %x)\n", __FUNCTION__
, getPowerStateString((uint32_t) ordinal
), tag
);
3976 if ((ordinal
!= ON_STATE
) && (ordinal
!= AOT_STATE
) && (ordinal
!= SLEEP_STATE
)) {
3977 return kIOReturnUnsupported
;
3980 return super::changePowerStateWithOverrideTo(ordinal
, tag
);
3984 IOPMrootDomain::changePowerStateWithTagTo(
3985 IOPMPowerStateIndex ordinal
, IOPMRequestTag reason
)
3987 uint32_t tag
= nextRequestTag(reason
);
3988 DLOG("%s(%s, %x)\n", __FUNCTION__
, getPowerStateString((uint32_t) ordinal
), tag
);
3990 if ((ordinal
!= ON_STATE
) && (ordinal
!= AOT_STATE
) && (ordinal
!= SLEEP_STATE
)) {
3991 return kIOReturnUnsupported
;
3994 return super::changePowerStateWithTagTo(ordinal
, tag
);
3998 IOPMrootDomain::changePowerStateWithTagToPriv(
3999 IOPMPowerStateIndex ordinal
, IOPMRequestTag reason
)
4001 uint32_t tag
= nextRequestTag(reason
);
4002 DLOG("%s(%s, %x)\n", __FUNCTION__
, getPowerStateString((uint32_t) ordinal
), tag
);
4004 if ((ordinal
!= ON_STATE
) && (ordinal
!= AOT_STATE
) && (ordinal
!= SLEEP_STATE
)) {
4005 return kIOReturnUnsupported
;
4008 return super::changePowerStateWithTagToPriv(ordinal
, tag
);
4011 //******************************************************************************
4014 //******************************************************************************
4017 IOPMrootDomain::activitySinceSleep(void)
4019 return userActivityCount
!= userActivityAtSleep
;
4023 IOPMrootDomain::abortHibernation(void)
4026 // don't allow hibernation to be aborted on ARM due to user activity
4027 // since once ApplePMGR decides we're hibernating, we can't turn back
4028 // see: <rdar://problem/63848862> Tonga ApplePMGR diff quiesce path support
4031 bool ret
= activitySinceSleep();
4033 if (ret
&& !hibernateAborted
&& checkSystemCanSustainFullWake()) {
4034 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
4035 hibernateAborted
= true;
4042 hibernate_should_abort(void)
4045 return gRootDomain
->abortHibernation();
4051 //******************************************************************************
4052 // willNotifyPowerChildren
4054 // Called after all interested drivers have all acknowledged the power change,
4055 // but before any power children is informed. Dispatched though a thread call,
4056 // so it is safe to perform work that might block on a sleeping disk. PM state
4057 // machine (not thread) will block w/o timeout until this function returns.
4058 //******************************************************************************
4061 IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState
)
4063 OSSharedPtr
<OSDictionary
> dict
;
4064 OSSharedPtr
<OSNumber
> secs
;
4066 if (SLEEP_STATE
== newPowerState
) {
4067 notifierThread
= current_thread();
4068 if (!tasksSuspended
) {
4069 AbsoluteTime deadline
;
4070 tasksSuspended
= TRUE
;
4071 updateTasksSuspend();
4073 clock_interval_to_deadline(10, kSecondScale
, &deadline
);
4074 #if defined(XNU_TARGET_OS_OSX)
4075 vm_pageout_wait(AbsoluteTime_to_scalar(&deadline
));
4076 #endif /* defined(XNU_TARGET_OS_OSX) */
4079 _aotReadyToFullWake
= false;
4081 if (_aotLingerTime
) {
4083 IOLog("aot linger no return\n");
4084 clock_absolutetime_interval_to_deadline(_aotLingerTime
, &deadline
);
4085 clock_delay_until(deadline
);
4090 _aotWakeTimeCalendar
.selector
= kPMCalendarTypeInvalid
;
4092 bzero(_aotMetrics
, sizeof(IOPMAOTMetrics
));
4094 } else if (!_aotNow
&& !_debugWakeSeconds
) {
4097 _aotPendingFlags
= 0;
4098 _aotTasksSuspended
= true;
4099 _aotLastWakeTime
= 0;
4100 bzero(_aotMetrics
, sizeof(IOPMAOTMetrics
));
4101 if (kIOPMAOTModeCycle
& _aotMode
) {
4102 clock_interval_to_absolutetime_interval(60, kSecondScale
, &_aotTestInterval
);
4103 _aotTestTime
= mach_continuous_time() + _aotTestInterval
;
4104 setWakeTime(_aotTestTime
);
4106 uint32_t lingerSecs
;
4107 if (!PE_parse_boot_argn("aotlinger", &lingerSecs
, sizeof(lingerSecs
))) {
4110 clock_interval_to_absolutetime_interval(lingerSecs
, kSecondScale
, &_aotLingerTime
);
4111 clock_interval_to_absolutetime_interval(2000, kMillisecondScale
, &_aotWakePreWindow
);
4112 clock_interval_to_absolutetime_interval(1100, kMillisecondScale
, &_aotWakePostWindow
);
4116 IOHibernateSystemSleep();
4117 IOHibernateIOKitSleep();
4119 if (gRootDomain
->activitySinceSleep()) {
4120 dict
= OSDictionary::withCapacity(1);
4121 secs
= OSNumber::withNumber(1, 32);
4124 dict
->setObject(gIOPMSettingDebugWakeRelativeKey
.get(), secs
.get());
4125 gRootDomain
->setProperties(dict
.get());
4126 MSG("Reverting sleep with relative wake\n");
4130 notifierThread
= NULL
;
4134 //******************************************************************************
4135 // willTellSystemCapabilityDidChange
4137 // IOServicePM calls this from OurChangeTellCapabilityDidChange() when root
4138 // domain is raising its power state, immediately after notifying interested
4139 // drivers and power children.
4140 //******************************************************************************
4143 IOPMrootDomain::willTellSystemCapabilityDidChange( void )
4145 if ((_systemTransitionType
== kSystemTransitionWake
) &&
4146 !CAP_GAIN(kIOPMSystemCapabilityGraphics
)) {
4147 // After powering up drivers, dark->full promotion on the current wake
4148 // transition is no longer possible. That is because the next machine
4149 // state will issue the system capability change messages.
4150 // The darkWakePowerClamped flag may already be set if the system has
4151 // at least one driver that was power clamped due to dark wake.
4152 // This function sets the darkWakePowerClamped flag in case there
4153 // is no power-clamped driver in the system.
4155 // Last opportunity to exit dark wake using:
4156 // requestFullWake( kFullWakeReasonLocalUser );
4158 if (!darkWakePowerClamped
) {
4159 if (darkWakeLogClamp
) {
4163 clock_get_uptime(&now
);
4164 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
4165 absolutetime_to_nanoseconds(now
, &nsec
);
4166 DLOG("dark wake promotion disabled at %u ms\n",
4167 ((int)((nsec
) / NSEC_PER_MSEC
)));
4169 darkWakePowerClamped
= true;
4174 //******************************************************************************
4175 // sleepOnClamshellClosed
4177 // contains the logic to determine if the system should sleep when the clamshell
4179 //******************************************************************************
4182 IOPMrootDomain::shouldSleepOnClamshellClosed( void )
4184 if (!clamshellExists
) {
4188 DLOG("clamshell closed %d, disabled %d/%x, desktopMode %d, ac %d\n",
4189 clamshellClosed
, clamshellDisabled
, clamshellSleepDisableMask
, desktopMode
, acAdaptorConnected
);
4191 return !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) && !clamshellSleepDisableMask
;
4195 IOPMrootDomain::shouldSleepOnRTCAlarmWake( void )
4197 // Called once every RTC/Alarm wake. Device should go to sleep if on clamshell
4198 // closed && battery
4199 if (!clamshellExists
) {
4203 DLOG("shouldSleepOnRTCAlarmWake: clamshell closed %d, disabled %d/%x, desktopMode %d, ac %d\n",
4204 clamshellClosed
, clamshellDisabled
, clamshellSleepDisableMask
, desktopMode
, acAdaptorConnected
);
4206 return !acAdaptorConnected
&& !clamshellSleepDisableMask
;
4210 IOPMrootDomain::sendClientClamshellNotification( void )
4212 /* Only broadcast clamshell alert if clamshell exists. */
4213 if (!clamshellExists
) {
4217 setProperty(kAppleClamshellStateKey
,
4218 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
4220 setProperty(kAppleClamshellCausesSleepKey
,
4221 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
4223 /* Argument to message is a bitfiel of
4224 * ( kClamshellStateBit | kClamshellSleepBit )
4226 messageClients(kIOPMMessageClamshellStateChange
,
4227 (void *)(uintptr_t) ((clamshellClosed
? kClamshellStateBit
: 0)
4228 | (shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)));
4231 //******************************************************************************
4232 // getSleepSupported
4235 //******************************************************************************
4238 IOPMrootDomain::getSleepSupported( void )
4240 return platformSleepSupport
;
4243 //******************************************************************************
4244 // setSleepSupported
4247 //******************************************************************************
4250 IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
4252 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
4253 OSBitOrAtomic(flags
, &platformSleepSupport
);
4256 //******************************************************************************
4257 // setClamShellSleepDisable
4259 //******************************************************************************
4262 IOPMrootDomain::setClamShellSleepDisable( bool disable
, uint32_t bitmask
)
4266 // User client calls this in non-gated context
4267 if (gIOPMWorkLoop
->inGate() == false) {
4268 gIOPMWorkLoop
->runAction(
4269 OSMemberFunctionCast(IOWorkLoop::Action
, this,
4270 &IOPMrootDomain::setClamShellSleepDisable
),
4272 (void *) disable
, (void *)(uintptr_t) bitmask
);
4276 oldMask
= clamshellSleepDisableMask
;
4278 clamshellSleepDisableMask
|= bitmask
;
4280 clamshellSleepDisableMask
&= ~bitmask
;
4282 DLOG("setClamShellSleepDisable(%x->%x)\n", oldMask
, clamshellSleepDisableMask
);
4284 if (clamshellExists
&& clamshellClosed
&&
4285 (clamshellSleepDisableMask
!= oldMask
) &&
4286 (clamshellSleepDisableMask
== 0)) {
4287 handlePowerNotification(kLocalEvalClamshellCommand
);
4291 //******************************************************************************
4295 //******************************************************************************
4298 IOPMrootDomain::wakeFromDoze( void )
4300 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
4303 //******************************************************************************
4306 // Record the earliest scheduled RTC alarm to determine whether a RTC wake
4307 // should be a dark wake or a full wake. Both Maintenance and SleepService
4308 // alarms are dark wake, while AutoWake (WakeByCalendarDate) and DebugWake
4309 // (WakeRelativeToSleep) should trigger a full wake. Scheduled power-on
4310 // PMSettings are ignored.
4312 // Caller serialized using settingsCtrlLock.
4313 //******************************************************************************
4316 IOPMrootDomain::recordRTCAlarm(
4317 const OSSymbol
*type
,
4320 uint32_t previousAlarmMask
= _scheduledAlarmMask
;
4322 if (type
== gIOPMSettingDebugWakeRelativeKey
) {
4323 OSNumber
* n
= OSDynamicCast(OSNumber
, object
);
4325 // Debug wake has highest scheduling priority so it overrides any
4326 // pre-existing alarm.
4327 uint32_t debugSecs
= n
->unsigned32BitValue();
4328 _nextScheduledAlarmType
.reset(type
, OSRetain
);
4329 _nextScheduledAlarmUTC
= debugSecs
;
4331 _debugWakeSeconds
= debugSecs
;
4332 OSBitOrAtomic(kIOPMAlarmBitDebugWake
, &_scheduledAlarmMask
);
4333 DLOG("next alarm (%s) in %u secs\n",
4334 type
->getCStringNoCopy(), debugSecs
);
4336 } else if ((type
== gIOPMSettingAutoWakeCalendarKey
.get()) ||
4337 (type
== gIOPMSettingMaintenanceWakeCalendarKey
.get()) ||
4338 (type
== gIOPMSettingSleepServiceWakeCalendarKey
.get())) {
4339 OSData
* data
= OSDynamicCast(OSData
, object
);
4340 if (data
&& (data
->getLength() == sizeof(IOPMCalendarStruct
))) {
4341 const IOPMCalendarStruct
* cs
;
4342 bool replaceNextAlarm
= false;
4345 cs
= (const IOPMCalendarStruct
*) data
->getBytesNoCopy();
4346 secs
= IOPMConvertCalendarToSeconds(cs
);
4347 DLOG("%s " YMDTF
"\n", type
->getCStringNoCopy(), YMDT(cs
));
4349 // Update the next scheduled alarm type
4350 if ((_nextScheduledAlarmType
== NULL
) ||
4351 ((_nextScheduledAlarmType
!= gIOPMSettingDebugWakeRelativeKey
) &&
4352 (secs
< _nextScheduledAlarmUTC
))) {
4353 replaceNextAlarm
= true;
4356 if (type
== gIOPMSettingAutoWakeCalendarKey
.get()) {
4358 _calendarWakeAlarmUTC
= IOPMConvertCalendarToSeconds(cs
);
4359 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_scheduledAlarmMask
);
4361 // TODO: can this else-block be removed?
4362 _calendarWakeAlarmUTC
= 0;
4363 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_scheduledAlarmMask
);
4366 if (type
== gIOPMSettingMaintenanceWakeCalendarKey
.get()) {
4367 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake
, &_scheduledAlarmMask
);
4369 if (type
== gIOPMSettingSleepServiceWakeCalendarKey
.get()) {
4370 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake
, &_scheduledAlarmMask
);
4373 if (replaceNextAlarm
) {
4374 _nextScheduledAlarmType
.reset(type
, OSRetain
);
4375 _nextScheduledAlarmUTC
= secs
;
4376 DLOG("next alarm (%s) " YMDTF
"\n", type
->getCStringNoCopy(), YMDT(cs
));
4381 if (_scheduledAlarmMask
!= previousAlarmMask
) {
4382 DLOG("scheduled alarm mask 0x%x\n", (uint32_t) _scheduledAlarmMask
);
4389 //******************************************************************************
4392 // Adds a new feature to the supported features dictionary
4393 //******************************************************************************
4396 IOPMrootDomain::publishFeature( const char * feature
)
4398 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
4401 //******************************************************************************
4402 // publishFeature (with supported power source specified)
4404 // Adds a new feature to the supported features dictionary
4405 //******************************************************************************
4408 IOPMrootDomain::publishFeature(
4409 const char *feature
,
4410 uint32_t supportedWhere
,
4411 uint32_t *uniqueFeatureID
)
4413 static uint16_t next_feature_id
= 500;
4415 OSSharedPtr
<OSNumber
> new_feature_data
;
4416 OSNumber
*existing_feature
= NULL
;
4417 OSArray
*existing_feature_arr_raw
= NULL
;
4418 OSSharedPtr
<OSArray
> existing_feature_arr
;
4419 OSObject
*osObj
= NULL
;
4420 uint32_t feature_value
= 0;
4422 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
4424 if (!supportedWhere
) {
4425 // Feature isn't supported anywhere!
4429 if (next_feature_id
> 5000) {
4430 // Far, far too many features!
4434 if (featuresDictLock
) {
4435 IOLockLock(featuresDictLock
);
4438 OSSharedPtr
<OSObject
> origFeaturesProp
= copyProperty(kRootDomainSupportedFeatures
);
4439 OSDictionary
*origFeatures
= OSDynamicCast(OSDictionary
, origFeaturesProp
.get());
4440 OSSharedPtr
<OSDictionary
> features
;
4442 // Create new features dict if necessary
4444 features
= OSDictionary::withDictionary(origFeatures
);
4446 features
= OSDictionary::withCapacity(1);
4449 // Create OSNumber to track new feature
4451 next_feature_id
+= 1;
4452 if (uniqueFeatureID
) {
4453 // We don't really mind if the calling kext didn't give us a place
4454 // to stash their unique id. Many kexts don't plan to unload, and thus
4455 // have no need to remove themselves later.
4456 *uniqueFeatureID
= next_feature_id
;
4459 feature_value
= (uint32_t)next_feature_id
;
4460 feature_value
<<= 16;
4461 feature_value
+= supportedWhere
;
4463 new_feature_data
= OSNumber::withNumber(
4464 (unsigned long long)feature_value
, 32);
4466 // Does features object already exist?
4467 if ((osObj
= features
->getObject(feature
))) {
4468 if ((existing_feature
= OSDynamicCast(OSNumber
, osObj
))) {
4469 // We need to create an OSArray to hold the now 2 elements.
4470 existing_feature_arr
= OSArray::withObjects(
4471 (const OSObject
**)&existing_feature
, 1, 2);
4472 } else if ((existing_feature_arr_raw
= OSDynamicCast(OSArray
, osObj
))) {
4473 // Add object to existing array
4474 existing_feature_arr
= OSArray::withArray(
4475 existing_feature_arr_raw
,
4476 existing_feature_arr_raw
->getCount() + 1);
4479 if (existing_feature_arr
) {
4480 existing_feature_arr
->setObject(new_feature_data
.get());
4481 features
->setObject(feature
, existing_feature_arr
.get());
4484 // The easy case: no previously existing features listed. We simply
4485 // set the OSNumber at key 'feature' and we're on our way.
4486 features
->setObject(feature
, new_feature_data
.get());
4489 setProperty(kRootDomainSupportedFeatures
, features
.get());
4491 if (featuresDictLock
) {
4492 IOLockUnlock(featuresDictLock
);
4495 // Notify EnergySaver and all those in user space so they might
4496 // re-populate their feature specific UI
4497 if (pmPowerStateQueue
) {
4498 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
4502 //******************************************************************************
4503 // removePublishedFeature
4505 // Removes previously published feature
4506 //******************************************************************************
4509 IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
4511 IOReturn ret
= kIOReturnError
;
4512 uint32_t feature_value
= 0;
4513 uint16_t feature_id
= 0;
4514 bool madeAChange
= false;
4516 OSSymbol
*dictKey
= NULL
;
4517 OSSharedPtr
<OSCollectionIterator
> dictIterator
;
4518 OSArray
*arrayMember
= NULL
;
4519 OSNumber
*numberMember
= NULL
;
4520 OSObject
*osObj
= NULL
;
4521 OSNumber
*osNum
= NULL
;
4522 OSSharedPtr
<OSArray
> arrayMemberCopy
;
4524 if (kBadPMFeatureID
== removeFeatureID
) {
4525 return kIOReturnNotFound
;
4528 if (featuresDictLock
) {
4529 IOLockLock(featuresDictLock
);
4532 OSSharedPtr
<OSObject
> origFeaturesProp
= copyProperty(kRootDomainSupportedFeatures
);
4533 OSDictionary
*origFeatures
= OSDynamicCast(OSDictionary
, origFeaturesProp
.get());
4534 OSSharedPtr
<OSDictionary
> features
;
4537 // Any modifications to the dictionary are made to the copy to prevent
4538 // races & crashes with userland clients. Dictionary updated
4539 // automically later.
4540 features
= OSDictionary::withDictionary(origFeatures
);
4543 ret
= kIOReturnNotFound
;
4547 // We iterate 'features' dictionary looking for an entry tagged
4548 // with 'removeFeatureID'. If found, we remove it from our tracking
4549 // structures and notify the OS via a general interest message.
4551 dictIterator
= OSCollectionIterator::withCollection(features
.get());
4552 if (!dictIterator
) {
4556 while ((dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject()))) {
4557 osObj
= features
->getObject(dictKey
);
4559 // Each Feature is either tracked by an OSNumber
4560 if (osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
))) {
4561 feature_value
= numberMember
->unsigned32BitValue();
4562 feature_id
= (uint16_t)(feature_value
>> 16);
4564 if (feature_id
== (uint16_t)removeFeatureID
) {
4566 features
->removeObject(dictKey
);
4571 // Or tracked by an OSArray of OSNumbers
4572 } else if (osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
))) {
4573 unsigned int arrayCount
= arrayMember
->getCount();
4575 for (unsigned int i
= 0; i
< arrayCount
; i
++) {
4576 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
4581 feature_value
= osNum
->unsigned32BitValue();
4582 feature_id
= (uint16_t)(feature_value
>> 16);
4584 if (feature_id
== (uint16_t)removeFeatureID
) {
4586 if (1 == arrayCount
) {
4587 // If the array only contains one element, remove
4589 features
->removeObject(dictKey
);
4591 // Otherwise remove the element from a copy of the array.
4592 arrayMemberCopy
= OSArray::withArray(arrayMember
);
4593 if (arrayMemberCopy
) {
4594 arrayMemberCopy
->removeObject(i
);
4595 features
->setObject(dictKey
, arrayMemberCopy
.get());
4607 ret
= kIOReturnSuccess
;
4609 setProperty(kRootDomainSupportedFeatures
, features
.get());
4611 // Notify EnergySaver and all those in user space so they might
4612 // re-populate their feature specific UI
4613 if (pmPowerStateQueue
) {
4614 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
4617 ret
= kIOReturnNotFound
;
4621 if (featuresDictLock
) {
4622 IOLockUnlock(featuresDictLock
);
4627 //******************************************************************************
4628 // publishPMSetting (private)
4630 // Should only be called by PMSettingObject to publish a PM Setting as a
4631 // supported feature.
4632 //******************************************************************************
4635 IOPMrootDomain::publishPMSetting(
4636 const OSSymbol
* feature
, uint32_t where
, uint32_t * featureID
)
4638 if (noPublishPMSettings
&&
4639 (noPublishPMSettings
->getNextIndexOfObject(feature
, 0) != (unsigned int)-1)) {
4640 // Setting found in noPublishPMSettings array
4641 *featureID
= kBadPMFeatureID
;
4646 feature
->getCStringNoCopy(), where
, featureID
);
4649 //******************************************************************************
4650 // setPMSetting (private)
4652 // Internal helper to relay PM settings changes from user space to individual
4653 // drivers. Should be called only by IOPMrootDomain::setProperties.
4654 //******************************************************************************
4657 IOPMrootDomain::setPMSetting(
4658 const OSSymbol
*type
,
4661 PMSettingCallEntry
*entries
= NULL
;
4662 OSSharedPtr
<OSArray
> chosen
;
4663 const OSArray
*array
;
4664 PMSettingObject
*pmso
;
4665 thread_t thisThread
;
4666 int i
, j
, count
, capacity
;
4671 return kIOReturnBadArgument
;
4676 // Update settings dict so changes are visible from copyPMSetting().
4677 fPMSettingsDict
->setObject(type
, object
);
4679 // Prep all PMSetting objects with the given 'type' for callout.
4680 array
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(type
));
4681 if (!array
|| ((capacity
= array
->getCount()) == 0)) {
4685 // Array to retain PMSetting objects targeted for callout.
4686 chosen
= OSArray::withCapacity(capacity
);
4688 goto unlock_exit
; // error
4690 entries
= IONew(PMSettingCallEntry
, capacity
);
4692 goto unlock_exit
; // error
4694 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
4696 thisThread
= current_thread();
4698 for (i
= 0, j
= 0; i
< capacity
; i
++) {
4699 pmso
= (PMSettingObject
*) array
->getObject(i
);
4700 if (pmso
->disabled
) {
4703 entries
[j
].thread
= thisThread
;
4704 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
4705 chosen
->setObject(pmso
);
4715 // Call each pmso in the chosen array.
4716 for (i
= 0; i
< count
; i
++) {
4717 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
4718 ret
= pmso
->dispatchPMSetting(type
, object
);
4719 if (ret
== kIOReturnSuccess
) {
4720 // At least one setting handler was successful
4722 #if DEVELOPMENT || DEBUG
4724 // Log the handler and kext that failed
4725 OSSharedPtr
<const OSSymbol
> kextName
= copyKextIdentifierWithAddress((vm_address_t
) pmso
->func
);
4727 DLOG("PMSetting(%s) error 0x%x from %s\n",
4728 type
->getCStringNoCopy(), ret
, kextName
->getCStringNoCopy());
4735 for (i
= 0; i
< count
; i
++) {
4736 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
4737 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
4738 if (pmso
->waitThread
) {
4739 PMSETTING_WAKEUP(pmso
);
4744 recordRTCAlarm(type
, object
);
4750 IODelete(entries
, PMSettingCallEntry
, capacity
);
4753 return kIOReturnSuccess
;
4756 //******************************************************************************
4757 // copyPMSetting (public)
4759 // Allows kexts to safely read setting values, without being subscribed to
4761 //******************************************************************************
4763 OSSharedPtr
<OSObject
>
4764 IOPMrootDomain::copyPMSetting(
4765 OSSymbol
*whichSetting
)
4767 OSSharedPtr
<OSObject
> obj
;
4769 if (!whichSetting
) {
4774 obj
.reset(fPMSettingsDict
->getObject(whichSetting
), OSRetain
);
4780 //******************************************************************************
4781 // registerPMSettingController (public)
4783 // direct wrapper to registerPMSettingController with uint32_t power source arg
4784 //******************************************************************************
4787 IOPMrootDomain::registerPMSettingController(
4788 const OSSymbol
* settings
[],
4789 IOPMSettingControllerCallback func
,
4794 return registerPMSettingController(
4796 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
4797 func
, target
, refcon
, handle
);
4800 //******************************************************************************
4801 // registerPMSettingController (public)
4803 // Kexts may register for notifications when a particular setting is changed.
4804 // A list of settings is available in IOPM.h.
4806 // * settings - An OSArray containing OSSymbols. Caller should populate this
4807 // array with a list of settings caller wants notifications from.
4808 // * func - A C function callback of the type IOPMSettingControllerCallback
4809 // * target - caller may provide an OSObject *, which PM will pass as an
4810 // target to calls to "func"
4811 // * refcon - caller may provide an void *, which PM will pass as an
4812 // argument to calls to "func"
4813 // * handle - This is a return argument. We will populate this pointer upon
4814 // call success. Hold onto this and pass this argument to
4815 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
4817 // kIOReturnSuccess on success
4818 //******************************************************************************
4821 IOPMrootDomain::registerPMSettingController(
4822 const OSSymbol
* settings
[],
4823 uint32_t supportedPowerSources
,
4824 IOPMSettingControllerCallback func
,
4829 PMSettingObject
*pmso
= NULL
;
4830 OSObject
*pmsh
= NULL
;
4833 if (NULL
== settings
||
4836 return kIOReturnBadArgument
;
4839 pmso
= PMSettingObject::pmSettingObject(
4840 (IOPMrootDomain
*) this, func
, target
,
4841 refcon
, supportedPowerSources
, settings
, &pmsh
);
4845 return kIOReturnInternalError
;
4849 for (i
= 0; settings
[i
]; i
++) {
4850 OSSharedPtr
<OSArray
> newList
;
4851 OSArray
*list
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(settings
[i
]));
4853 // New array of callbacks for this setting
4854 newList
= OSArray::withCapacity(1);
4855 settingsCallbacks
->setObject(settings
[i
], newList
.get());
4856 list
= newList
.get();
4859 // Add caller to the callback list
4860 list
->setObject(pmso
);
4864 // Return handle to the caller, the setting object is private.
4867 return kIOReturnSuccess
;
4870 //******************************************************************************
4871 // deregisterPMSettingObject (private)
4873 // Only called from PMSettingObject.
4874 //******************************************************************************
4877 IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
4879 thread_t thisThread
= current_thread();
4880 PMSettingCallEntry
*callEntry
;
4881 OSSharedPtr
<OSCollectionIterator
> iter
;
4889 pmso
->disabled
= true;
4891 // Wait for all callout threads to finish.
4894 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
4896 if (callEntry
->thread
!= thisThread
) {
4902 assert(NULL
== pmso
->waitThread
);
4903 pmso
->waitThread
= thisThread
;
4904 PMSETTING_WAIT(pmso
);
4905 pmso
->waitThread
= NULL
;
4909 // Search each PM settings array in the kernel.
4910 iter
= OSCollectionIterator::withCollection(settingsCallbacks
.get());
4912 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject()))) {
4913 array
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(sym
));
4914 index
= array
->getNextIndexOfObject(pmso
, 0);
4916 array
->removeObject(index
);
4926 //******************************************************************************
4927 // informCPUStateChange
4929 // Call into PM CPU code so that CPU power savings may dynamically adjust for
4930 // running on battery, with the lid closed, etc.
4932 // informCPUStateChange is a no-op on non x86 systems
4933 // only x86 has explicit support in the IntelCPUPowerManagement kext
4934 //******************************************************************************
4937 IOPMrootDomain::informCPUStateChange(
4941 #if defined(__i386__) || defined(__x86_64__)
4943 pmioctlVariableInfo_t varInfoStruct
;
4945 const char *varNameStr
= NULL
;
4946 int32_t *varIndex
= NULL
;
4948 if (kInformAC
== type
) {
4949 varNameStr
= kIOPMRootDomainBatPowerCString
;
4950 varIndex
= &idxPMCPULimitedPower
;
4951 } else if (kInformLid
== type
) {
4952 varNameStr
= kIOPMRootDomainLidCloseCString
;
4953 varIndex
= &idxPMCPUClamshell
;
4958 // Set the new value!
4959 // pmCPUControl will assign us a new ID if one doesn't exist yet
4960 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
4961 varInfoStruct
.varID
= *varIndex
;
4962 varInfoStruct
.varType
= vBool
;
4963 varInfoStruct
.varInitValue
= value
;
4964 varInfoStruct
.varCurValue
= value
;
4965 strlcpy((char *)varInfoStruct
.varName
,
4966 (const char *)varNameStr
,
4967 sizeof(varInfoStruct
.varName
));
4970 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
4972 // pmCPU only assigns numerical id's when a new varName is specified
4974 && (*varIndex
== kCPUUnknownIndex
)) {
4975 // pmCPUControl has assigned us a new variable ID.
4976 // Let's re-read the structure we just SET to learn that ID.
4977 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
4979 if (0 == pmCPUret
) {
4980 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
4981 *varIndex
= varInfoStruct
.varID
;
4987 #endif /* __i386__ || __x86_64__ */
4991 // MARK: Deep Sleep Policy
4995 //******************************************************************************
4996 // evaluateSystemSleepPolicy
4997 //******************************************************************************
4999 #define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
5003 kIOPMSleepFlagHibernate
= 0x00000001,
5004 kIOPMSleepFlagSleepTimerEnable
= 0x00000002
5007 struct IOPMSystemSleepPolicyEntry
{
5008 uint32_t factorMask
;
5009 uint32_t factorBits
;
5010 uint32_t sleepFlags
;
5011 uint32_t wakeEvents
;
5012 } __attribute__((packed
));
5014 struct IOPMSystemSleepPolicyTable
{
5017 uint16_t entryCount
;
5018 IOPMSystemSleepPolicyEntry entries
[];
5019 } __attribute__((packed
));
5022 kIOPMSleepAttributeHibernateSetup
= 0x00000001,
5023 kIOPMSleepAttributeHibernateSleep
= 0x00000002
5027 getSleepTypeAttributes( uint32_t sleepType
)
5029 static const uint32_t sleepTypeAttributes
[kIOPMSleepTypeLast
] =
5034 /* safesleep */ kIOPMSleepAttributeHibernateSetup
,
5035 /* hibernate */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
5036 /* standby */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
5037 /* poweroff */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
5041 if (sleepType
>= kIOPMSleepTypeLast
) {
5045 return sleepTypeAttributes
[sleepType
];
5049 IOPMrootDomain::evaluateSystemSleepPolicy(
5050 IOPMSystemSleepParameters
* params
, int sleepPhase
, uint32_t * hibMode
)
5052 #define SLEEP_FACTOR(x) {(uint32_t) kIOPMSleepFactor ## x, #x}
5054 static const IONamedValue factorValues
[] = {
5055 SLEEP_FACTOR( SleepTimerWake
),
5056 SLEEP_FACTOR( LidOpen
),
5057 SLEEP_FACTOR( ACPower
),
5058 SLEEP_FACTOR( BatteryLow
),
5059 SLEEP_FACTOR( StandbyNoDelay
),
5060 SLEEP_FACTOR( StandbyForced
),
5061 SLEEP_FACTOR( StandbyDisabled
),
5062 SLEEP_FACTOR( USBExternalDevice
),
5063 SLEEP_FACTOR( BluetoothHIDDevice
),
5064 SLEEP_FACTOR( ExternalMediaMounted
),
5065 SLEEP_FACTOR( ThunderboltDevice
),
5066 SLEEP_FACTOR( RTCAlarmScheduled
),
5067 SLEEP_FACTOR( MagicPacketWakeEnabled
),
5068 SLEEP_FACTOR( HibernateForced
),
5069 SLEEP_FACTOR( AutoPowerOffDisabled
),
5070 SLEEP_FACTOR( AutoPowerOffForced
),
5071 SLEEP_FACTOR( ExternalDisplay
),
5072 SLEEP_FACTOR( NetworkKeepAliveActive
),
5073 SLEEP_FACTOR( LocalUserActivity
),
5074 SLEEP_FACTOR( HibernateFailed
),
5075 SLEEP_FACTOR( ThermalWarning
),
5076 SLEEP_FACTOR( DisplayCaptured
),
5080 const IOPMSystemSleepPolicyTable
* pt
;
5081 OSSharedPtr
<OSObject
> prop
;
5082 OSData
* policyData
;
5083 uint64_t currentFactors
= 0;
5084 char currentFactorsBuf
[512];
5085 uint32_t standbyDelay
= 0;
5086 uint32_t powerOffDelay
= 0;
5087 uint32_t powerOffTimer
= 0;
5088 uint32_t standbyTimer
= 0;
5090 bool standbyEnabled
;
5091 bool powerOffEnabled
;
5094 // Get platform's sleep policy table
5095 if (!gSleepPolicyHandler
) {
5096 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
5102 // Fetch additional settings
5103 standbyEnabled
= (getSleepOption(kIOPMDeepSleepDelayKey
, &standbyDelay
)
5104 && propertyHasValue(kIOPMDeepSleepEnabledKey
, kOSBooleanTrue
));
5105 powerOffEnabled
= (getSleepOption(kIOPMAutoPowerOffDelayKey
, &powerOffDelay
)
5106 && propertyHasValue(kIOPMAutoPowerOffEnabledKey
, kOSBooleanTrue
));
5107 if (!getSleepOption(kIOPMAutoPowerOffTimerKey
, &powerOffTimer
)) {
5108 powerOffTimer
= powerOffDelay
;
5110 if (!getSleepOption(kIOPMDeepSleepTimerKey
, &standbyTimer
)) {
5111 standbyTimer
= standbyDelay
;
5114 DLOG("phase %d, standby %d delay %u timer %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
5115 sleepPhase
, standbyEnabled
, standbyDelay
, standbyTimer
,
5116 powerOffEnabled
, powerOffDelay
, powerOffTimer
, *hibMode
);
5118 currentFactorsBuf
[0] = 0;
5119 // pmset level overrides
5120 if ((*hibMode
& kIOHibernateModeOn
) == 0) {
5121 if (!gSleepPolicyHandler
) {
5122 standbyEnabled
= false;
5123 powerOffEnabled
= false;
5125 } else if (!(*hibMode
& kIOHibernateModeSleep
)) {
5126 // Force hibernate (i.e. mode 25)
5127 // If standby is enabled, force standy.
5128 // If poweroff is enabled, force poweroff.
5129 if (standbyEnabled
) {
5130 currentFactors
|= kIOPMSleepFactorStandbyForced
;
5131 } else if (powerOffEnabled
) {
5132 currentFactors
|= kIOPMSleepFactorAutoPowerOffForced
;
5134 currentFactors
|= kIOPMSleepFactorHibernateForced
;
5138 // Current factors based on environment and assertions
5139 if (sleepTimerMaintenance
) {
5140 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
5142 if (standbyEnabled
&& sleepToStandby
&& !gSleepPolicyHandler
) {
5143 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
5145 if (!clamshellClosed
) {
5146 currentFactors
|= kIOPMSleepFactorLidOpen
;
5148 if (acAdaptorConnected
) {
5149 currentFactors
|= kIOPMSleepFactorACPower
;
5151 if (lowBatteryCondition
) {
5153 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
5154 if ((hibernateMode
& kIOHibernateModeOn
) == 0) {
5155 DLOG("HibernateMode is 0. Not sending LowBattery factor to IOPPF\n");
5157 currentFactors
|= kIOPMSleepFactorBatteryLow
;
5160 if (!standbyDelay
|| !standbyTimer
) {
5161 currentFactors
|= kIOPMSleepFactorStandbyNoDelay
;
5163 if (standbyNixed
|| !standbyEnabled
) {
5164 currentFactors
|= kIOPMSleepFactorStandbyDisabled
;
5167 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
5168 currentFactors
&= ~kIOPMSleepFactorSleepTimerWake
;
5170 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
5171 kIOPMDriverAssertionLevelOff
) {
5172 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
5174 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
5175 kIOPMDriverAssertionLevelOff
) {
5176 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
5178 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
5179 kIOPMDriverAssertionLevelOff
) {
5180 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
5182 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) !=
5183 kIOPMDriverAssertionLevelOff
) {
5184 currentFactors
|= kIOPMSleepFactorThunderboltDevice
;
5186 if (_scheduledAlarmMask
!= 0) {
5187 currentFactors
|= kIOPMSleepFactorRTCAlarmScheduled
;
5189 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit
) !=
5190 kIOPMDriverAssertionLevelOff
) {
5191 currentFactors
|= kIOPMSleepFactorMagicPacketWakeEnabled
;
5193 #define TCPKEEPALIVE 1
5195 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit
) !=
5196 kIOPMDriverAssertionLevelOff
) {
5197 currentFactors
|= kIOPMSleepFactorNetworkKeepAliveActive
;
5200 if (!powerOffEnabled
) {
5201 currentFactors
|= kIOPMSleepFactorAutoPowerOffDisabled
;
5204 currentFactors
|= kIOPMSleepFactorExternalDisplay
;
5206 if (userWasActive
) {
5207 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
5209 if (darkWakeHibernateError
&& !CAP_HIGHEST(kIOPMSystemCapabilityGraphics
)) {
5210 currentFactors
|= kIOPMSleepFactorHibernateFailed
;
5212 if (thermalWarningState
) {
5213 currentFactors
|= kIOPMSleepFactorThermalWarning
;
5216 for (int factorBit
= 0; factorBit
< (8 * sizeof(uint32_t)); factorBit
++) {
5217 uint32_t factor
= 1 << factorBit
;
5218 if (factor
& currentFactors
) {
5219 strlcat(currentFactorsBuf
, ", ", sizeof(currentFactorsBuf
));
5220 strlcat(currentFactorsBuf
, IOFindNameForValue(factor
, factorValues
), sizeof(currentFactorsBuf
));
5223 DLOG("sleep factors 0x%llx%s\n", currentFactors
, currentFactorsBuf
);
5225 if (gSleepPolicyHandler
) {
5226 uint32_t savedHibernateMode
;
5229 if (!gSleepPolicyVars
) {
5230 gSleepPolicyVars
= IONew(IOPMSystemSleepPolicyVariables
, 1);
5231 if (!gSleepPolicyVars
) {
5234 bzero(gSleepPolicyVars
, sizeof(*gSleepPolicyVars
));
5236 gSleepPolicyVars
->signature
= kIOPMSystemSleepPolicySignature
;
5237 gSleepPolicyVars
->version
= kIOPMSystemSleepPolicyVersion
;
5238 gSleepPolicyVars
->currentCapability
= _currentCapability
;
5239 gSleepPolicyVars
->highestCapability
= _highestCapability
;
5240 gSleepPolicyVars
->sleepFactors
= currentFactors
;
5241 gSleepPolicyVars
->sleepReason
= lastSleepReason
;
5242 gSleepPolicyVars
->sleepPhase
= sleepPhase
;
5243 gSleepPolicyVars
->standbyDelay
= standbyDelay
;
5244 gSleepPolicyVars
->standbyTimer
= standbyTimer
;
5245 gSleepPolicyVars
->poweroffDelay
= powerOffDelay
;
5246 gSleepPolicyVars
->scheduledAlarms
= _scheduledAlarmMask
| _userScheduledAlarmMask
;
5247 gSleepPolicyVars
->poweroffTimer
= powerOffTimer
;
5249 if (kIOPMSleepPhase0
== sleepPhase
) {
5250 // preserve hibernateMode
5251 savedHibernateMode
= gSleepPolicyVars
->hibernateMode
;
5252 gSleepPolicyVars
->hibernateMode
= *hibMode
;
5253 } else if (kIOPMSleepPhase1
== sleepPhase
) {
5254 // use original hibernateMode for phase2
5255 gSleepPolicyVars
->hibernateMode
= *hibMode
;
5258 result
= gSleepPolicyHandler(gSleepPolicyTarget
, gSleepPolicyVars
, params
);
5260 if (kIOPMSleepPhase0
== sleepPhase
) {
5261 // restore hibernateMode
5262 gSleepPolicyVars
->hibernateMode
= savedHibernateMode
;
5265 if ((result
!= kIOReturnSuccess
) ||
5266 (kIOPMSleepTypeInvalid
== params
->sleepType
) ||
5267 (params
->sleepType
>= kIOPMSleepTypeLast
) ||
5268 (kIOPMSystemSleepParametersVersion
!= params
->version
)) {
5269 MSG("sleep policy handler error\n");
5273 if ((getSleepTypeAttributes(params
->sleepType
) &
5274 kIOPMSleepAttributeHibernateSetup
) &&
5275 ((*hibMode
& kIOHibernateModeOn
) == 0)) {
5276 *hibMode
|= (kIOHibernateModeOn
| kIOHibernateModeSleep
);
5279 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
5280 params
->version
, params
->sleepType
, params
->sleepFlags
,
5281 params
->ecWakeEvents
, params
->ecWakeTimer
, params
->ecPoweroffTimer
);
5286 // Policy table is meaningless without standby enabled
5287 if (!standbyEnabled
) {
5291 // Validate the sleep policy table
5292 policyData
= OSDynamicCast(OSData
, prop
.get());
5293 if (!policyData
|| (policyData
->getLength() <= sizeof(IOPMSystemSleepPolicyTable
))) {
5297 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
5298 if ((pt
->signature
!= kIOPMSystemSleepPolicySignature
) ||
5299 (pt
->version
!= 1) || (0 == pt
->entryCount
)) {
5303 if (((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
5304 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
))) {
5308 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++) {
5309 const IOPMSystemSleepPolicyEntry
* entry
= &pt
->entries
[i
];
5310 mismatch
= (((uint32_t)currentFactors
^ entry
->factorBits
) & entry
->factorMask
);
5312 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
5313 entry
->factorMask
, entry
->factorBits
,
5314 entry
->sleepFlags
, entry
->wakeEvents
, mismatch
);
5319 DLOG("^ found match\n");
5322 params
->version
= kIOPMSystemSleepParametersVersion
;
5323 params
->reserved1
= 1;
5324 if (entry
->sleepFlags
& kIOPMSleepFlagHibernate
) {
5325 params
->sleepType
= kIOPMSleepTypeStandby
;
5327 params
->sleepType
= kIOPMSleepTypeNormalSleep
;
5330 params
->ecWakeEvents
= entry
->wakeEvents
;
5331 if (entry
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
) {
5332 if (kIOPMSleepPhase2
== sleepPhase
) {
5333 clock_sec_t now_secs
= gIOLastSleepTime
.tv_sec
;
5335 if (!_standbyTimerResetSeconds
||
5336 (now_secs
<= _standbyTimerResetSeconds
)) {
5337 // Reset standby timer adjustment
5338 _standbyTimerResetSeconds
= now_secs
;
5339 DLOG("standby delay %u, reset %u\n",
5340 standbyDelay
, (uint32_t) _standbyTimerResetSeconds
);
5341 } else if (standbyDelay
) {
5342 // Shorten the standby delay timer
5343 clock_sec_t elapsed
= now_secs
- _standbyTimerResetSeconds
;
5344 if (standbyDelay
> elapsed
) {
5345 standbyDelay
-= elapsed
;
5347 standbyDelay
= 1; // must be > 0
5349 DLOG("standby delay %u, elapsed %u\n",
5350 standbyDelay
, (uint32_t) elapsed
);
5353 params
->ecWakeTimer
= standbyDelay
;
5354 } else if (kIOPMSleepPhase2
== sleepPhase
) {
5355 // A sleep that does not enable the sleep timer will reset
5356 // the standby delay adjustment.
5357 _standbyTimerResetSeconds
= 0;
5366 static IOPMSystemSleepParameters gEarlySystemSleepParams
;
5369 IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
5371 // Evaluate early (priority interest phase), before drivers sleep.
5373 DLOG("%s\n", __FUNCTION__
);
5374 removeProperty(kIOPMSystemSleepParametersKey
);
5376 // Full wake resets the standby timer delay adjustment
5377 if (_highestCapability
& kIOPMSystemCapabilityGraphics
) {
5378 _standbyTimerResetSeconds
= 0;
5381 hibernateDisabled
= false;
5383 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
5385 // Save for late evaluation if sleep is aborted
5386 bzero(&gEarlySystemSleepParams
, sizeof(gEarlySystemSleepParams
));
5388 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams
, kIOPMSleepPhase1
,
5390 if (!hibernateRetry
&&
5391 ((getSleepTypeAttributes(gEarlySystemSleepParams
.sleepType
) &
5392 kIOPMSleepAttributeHibernateSetup
) == 0)) {
5393 // skip hibernate setup
5394 hibernateDisabled
= true;
5398 // Publish IOPMSystemSleepType
5399 uint32_t sleepType
= gEarlySystemSleepParams
.sleepType
;
5400 if (sleepType
== kIOPMSleepTypeInvalid
) {
5402 sleepType
= kIOPMSleepTypeNormalSleep
;
5403 if (hibernateMode
& kIOHibernateModeOn
) {
5404 sleepType
= (hibernateMode
& kIOHibernateModeSleep
) ?
5405 kIOPMSleepTypeSafeSleep
: kIOPMSleepTypeHibernate
;
5407 } else if ((sleepType
== kIOPMSleepTypeStandby
) &&
5408 (gEarlySystemSleepParams
.ecPoweroffTimer
)) {
5409 // report the lowest possible sleep state
5410 sleepType
= kIOPMSleepTypePowerOff
;
5413 setProperty(kIOPMSystemSleepTypeKey
, sleepType
, 32);
5417 IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
5419 IOPMSystemSleepParameters params
;
5420 OSSharedPtr
<OSData
> paramsData
;
5422 // Evaluate sleep policy after sleeping drivers but before platform sleep.
5424 DLOG("%s\n", __FUNCTION__
);
5426 bzero(¶ms
, sizeof(params
));
5428 if (evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase2
, &hibernateMode
)) {
5429 if ((kIOPMSleepTypeStandby
== params
.sleepType
)
5430 && gIOHibernateStandbyDisabled
&& gSleepPolicyVars
5431 && (!((kIOPMSleepFactorStandbyForced
| kIOPMSleepFactorAutoPowerOffForced
| kIOPMSleepFactorHibernateForced
)
5432 & gSleepPolicyVars
->sleepFactors
))) {
5433 standbyNixed
= true;
5437 || ((hibernateDisabled
|| hibernateAborted
) &&
5438 (getSleepTypeAttributes(params
.sleepType
) &
5439 kIOPMSleepAttributeHibernateSetup
))) {
5440 // Final evaluation picked a state requiring hibernation,
5441 // but hibernate isn't going to proceed. Arm a short sleep using
5442 // the early non-hibernate sleep parameters.
5443 bcopy(&gEarlySystemSleepParams
, ¶ms
, sizeof(params
));
5444 params
.sleepType
= kIOPMSleepTypeAbortedSleep
;
5445 params
.ecWakeTimer
= 1;
5449 // Set hibernateRetry flag to force hibernate setup on the
5451 hibernateRetry
= true;
5453 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d, standbyNixed %d\n",
5454 params
.ecWakeTimer
, hibernateDisabled
, hibernateAborted
, standbyNixed
);
5456 hibernateRetry
= false;
5459 if (kIOPMSleepTypeAbortedSleep
!= params
.sleepType
) {
5460 resetTimers
= false;
5463 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
5465 setProperty(kIOPMSystemSleepParametersKey
, paramsData
.get());
5468 if (getSleepTypeAttributes(params
.sleepType
) &
5469 kIOPMSleepAttributeHibernateSleep
) {
5470 // Disable sleep to force hibernation
5471 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
5477 IOPMrootDomain::getHibernateSettings(
5478 uint32_t * hibernateModePtr
,
5479 uint32_t * hibernateFreeRatio
,
5480 uint32_t * hibernateFreeTime
)
5482 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
5483 // has updated the hibernateDisabled flag.
5485 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateModePtr
);
5486 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
5487 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
5488 if (hibernateDisabled
) {
5489 *hibernateModePtr
= 0;
5490 } else if (gSleepPolicyHandler
) {
5491 *hibernateModePtr
= hibernateMode
;
5493 DLOG("hibernateMode 0x%x\n", *hibernateModePtr
);
5498 IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
5500 OSSharedPtr
<OSObject
> optionsProp
;
5501 OSDictionary
* optionsDict
;
5502 OSSharedPtr
<OSObject
> obj
;
5506 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
5507 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
.get());
5510 obj
.reset(optionsDict
->getObject(key
), OSRetain
);
5513 obj
= copyProperty(key
);
5516 if ((num
= OSDynamicCast(OSNumber
, obj
.get()))) {
5517 *option
= num
->unsigned32BitValue();
5519 } else if (OSDynamicCast(OSBoolean
, obj
.get())) {
5520 *option
= (obj
== kOSBooleanTrue
) ? 1 : 0;
5527 #endif /* HIBERNATION */
5530 IOPMrootDomain::getSystemSleepType( uint32_t * sleepType
, uint32_t * standbyTimer
)
5533 IOPMSystemSleepParameters params
;
5534 uint32_t hibMode
= 0;
5537 if (gIOPMWorkLoop
->inGate() == false) {
5538 IOReturn ret
= gIOPMWorkLoop
->runAction(
5539 OSMemberFunctionCast(IOWorkLoop::Action
, this,
5540 &IOPMrootDomain::getSystemSleepType
),
5542 (void *) sleepType
, (void *) standbyTimer
);
5546 getSleepOption(kIOHibernateModeKey
, &hibMode
);
5547 bzero(¶ms
, sizeof(params
));
5549 ok
= evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase0
, &hibMode
);
5551 *sleepType
= params
.sleepType
;
5552 if (!getSleepOption(kIOPMDeepSleepTimerKey
, standbyTimer
) &&
5553 !getSleepOption(kIOPMDeepSleepDelayKey
, standbyTimer
)) {
5554 DLOG("Standby delay is not set\n");
5557 return kIOReturnSuccess
;
5561 return kIOReturnUnsupported
;
5565 // MARK: Shutdown and Restart
5567 //******************************************************************************
5568 // handlePlatformHaltRestart
5570 //******************************************************************************
5572 // Phases while performing shutdown/restart
5575 kNotifyPriorityClients
= 0x10,
5576 kNotifyPowerPlaneDrivers
= 0x20,
5577 kNotifyHaltRestartAction
= 0x30,
5582 struct HaltRestartApplierContext
{
5583 IOPMrootDomain
* RootDomain
;
5584 unsigned long PowerState
;
5585 IOPMPowerFlags PowerFlags
;
5588 const char * LogString
;
5589 shutdownPhase_t phase
;
5591 IOServiceInterestHandler handler
;
5595 shutdownPhase2String(shutdownPhase_t phase
)
5599 return "Notifications completed";
5600 case kNotifyPriorityClients
:
5601 return "Notifying priority clients";
5602 case kNotifyPowerPlaneDrivers
:
5603 return "Notifying power plane drivers";
5604 case kNotifyHaltRestartAction
:
5605 return "Notifying HaltRestart action handlers";
5607 return "Quiescing PM";
5614 platformHaltRestartApplier( OSObject
* object
, void * context
)
5616 IOPowerStateChangeNotification notify
;
5617 HaltRestartApplierContext
* ctx
;
5618 AbsoluteTime startTime
, elapsedTime
;
5621 ctx
= (HaltRestartApplierContext
*) context
;
5623 _IOServiceInterestNotifier
* notifier
;
5624 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
5625 memset(¬ify
, 0, sizeof(notify
));
5626 notify
.powerRef
= (void *)(uintptr_t)ctx
->Counter
;
5627 notify
.returnValue
= 0;
5628 notify
.stateNumber
= ctx
->PowerState
;
5629 notify
.stateFlags
= ctx
->PowerFlags
;
5632 ctx
->handler
= notifier
->handler
;
5635 clock_get_uptime(&startTime
);
5636 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
5637 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
5639 if ((deltaTime
> kPMHaltTimeoutMS
) && notifier
) {
5640 LOG("%s handler %p took %u ms\n",
5641 ctx
->LogString
, OBFUSCATE(notifier
->handler
), deltaTime
);
5642 halt_log_enter("PowerOff/Restart message to priority client", (const void *) notifier
->handler
, elapsedTime
);
5645 ctx
->handler
= NULL
;
5650 quiescePowerTreeCallback( void * target
, void * param
)
5652 IOLockLock(gPMHaltLock
);
5654 thread_wakeup(param
);
5655 IOLockUnlock(gPMHaltLock
);
5659 IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
5661 AbsoluteTime startTime
, elapsedTime
;
5664 memset(&gHaltRestartCtx
, 0, sizeof(gHaltRestartCtx
));
5665 gHaltRestartCtx
.RootDomain
= this;
5667 clock_get_uptime(&startTime
);
5670 case kPEUPSDelayHaltCPU
:
5671 gHaltRestartCtx
.PowerState
= OFF_STATE
;
5672 gHaltRestartCtx
.MessageType
= kIOMessageSystemWillPowerOff
;
5673 gHaltRestartCtx
.LogString
= "PowerOff";
5677 gHaltRestartCtx
.PowerState
= RESTART_STATE
;
5678 gHaltRestartCtx
.MessageType
= kIOMessageSystemWillRestart
;
5679 gHaltRestartCtx
.LogString
= "Restart";
5683 gHaltRestartCtx
.PowerState
= ON_STATE
;
5684 gHaltRestartCtx
.MessageType
= kIOMessageSystemPagingOff
;
5685 gHaltRestartCtx
.LogString
= "PagingOff";
5686 IOService::updateConsoleUsers(NULL
, kIOMessageSystemPagingOff
);
5688 IOHibernateSystemRestart();
5696 gHaltRestartCtx
.phase
= kNotifyPriorityClients
;
5697 // Notify legacy clients
5698 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &gHaltRestartCtx
);
5700 // For normal shutdown, turn off File Server Mode.
5701 if (kPEHaltCPU
== pe_type
) {
5702 OSSharedPtr
<const OSSymbol
> setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
5703 OSSharedPtr
<OSNumber
> num
= OSNumber::withNumber((unsigned long long) 0, 32);
5704 if (setting
&& num
) {
5705 setPMSetting(setting
.get(), num
.get());
5709 if (kPEPagingOff
!= pe_type
) {
5710 gHaltRestartCtx
.phase
= kNotifyPowerPlaneDrivers
;
5711 // Notify in power tree order
5712 notifySystemShutdown(this, gHaltRestartCtx
.MessageType
);
5715 gHaltRestartCtx
.phase
= kNotifyHaltRestartAction
;
5716 #if defined(XNU_TARGET_OS_OSX)
5717 IOCPURunPlatformHaltRestartActions(pe_type
);
5718 #else /* !defined(XNU_TARGET_OS_OSX) */
5719 if (kPEPagingOff
!= pe_type
) {
5720 IOCPURunPlatformHaltRestartActions(pe_type
);
5722 #endif /* !defined(XNU_TARGET_OS_OSX) */
5724 // Wait for PM to quiesce
5725 if ((kPEPagingOff
!= pe_type
) && gPMHaltLock
) {
5726 gHaltRestartCtx
.phase
= kQuiescePM
;
5727 AbsoluteTime quiesceTime
= mach_absolute_time();
5729 IOLockLock(gPMHaltLock
);
5730 gPMQuiesced
= false;
5731 if (quiescePowerTree(this, &quiescePowerTreeCallback
, &gPMQuiesced
) ==
5733 while (!gPMQuiesced
) {
5734 IOLockSleep(gPMHaltLock
, &gPMQuiesced
, THREAD_UNINT
);
5737 IOLockUnlock(gPMHaltLock
);
5738 deltaTime
= computeDeltaTimeMS(&quiesceTime
, &elapsedTime
);
5739 DLOG("PM quiesce took %u ms\n", deltaTime
);
5740 halt_log_enter("Quiesce", NULL
, elapsedTime
);
5742 gHaltRestartCtx
.phase
= kNotifyDone
;
5744 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
5745 LOG("%s all drivers took %u ms\n", gHaltRestartCtx
.LogString
, deltaTime
);
5747 halt_log_enter(gHaltRestartCtx
.LogString
, NULL
, elapsedTime
);
5749 deltaTime
= computeDeltaTimeMS(&gHaltStartTime
, &elapsedTime
);
5750 LOG("%s total %u ms\n", gHaltRestartCtx
.LogString
, deltaTime
);
5752 if (gHaltLog
&& gHaltTimeMaxLog
&& (deltaTime
>= gHaltTimeMaxLog
)) {
5753 printf("%s total %d ms:%s\n", gHaltRestartCtx
.LogString
, deltaTime
, gHaltLog
);
5756 checkShutdownTimeout();
5760 IOPMrootDomain::checkShutdownTimeout()
5762 AbsoluteTime elapsedTime
;
5763 uint32_t deltaTime
= computeDeltaTimeMS(&gHaltStartTime
, &elapsedTime
);
5765 if (gHaltTimeMaxPanic
&& (deltaTime
>= gHaltTimeMaxPanic
)) {
5772 IOPMrootDomain::panicWithShutdownLog(uint32_t timeoutInMs
)
5775 if ((gHaltRestartCtx
.phase
== kNotifyPriorityClients
) && gHaltRestartCtx
.handler
) {
5776 halt_log_enter("Blocked on priority client", (void *)gHaltRestartCtx
.handler
, mach_absolute_time() - gHaltStartTime
);
5778 panic("%s timed out in phase '%s'. Total %d ms:%s",
5779 gHaltRestartCtx
.LogString
, shutdownPhase2String(gHaltRestartCtx
.phase
), timeoutInMs
, gHaltLog
);
5781 panic("%s timed out in phase \'%s\'. Total %d ms",
5782 gHaltRestartCtx
.LogString
, shutdownPhase2String(gHaltRestartCtx
.phase
), timeoutInMs
);
5786 //******************************************************************************
5789 //******************************************************************************
5792 IOPMrootDomain::shutdownSystem( void )
5794 return kIOReturnUnsupported
;
5797 //******************************************************************************
5800 //******************************************************************************
5803 IOPMrootDomain::restartSystem( void )
5805 return kIOReturnUnsupported
;
5809 // MARK: System Capability
5811 //******************************************************************************
5812 // tagPowerPlaneService
5814 // Running on PM work loop thread.
5815 //******************************************************************************
5818 IOPMrootDomain::tagPowerPlaneService(
5819 IOService
* service
,
5820 IOPMActions
* actions
,
5821 IOPMPowerStateIndex maxPowerState
)
5825 memset(actions
, 0, sizeof(*actions
));
5826 actions
->target
= this;
5828 if (service
== this) {
5829 actions
->actionPowerChangeStart
=
5830 OSMemberFunctionCast(
5831 IOPMActionPowerChangeStart
, this,
5832 &IOPMrootDomain::handleOurPowerChangeStart
);
5834 actions
->actionPowerChangeDone
=
5835 OSMemberFunctionCast(
5836 IOPMActionPowerChangeDone
, this,
5837 &IOPMrootDomain::handleOurPowerChangeDone
);
5839 actions
->actionPowerChangeOverride
=
5840 OSMemberFunctionCast(
5841 IOPMActionPowerChangeOverride
, this,
5842 &IOPMrootDomain::overrideOurPowerChange
);
5846 #if DISPLAY_WRANGLER_PRESENT
5847 if (NULL
!= service
->metaCast("IODisplayWrangler")) {
5848 // XXX should this really retain?
5849 wrangler
.reset(service
, OSRetain
);
5850 wrangler
->registerInterest(gIOGeneralInterest
,
5851 &displayWranglerNotification
, this, NULL
);
5853 // found the display wrangler, check for any display assertions already created
5854 if (pmAssertions
->getActivatedAssertions() & kIOPMDriverAssertionPreventDisplaySleepBit
) {
5855 DLOG("wrangler setIgnoreIdleTimer\(1) due to pre-existing assertion\n");
5856 wrangler
->setIgnoreIdleTimer( true );
5858 flags
|= kPMActionsFlagIsDisplayWrangler
;
5860 #endif /* DISPLAY_WRANGLER_PRESENT */
5862 if (service
->propertyExists("IOPMStrictTreeOrder")) {
5863 flags
|= kPMActionsFlagIsGraphicsDriver
;
5865 if (service
->propertyExists("IOPMUnattendedWakePowerState")) {
5866 flags
|= kPMActionsFlagIsAudioDriver
;
5869 OSSharedPtr
<OSObject
> prop
= service
->copyProperty(kIOPMDarkWakeMaxPowerStateKey
);
5871 OSNumber
* num
= OSDynamicCast(OSNumber
, prop
.get());
5873 actions
->darkWakePowerState
= num
->unsigned32BitValue();
5874 if (actions
->darkWakePowerState
< maxPowerState
) {
5875 flags
|= kPMActionsFlagHasDarkWakePowerState
;
5880 // Find the power connection object that is a child of the PCI host
5881 // bridge, and has a graphics/audio device attached below. Mark the
5882 // power branch for delayed child notifications.
5885 IORegistryEntry
* child
= service
;
5886 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
5888 while (child
!= this) {
5889 if (child
->propertyHasValue("IOPCITunnelled", kOSBooleanTrue
)) {
5890 // Skip delaying notifications and clamping power on external graphics and audio devices.
5891 DLOG("Avoiding delayChildNotification on object 0x%llx. flags: 0x%x\n", service
->getRegistryEntryID(), flags
);
5895 if ((parent
== pciHostBridgeDriver
) ||
5897 if (OSDynamicCast(IOPowerConnection
, child
)) {
5898 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
5899 conn
->delayChildNotification
= true;
5900 DLOG("delayChildNotification for 0x%llx\n", conn
->getRegistryEntryID());
5905 parent
= child
->getParentEntry(gIOPowerPlane
);
5910 DLOG("%s tag flags %x\n", service
->getName(), flags
);
5911 actions
->flags
|= flags
;
5912 actions
->actionPowerChangeOverride
=
5913 OSMemberFunctionCast(
5914 IOPMActionPowerChangeOverride
, this,
5915 &IOPMrootDomain::overridePowerChangeForService
);
5917 if (flags
& kPMActionsFlagIsDisplayWrangler
) {
5918 actions
->actionActivityTickle
=
5919 OSMemberFunctionCast(
5920 IOPMActionActivityTickle
, this,
5921 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
5923 actions
->actionUpdatePowerClient
=
5924 OSMemberFunctionCast(
5925 IOPMActionUpdatePowerClient
, this,
5926 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler
);
5931 // Locate the first PCI host bridge for PMTrace.
5932 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge")) {
5933 IOService
* provider
= service
->getProvider();
5934 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
5935 provider
->inPlane(gIODTPlane
)) {
5936 pciHostBridgeDevice
.reset(provider
, OSNoRetain
);
5937 pciHostBridgeDriver
.reset(service
, OSNoRetain
);
5938 DLOG("PMTrace found PCI host bridge %s->%s\n",
5939 provider
->getName(), service
->getName());
5943 // Tag top-level PCI devices. The order of PMinit() call does not
5944 // change across boots and is used as the PCI bit number.
5945 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice")) {
5946 // Would prefer to check built-in property, but tagPowerPlaneService()
5947 // is called before pciDevice->registerService().
5948 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
5949 if ((parent
== pciHostBridgeDevice
) && service
->propertyExists("acpi-device")) {
5950 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
5952 // Save the assigned bit for fast lookup.
5953 actions
->flags
|= (bit
& kPMActionsPCIBitNumberMask
);
5955 actions
->actionPowerChangeStart
=
5956 OSMemberFunctionCast(
5957 IOPMActionPowerChangeStart
, this,
5958 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
5960 actions
->actionPowerChangeDone
=
5961 OSMemberFunctionCast(
5962 IOPMActionPowerChangeDone
, this,
5963 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
5969 //******************************************************************************
5970 // PM actions for root domain
5971 //******************************************************************************
5974 IOPMrootDomain::overrideOurPowerChange(
5975 IOService
* service
,
5976 IOPMActions
* actions
,
5977 const IOPMRequest
* request
,
5978 IOPMPowerStateIndex
* inOutPowerState
,
5979 IOPMPowerChangeFlags
* inOutChangeFlags
)
5981 uint32_t changeFlags
= *inOutChangeFlags
;
5982 uint32_t desiredPowerState
= (uint32_t) *inOutPowerState
;
5983 uint32_t currentPowerState
= (uint32_t) getPowerState();
5985 if (request
->getTag() == 0) {
5986 // Set a tag for any request that originates from IOServicePM
5987 (const_cast<IOPMRequest
*>(request
))->fTag
= nextRequestTag(kCPSReasonPMInternals
);
5990 DLOG("PowerChangeOverride (%s->%s, %x, 0x%x) tag 0x%x\n",
5991 getPowerStateString(currentPowerState
),
5992 getPowerStateString(desiredPowerState
),
5993 _currentCapability
, changeFlags
,
5996 if ((AOT_STATE
== desiredPowerState
) && (ON_STATE
== currentPowerState
)) {
5997 // Assertion may have been taken in AOT leading to changePowerStateTo(AOT)
5998 *inOutChangeFlags
|= kIOPMNotDone
;
6002 if (changeFlags
& kIOPMParentInitiated
) {
6003 // Root parent is permanently pegged at max power,
6004 // a parent initiated power change is unexpected.
6005 *inOutChangeFlags
|= kIOPMNotDone
;
6009 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
6010 if (lowBatteryCondition
&& (desiredPowerState
< currentPowerState
)) {
6011 // Reject sleep requests when lowBatteryCondition is TRUE to
6012 // avoid racing with the impending system shutdown.
6013 *inOutChangeFlags
|= kIOPMNotDone
;
6018 if (desiredPowerState
< currentPowerState
) {
6019 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
)) {
6020 // Root domain is dropping power state from ON->SLEEP.
6021 // If system is in full wake, first enter dark wake by
6022 // converting the power drop to a capability change.
6023 // Once in dark wake, transition to sleep state ASAP.
6025 darkWakeToSleepASAP
= true;
6027 // Drop graphics and audio capability
6028 _desiredCapability
&= ~(
6029 kIOPMSystemCapabilityGraphics
|
6030 kIOPMSystemCapabilityAudio
);
6032 // Convert to capability change (ON->ON)
6033 *inOutPowerState
= getRUN_STATE();
6034 *inOutChangeFlags
|= kIOPMSynchronize
;
6036 // Revert device desire from SLEEP to ON
6037 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonPowerOverride
);
6039 // System is already in dark wake, ok to drop power state.
6040 // Broadcast root power down to entire tree.
6041 *inOutChangeFlags
|= kIOPMRootChangeDown
;
6043 } else if (desiredPowerState
> currentPowerState
) {
6044 if ((_currentCapability
& kIOPMSystemCapabilityCPU
) == 0) {
6045 // Broadcast power up when waking from sleep, but not for the
6046 // initial power change at boot by checking for cpu capability.
6047 *inOutChangeFlags
|= kIOPMRootChangeUp
;
6053 IOPMrootDomain::handleOurPowerChangeStart(
6054 IOService
* service
,
6055 IOPMActions
* actions
,
6056 const IOPMRequest
* request
,
6057 IOPMPowerStateIndex newPowerState
,
6058 IOPMPowerChangeFlags
* inOutChangeFlags
)
6060 IOPMRequestTag requestTag
= request
->getTag();
6061 IOPMRequestTag sleepReason
;
6063 uint32_t changeFlags
= *inOutChangeFlags
;
6064 uint32_t currentPowerState
= (uint32_t) getPowerState();
6065 bool publishSleepReason
= false;
6067 // Check if request has a valid sleep reason
6068 sleepReason
= REQUEST_TAG_TO_REASON(requestTag
);
6069 if (sleepReason
< kIOPMSleepReasonClamshell
) {
6070 sleepReason
= kIOPMSleepReasonIdle
;
6073 _systemTransitionType
= kSystemTransitionNone
;
6074 _systemMessageClientMask
= 0;
6075 capabilityLoss
= false;
6076 toldPowerdCapWillChange
= false;
6078 // Emergency notifications may arrive after the initial sleep request
6079 // has been queued. Override the sleep reason so powerd and others can
6080 // treat this as an emergency sleep.
6081 if (lowBatteryCondition
) {
6082 sleepReason
= kIOPMSleepReasonLowPower
;
6083 } else if (thermalEmergencyState
) {
6084 sleepReason
= kIOPMSleepReasonThermalEmergency
;
6087 // 1. Explicit capability change.
6088 if (changeFlags
& kIOPMSynchronize
) {
6089 if (newPowerState
== ON_STATE
) {
6090 if (changeFlags
& kIOPMSyncNoChildNotify
) {
6091 _systemTransitionType
= kSystemTransitionNewCapClient
;
6093 _systemTransitionType
= kSystemTransitionCapability
;
6097 // 2. Going to sleep (cancellation still possible).
6098 else if (newPowerState
< currentPowerState
) {
6099 _systemTransitionType
= kSystemTransitionSleep
;
6101 // 3. Woke from (idle or demand) sleep.
6102 else if (!systemBooting
&&
6103 (changeFlags
& kIOPMSelfInitiated
) &&
6104 (newPowerState
> currentPowerState
)) {
6105 _systemTransitionType
= kSystemTransitionWake
;
6106 _desiredCapability
= kIOPMSystemCapabilityCPU
| kIOPMSystemCapabilityNetwork
;
6108 // Early exit from dark wake to full (e.g. LID open)
6109 if (kFullWakeReasonNone
!= fullWakeReason
) {
6110 _desiredCapability
|= (
6111 kIOPMSystemCapabilityGraphics
|
6112 kIOPMSystemCapabilityAudio
);
6114 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
6115 if (fullWakeReason
== kFullWakeReasonLocalUser
) {
6116 darkWakeExit
= true;
6117 darkWakeToSleepASAP
= false;
6118 setProperty(kIOPMRootDomainWakeTypeKey
, isRTCAlarmWake
?
6119 kIOPMRootDomainWakeTypeAlarm
: kIOPMRootDomainWakeTypeUser
);
6124 IOHibernateSetWakeCapabilities(_desiredCapability
);
6128 // Update pending wake capability at the beginning of every
6129 // state transition (including synchronize). This will become
6130 // the current capability at the end of the transition.
6132 if (kSystemTransitionSleep
== _systemTransitionType
) {
6133 _pendingCapability
= 0;
6134 capabilityLoss
= true;
6135 } else if (kSystemTransitionNewCapClient
!= _systemTransitionType
) {
6136 _pendingCapability
= _desiredCapability
|
6137 kIOPMSystemCapabilityCPU
|
6138 kIOPMSystemCapabilityNetwork
;
6140 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
) {
6141 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
6144 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
6145 (_pendingCapability
== _currentCapability
)) {
6146 // Cancel the PM state change.
6147 _systemTransitionType
= kSystemTransitionNone
;
6148 *inOutChangeFlags
|= kIOPMNotDone
;
6150 if (__builtin_popcount(_pendingCapability
) <
6151 __builtin_popcount(_currentCapability
)) {
6152 capabilityLoss
= true;
6156 // 1. Capability change.
6157 if (kSystemTransitionCapability
== _systemTransitionType
) {
6158 // Dark to Full transition.
6159 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
)) {
6160 tracePoint( kIOPMTracePointDarkWakeExit
);
6162 #if defined(XNU_TARGET_OS_OSX)
6163 // rdar://problem/65627936
6164 // When a dark->full wake promotion is scheduled before an ON->SLEEP
6165 // power state drop, invalidate any request to drop power state already
6166 // in the queue, including the override variant, unless full wake cannot
6167 // be sustained. Any power state drop queued after this SustainFullWake
6168 // request will not be affected.
6169 if (checkSystemCanSustainFullWake()) {
6170 changePowerStateWithOverrideTo(getRUN_STATE(), kCPSReasonSustainFullWake
);
6174 willEnterFullWake();
6177 // Full to Dark transition.
6178 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
)) {
6179 // Clear previous stats
6180 IOLockLock(pmStatsLock
);
6181 if (pmStatsAppResponses
) {
6182 pmStatsAppResponses
= OSArray::withCapacity(5);
6184 IOLockUnlock(pmStatsLock
);
6186 tracePoint( kIOPMTracePointDarkWakeEntry
);
6187 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
6188 _systemMessageClientMask
= kSystemMessageClientPowerd
|
6189 kSystemMessageClientLegacyApp
;
6192 // Prevent user active transitions before notifying clients
6193 // that system will sleep.
6194 preventTransitionToUserActive(true);
6196 IOService::setAdvisoryTickleEnable( false );
6198 // Publish the sleep reason for full to dark wake
6199 publishSleepReason
= true;
6200 lastSleepReason
= fullToDarkReason
= sleepReason
;
6202 // Publish a UUID for the Sleep --> Wake cycle
6203 handlePublishSleepWakeUUID(true);
6204 if (sleepDelaysReport
) {
6205 clock_get_uptime(&ts_sleepStart
);
6206 DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart
);
6209 darkWakeExit
= false;
6213 else if (kSystemTransitionSleep
== _systemTransitionType
) {
6214 // Beginning of a system sleep transition.
6215 // Cancellation is still possible.
6216 tracePoint( kIOPMTracePointSleepStarted
);
6218 _systemMessageClientMask
= kSystemMessageClientAll
;
6219 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0) {
6220 _systemMessageClientMask
&= ~kSystemMessageClientLegacyApp
;
6222 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0) {
6223 // Kernel priority clients are only notified on the initial
6224 // transition to full wake, so don't notify them unless system
6225 // has gained graphics capability since the last system wake.
6226 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
6228 // System was in full wake, but the downwards power transition is driven
6229 // by a request that originates from IOServicePM, so it isn't tagged with
6230 // a valid system sleep reason.
6231 if (REQUEST_TAG_TO_REASON(requestTag
) == kCPSReasonPMInternals
) {
6232 // Publish the same reason for full to dark
6233 sleepReason
= fullToDarkReason
;
6237 gIOHibernateState
= 0;
6240 // Record the reason for dark wake back to sleep
6241 // System may not have ever achieved full wake
6243 publishSleepReason
= true;
6244 lastSleepReason
= sleepReason
;
6245 if (sleepDelaysReport
) {
6246 clock_get_uptime(&ts_sleepStart
);
6247 DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart
);
6251 else if (kSystemTransitionWake
== _systemTransitionType
) {
6252 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
6253 // Clear stats about sleep
6255 if (AOT_STATE
== newPowerState
) {
6256 _pendingCapability
= 0;
6259 if (AOT_STATE
== currentPowerState
) {
6260 // Wake events are no longer accepted after waking to AOT_STATE.
6261 // Re-enable wake event acceptance to append wake events claimed
6262 // during the AOT to ON_STATE transition.
6263 acceptSystemWakeEvents(kAcceptSystemWakeEvents_Reenable
);
6266 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
) {
6267 willEnterFullWake();
6271 // The only location where the sleep reason is published. At this point
6272 // sleep can still be cancelled, but sleep reason should be published
6273 // early for logging purposes.
6275 if (publishSleepReason
) {
6276 static const char * IOPMSleepReasons
[] =
6278 kIOPMClamshellSleepKey
,
6279 kIOPMPowerButtonSleepKey
,
6280 kIOPMSoftwareSleepKey
,
6281 kIOPMOSSwitchHibernationKey
,
6283 kIOPMLowPowerSleepKey
,
6284 kIOPMThermalEmergencySleepKey
,
6285 kIOPMMaintenanceSleepKey
,
6286 kIOPMSleepServiceExitKey
,
6287 kIOPMDarkWakeThermalEmergencyKey
,
6288 kIOPMNotificationWakeExitKey
6291 // Record sleep cause in IORegistry
6292 uint32_t reasonIndex
= sleepReason
- kIOPMSleepReasonClamshell
;
6293 if (reasonIndex
< sizeof(IOPMSleepReasons
) / sizeof(IOPMSleepReasons
[0])) {
6294 DLOG("sleep reason %s\n", IOPMSleepReasons
[reasonIndex
]);
6295 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[reasonIndex
]);
6299 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
6300 (kSystemTransitionNewCapClient
!= _systemTransitionType
)) {
6301 _systemStateGeneration
++;
6302 systemDarkWake
= false;
6304 DLOG("=== START (%s->%s, %x->%x, 0x%x) gen %u, msg %x, tag %x\n",
6305 getPowerStateString(currentPowerState
),
6306 getPowerStateString((uint32_t) newPowerState
),
6307 _currentCapability
, _pendingCapability
,
6308 *inOutChangeFlags
, _systemStateGeneration
, _systemMessageClientMask
,
6312 if ((AOT_STATE
== newPowerState
) && (SLEEP_STATE
!= currentPowerState
)) {
6313 panic("illegal AOT entry from %s", getPowerStateString(currentPowerState
));
6315 if (_aotNow
&& (ON_STATE
== newPowerState
)) {
6317 aotShouldExit(false, true);
6324 IOPMrootDomain::handleOurPowerChangeDone(
6325 IOService
* service
,
6326 IOPMActions
* actions
,
6327 const IOPMRequest
* request
,
6328 IOPMPowerStateIndex oldPowerState
,
6329 IOPMPowerChangeFlags changeFlags
)
6331 if (kSystemTransitionNewCapClient
== _systemTransitionType
) {
6332 _systemTransitionType
= kSystemTransitionNone
;
6336 if (_systemTransitionType
!= kSystemTransitionNone
) {
6337 uint32_t currentPowerState
= (uint32_t) getPowerState();
6339 if (changeFlags
& kIOPMNotDone
) {
6340 // Power down was cancelled or vetoed.
6341 _pendingCapability
= _currentCapability
;
6342 lastSleepReason
= 0;
6344 // When sleep is cancelled or reverted, don't report
6345 // the target (lower) power state as the previous state.
6346 oldPowerState
= currentPowerState
;
6348 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
) &&
6349 CAP_CURRENT(kIOPMSystemCapabilityCPU
)) {
6350 #if defined(XNU_TARGET_OS_OSX)
6351 pmPowerStateQueue
->submitPowerEvent(
6352 kPowerEventPolicyStimulus
,
6353 (void *) kStimulusDarkWakeReentry
,
6354 _systemStateGeneration
);
6355 #else /* !defined(XNU_TARGET_OS_OSX) */
6356 // On embedded, there are no factors that can prolong a
6357 // "darkWake" when a power down is vetoed. We need to
6358 // promote to "fullWake" at least once so that factors
6359 // that prevent idle sleep can assert themselves if required
6360 pmPowerStateQueue
->submitPowerEvent(
6361 kPowerEventPolicyStimulus
,
6362 (void *) kStimulusDarkWakeActivityTickle
);
6363 #endif /* !defined(XNU_TARGET_OS_OSX) */
6366 // Revert device desire to max.
6367 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonPowerDownCancel
);
6369 // Send message on dark wake to full wake promotion.
6370 // tellChangeUp() handles the normal SLEEP->ON case.
6372 if (kSystemTransitionCapability
== _systemTransitionType
) {
6373 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
)) {
6374 lastSleepReason
= 0; // stop logging wrangler tickles
6375 tellClients(kIOMessageSystemHasPoweredOn
);
6377 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
)) {
6378 // Going dark, reset full wake state
6379 // userIsActive will be cleared by wrangler powering down
6380 fullWakeReason
= kFullWakeReasonNone
;
6382 if (ts_sleepStart
) {
6383 clock_get_uptime(&wake2DarkwakeDelay
);
6384 SUB_ABSOLUTETIME(&wake2DarkwakeDelay
, &ts_sleepStart
);
6385 DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay
);
6391 // Reset state after exiting from dark wake.
6393 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
6394 CAP_LOSS(kIOPMSystemCapabilityCPU
)) {
6395 darkWakeMaintenance
= false;
6396 darkWakeToSleepASAP
= false;
6397 pciCantSleepValid
= false;
6398 darkWakeSleepService
= false;
6400 if (CAP_LOSS(kIOPMSystemCapabilityCPU
)) {
6401 // Remove the influence of display power assertion
6402 // before next system wake.
6404 wrangler
->changePowerStateForRootDomain(
6405 kWranglerPowerStateMin
);
6407 removeProperty(gIOPMUserTriggeredFullWakeKey
.get());
6411 // Entered dark mode.
6413 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
6414 (_pendingCapability
& kIOPMSystemCapabilityCPU
)) {
6415 // Queue an evaluation of whether to remain in dark wake,
6416 // and for how long. This serves the purpose of draining
6417 // any assertions from the queue.
6419 pmPowerStateQueue
->submitPowerEvent(
6420 kPowerEventPolicyStimulus
,
6421 (void *) kStimulusDarkWakeEntry
,
6422 _systemStateGeneration
);
6426 DLOG("=== FINISH (%s->%s, %x->%x, 0x%x) gen %u, msg %x, tag %x\n",
6427 getPowerStateString((uint32_t) oldPowerState
), getPowerStateString(currentPowerState
),
6428 _currentCapability
, _pendingCapability
,
6429 changeFlags
, _systemStateGeneration
, _systemMessageClientMask
,
6432 if ((currentPowerState
== ON_STATE
) && pmAssertions
) {
6433 pmAssertions
->reportCPUBitAccounting();
6436 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
) {
6438 #if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
6439 if (clamshellExists
&& fullWakeThreadCall
) {
6440 AbsoluteTime deadline
;
6441 clock_interval_to_deadline(DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
, kSecondScale
, &deadline
);
6442 thread_call_enter_delayed(fullWakeThreadCall
, deadline
);
6445 } else if (CAP_GAIN(kIOPMSystemCapabilityCPU
)) {
6449 // Update current system capability.
6450 if (_currentCapability
!= _pendingCapability
) {
6451 _currentCapability
= _pendingCapability
;
6454 // Update highest system capability.
6456 _highestCapability
|= _currentCapability
;
6458 if (darkWakePostTickle
&&
6459 (kSystemTransitionWake
== _systemTransitionType
) &&
6460 (gDarkWakeFlags
& kDarkWakeFlagPromotionMask
) ==
6461 kDarkWakeFlagPromotionLate
) {
6462 darkWakePostTickle
= false;
6464 } else if (darkWakeExit
) {
6465 requestFullWake( kFullWakeReasonLocalUser
);
6468 // Reset tracepoint at completion of capability change,
6469 // completion of wake transition, and aborted sleep transition.
6471 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
6472 (_systemTransitionType
== kSystemTransitionWake
) ||
6473 ((_systemTransitionType
== kSystemTransitionSleep
) &&
6474 (changeFlags
& kIOPMNotDone
))) {
6475 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
6476 tracePoint( kIOPMTracePointSystemUp
);
6479 _systemTransitionType
= kSystemTransitionNone
;
6480 _systemMessageClientMask
= 0;
6481 toldPowerdCapWillChange
= false;
6483 darkWakeLogClamp
= false;
6485 if (lowBatteryCondition
) {
6486 privateSleepSystem(kIOPMSleepReasonLowPower
);
6487 } else if (thermalEmergencyState
) {
6488 privateSleepSystem(kIOPMSleepReasonThermalEmergency
);
6489 } else if ((fullWakeReason
== kFullWakeReasonDisplayOn
) && !displayPowerOnRequested
) {
6490 // Request for full wake is removed while system is waking up to full wake
6491 DLOG("DisplayOn fullwake request is removed\n");
6492 handleSetDisplayPowerOn(false);
6495 if ((gClamshellFlags
& kClamshell_WAR_47715679
) && isRTCAlarmWake
) {
6496 pmPowerStateQueue
->submitPowerEvent(
6497 kPowerEventReceivedPowerNotification
, (void *)(uintptr_t) kLocalEvalClamshellCommand
);
6502 //******************************************************************************
6503 // PM actions for graphics and audio.
6504 //******************************************************************************
6507 IOPMrootDomain::overridePowerChangeForService(
6508 IOService
* service
,
6509 IOPMActions
* actions
,
6510 const IOPMRequest
* request
,
6511 IOPMPowerStateIndex
* inOutPowerState
,
6512 IOPMPowerChangeFlags
* inOutChangeFlags
)
6514 uint32_t powerState
= (uint32_t) *inOutPowerState
;
6515 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
6516 const uint32_t actionFlags
= actions
->flags
;
6518 if (kSystemTransitionNone
== _systemTransitionType
) {
6519 // Not in midst of a system transition.
6520 // Do not set kPMActionsStatePowerClamped.
6521 } else if ((actions
->state
& kPMActionsStatePowerClamped
) == 0) {
6522 bool enableClamp
= false;
6524 // For most drivers, enable the clamp during ON->Dark transition
6525 // which has the kIOPMSynchronize flag set in changeFlags.
6526 if ((actionFlags
& kPMActionsFlagIsDisplayWrangler
) &&
6527 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
6528 (changeFlags
& kIOPMSynchronize
)) {
6530 } else if ((actionFlags
& kPMActionsFlagIsAudioDriver
) &&
6531 ((gDarkWakeFlags
& kDarkWakeFlagAudioNotSuppressed
) == 0) &&
6532 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0) &&
6533 (changeFlags
& kIOPMSynchronize
)) {
6535 } else if ((actionFlags
& kPMActionsFlagHasDarkWakePowerState
) &&
6536 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
6537 (changeFlags
& kIOPMSynchronize
)) {
6539 } else if ((actionFlags
& kPMActionsFlagIsGraphicsDriver
) &&
6540 (_systemTransitionType
== kSystemTransitionSleep
)) {
6541 // For graphics drivers, clamp power when entering
6542 // system sleep. Not when dropping to dark wake.
6547 actions
->state
|= kPMActionsStatePowerClamped
;
6548 DLOG("power clamp enabled %s %qx, pendingCap 0x%x, ps %d, cflags 0x%x\n",
6549 service
->getName(), service
->getRegistryEntryID(),
6550 _pendingCapability
, powerState
, changeFlags
);
6552 } else if ((actions
->state
& kPMActionsStatePowerClamped
) != 0) {
6553 bool disableClamp
= false;
6555 if ((actionFlags
& (
6556 kPMActionsFlagIsDisplayWrangler
|
6557 kPMActionsFlagIsGraphicsDriver
)) &&
6558 (_pendingCapability
& kIOPMSystemCapabilityGraphics
)) {
6559 disableClamp
= true;
6560 } else if ((actionFlags
& kPMActionsFlagIsAudioDriver
) &&
6561 (_pendingCapability
& kIOPMSystemCapabilityAudio
)) {
6562 disableClamp
= true;
6563 } else if ((actionFlags
& kPMActionsFlagHasDarkWakePowerState
) &&
6564 (_pendingCapability
& kIOPMSystemCapabilityGraphics
)) {
6565 disableClamp
= true;
6569 actions
->state
&= ~kPMActionsStatePowerClamped
;
6570 DLOG("power clamp removed %s %qx, pendingCap 0x%x, ps %d, cflags 0x%x\n",
6571 service
->getName(), service
->getRegistryEntryID(),
6572 _pendingCapability
, powerState
, changeFlags
);
6576 if (actions
->state
& kPMActionsStatePowerClamped
) {
6577 uint32_t maxPowerState
= 0;
6579 // Determine the max power state allowed when clamp is enabled
6580 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
)) {
6581 // Parent intiated power state changes
6582 if ((service
->getPowerState() > maxPowerState
) &&
6583 (actionFlags
& kPMActionsFlagIsDisplayWrangler
)) {
6586 // Remove lingering effects of any tickle before entering
6587 // dark wake. It will take a new tickle to return to full
6588 // wake, so the existing tickle state is useless.
6590 if (changeFlags
& kIOPMDomainDidChange
) {
6591 *inOutChangeFlags
|= kIOPMExpireIdleTimer
;
6593 } else if (actionFlags
& kPMActionsFlagIsGraphicsDriver
) {
6595 } else if (actionFlags
& kPMActionsFlagHasDarkWakePowerState
) {
6596 maxPowerState
= actions
->darkWakePowerState
;
6599 // Deny all self-initiated changes when power is limited.
6600 // Wrangler tickle should never defeat the limiter.
6601 maxPowerState
= service
->getPowerState();
6604 if (powerState
> maxPowerState
) {
6605 DLOG("power clamped %s %qx, ps %u->%u, cflags 0x%x)\n",
6606 service
->getName(), service
->getRegistryEntryID(),
6607 powerState
, maxPowerState
, changeFlags
);
6608 *inOutPowerState
= maxPowerState
;
6610 if (darkWakePostTickle
&&
6611 (actionFlags
& kPMActionsFlagIsDisplayWrangler
) &&
6612 (changeFlags
& kIOPMDomainWillChange
) &&
6613 ((gDarkWakeFlags
& kDarkWakeFlagPromotionMask
) ==
6614 kDarkWakeFlagPromotionEarly
)) {
6615 darkWakePostTickle
= false;
6620 if (!darkWakePowerClamped
&& (changeFlags
& kIOPMDomainDidChange
)) {
6621 if (darkWakeLogClamp
) {
6625 clock_get_uptime(&now
);
6626 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
6627 absolutetime_to_nanoseconds(now
, &nsec
);
6628 DLOG("dark wake power clamped after %u ms\n",
6629 ((int)((nsec
) / NSEC_PER_MSEC
)));
6631 darkWakePowerClamped
= true;
6637 IOPMrootDomain::handleActivityTickleForDisplayWrangler(
6638 IOService
* service
,
6639 IOPMActions
* actions
)
6641 #if DISPLAY_WRANGLER_PRESENT
6642 // Warning: Not running in PM work loop context - don't modify state !!!
6643 // Trap tickle directed to IODisplayWrangler while running with graphics
6644 // capability suppressed.
6646 assert(service
== wrangler
);
6648 clock_get_uptime(&userActivityTime
);
6649 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
6650 || (lastSleepReason
== kIOPMSleepReasonMaintenance
)
6651 || (lastSleepReason
== kIOPMSleepReasonSoftware
));
6653 userActivityCount
++;
6654 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
6655 userActivityCount
, lastSleepReason
);
6658 if (!darkWakeExit
&& ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0)) {
6659 DLOG("display wrangler tickled\n");
6660 if (kIOLogPMRootDomain
& gIOKitDebug
) {
6661 OSReportWithBacktrace("Dark wake display tickle");
6663 if (pmPowerStateQueue
) {
6664 pmPowerStateQueue
->submitPowerEvent(
6665 kPowerEventPolicyStimulus
,
6666 (void *) kStimulusDarkWakeActivityTickle
,
6667 true /* set wake type */ );
6670 #endif /* DISPLAY_WRANGLER_PRESENT */
6674 IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
6675 IOService
* service
,
6676 IOPMActions
* actions
,
6677 const OSSymbol
* powerClient
,
6678 IOPMPowerStateIndex oldPowerState
,
6679 IOPMPowerStateIndex newPowerState
)
6681 #if DISPLAY_WRANGLER_PRESENT
6682 assert(service
== wrangler
);
6684 // This function implements half of the user active detection
6685 // by monitoring changes to the display wrangler's device desire.
6687 // User becomes active when either:
6688 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
6689 // in max power state. This desire change in absence of a power state
6690 // change is detected within. This handles the case when user becomes
6691 // active while the display is already lit by setDisplayPowerOn().
6693 // 2. Power state change to max, and DeviceDesire is also at max.
6694 // Handled by displayWranglerNotification().
6696 // User becomes inactive when DeviceDesire drops to sleep state or below.
6698 DLOG("wrangler %s (ps %u, %u->%u)\n",
6699 powerClient
->getCStringNoCopy(),
6700 (uint32_t) service
->getPowerState(),
6701 (uint32_t) oldPowerState
, (uint32_t) newPowerState
);
6703 if (powerClient
== gIOPMPowerClientDevice
) {
6704 if ((newPowerState
> oldPowerState
) &&
6705 (newPowerState
== kWranglerPowerStateMax
) &&
6706 (service
->getPowerState() == kWranglerPowerStateMax
)) {
6707 evaluatePolicy( kStimulusEnterUserActiveState
);
6708 } else if ((newPowerState
< oldPowerState
) &&
6709 (newPowerState
<= kWranglerPowerStateSleep
)) {
6710 evaluatePolicy( kStimulusLeaveUserActiveState
);
6714 if (newPowerState
<= kWranglerPowerStateSleep
) {
6715 evaluatePolicy( kStimulusDisplayWranglerSleep
);
6716 } else if (newPowerState
== kWranglerPowerStateMax
) {
6717 evaluatePolicy( kStimulusDisplayWranglerWake
);
6719 #endif /* DISPLAY_WRANGLER_PRESENT */
6722 //******************************************************************************
6723 // User active state management
6724 //******************************************************************************
6727 IOPMrootDomain::preventTransitionToUserActive( bool prevent
)
6729 #if DISPLAY_WRANGLER_PRESENT
6730 _preventUserActive
= prevent
;
6731 if (wrangler
&& !_preventUserActive
) {
6732 // Allowing transition to user active, but the wrangler may have
6733 // already powered ON in case of sleep cancel/revert. Poll the
6734 // same conditions checked for in displayWranglerNotification()
6735 // to bring the user active state up to date.
6737 if ((wrangler
->getPowerState() == kWranglerPowerStateMax
) &&
6738 (wrangler
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
6739 kWranglerPowerStateMax
)) {
6740 evaluatePolicy( kStimulusEnterUserActiveState
);
6743 #endif /* DISPLAY_WRANGLER_PRESENT */
6746 //******************************************************************************
6747 // Approve usage of delayed child notification by PM.
6748 //******************************************************************************
6751 IOPMrootDomain::shouldDelayChildNotification(
6752 IOService
* service
)
6754 if ((kFullWakeReasonNone
== fullWakeReason
) &&
6755 (kSystemTransitionWake
== _systemTransitionType
)) {
6756 DLOG("%s: delay child notify\n", service
->getName());
6762 //******************************************************************************
6763 // PM actions for PCI device.
6764 //******************************************************************************
6767 IOPMrootDomain::handlePowerChangeStartForPCIDevice(
6768 IOService
* service
,
6769 IOPMActions
* actions
,
6770 const IOPMRequest
* request
,
6771 IOPMPowerStateIndex powerState
,
6772 IOPMPowerChangeFlags
* inOutChangeFlags
)
6774 pmTracer
->tracePCIPowerChange(
6775 PMTraceWorker::kPowerChangeStart
,
6776 service
, *inOutChangeFlags
,
6777 (actions
->flags
& kPMActionsPCIBitNumberMask
));
6781 IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
6782 IOService
* service
,
6783 IOPMActions
* actions
,
6784 const IOPMRequest
* request
,
6785 IOPMPowerStateIndex powerState
,
6786 IOPMPowerChangeFlags changeFlags
)
6788 pmTracer
->tracePCIPowerChange(
6789 PMTraceWorker::kPowerChangeCompleted
,
6790 service
, changeFlags
,
6791 (actions
->flags
& kPMActionsPCIBitNumberMask
));
6794 //******************************************************************************
6797 // Override IOService::registerInterest() for root domain clients.
6798 //******************************************************************************
6800 class IOPMServiceInterestNotifier
: public _IOServiceInterestNotifier
6802 friend class IOPMrootDomain
;
6803 OSDeclareDefaultStructors(IOPMServiceInterestNotifier
);
6806 uint32_t ackTimeoutCnt
;
6807 uint32_t msgType
; // Message pending ack
6809 uint32_t maxMsgDelayMS
;
6810 uint32_t maxAckDelayMS
;
6811 uint64_t msgAbsTime
;
6814 OSSharedPtr
<const OSSymbol
> identifier
;
6815 OSSharedPtr
<const OSSymbol
> clientName
;
6818 OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier
, _IOServiceInterestNotifier
)
6820 OSSharedPtr
<IONotifier
>
6821 IOPMrootDomain::registerInterest(
6822 const OSSymbol
* typeOfInterest
,
6823 IOServiceInterestHandler handler
,
6824 void * target
, void * ref
)
6826 IOPMServiceInterestNotifier
* notifier
;
6827 bool isSystemCapabilityClient
;
6828 bool isKernelCapabilityClient
;
6829 IOReturn rc
= kIOReturnError
;
6831 isSystemCapabilityClient
= typeOfInterest
&&
6832 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
6834 isKernelCapabilityClient
= typeOfInterest
&&
6835 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
6837 if (isSystemCapabilityClient
) {
6838 typeOfInterest
= gIOAppPowerStateInterest
;
6841 notifier
= new IOPMServiceInterestNotifier
;
6846 if (notifier
->init()) {
6847 rc
= super::registerInterestForNotifier(notifier
, typeOfInterest
, handler
, target
, ref
);
6849 if (rc
!= kIOReturnSuccess
) {
6853 notifier
->ackTimeoutCnt
= 0;
6855 if (pmPowerStateQueue
) {
6856 if (isSystemCapabilityClient
) {
6858 if (pmPowerStateQueue
->submitPowerEvent(
6859 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false) {
6860 notifier
->release();
6864 if (isKernelCapabilityClient
) {
6866 if (pmPowerStateQueue
->submitPowerEvent(
6867 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false) {
6868 notifier
->release();
6873 OSSharedPtr
<OSData
> data
;
6874 uint8_t *uuid
= NULL
;
6875 OSSharedPtr
<OSKext
> kext
= OSKext::lookupKextWithAddress((vm_address_t
)handler
);
6877 data
= kext
->copyUUID();
6879 if (data
&& (data
->getLength() == sizeof(uuid_t
))) {
6880 uuid
= (uint8_t *)(data
->getBytesNoCopy());
6882 notifier
->uuid0
= ((uint64_t)(uuid
[0]) << 56) | ((uint64_t)(uuid
[1]) << 48) | ((uint64_t)(uuid
[2]) << 40) |
6883 ((uint64_t)(uuid
[3]) << 32) | ((uint64_t)(uuid
[4]) << 24) | ((uint64_t)(uuid
[5]) << 16) |
6884 ((uint64_t)(uuid
[6]) << 8) | (uuid
[7]);
6885 notifier
->uuid1
= ((uint64_t)(uuid
[8]) << 56) | ((uint64_t)(uuid
[9]) << 48) | ((uint64_t)(uuid
[10]) << 40) |
6886 ((uint64_t)(uuid
[11]) << 32) | ((uint64_t)(uuid
[12]) << 24) | ((uint64_t)(uuid
[13]) << 16) |
6887 ((uint64_t)(uuid
[14]) << 8) | (uuid
[15]);
6889 notifier
->identifier
= copyKextIdentifierWithAddress((vm_address_t
) handler
);
6891 return OSSharedPtr
<IOPMServiceInterestNotifier
>(notifier
, OSNoRetain
);
6894 //******************************************************************************
6895 // systemMessageFilter
6897 //******************************************************************************
6900 IOPMrootDomain::systemMessageFilter(
6901 void * object
, void * arg1
, void * arg2
, void * arg3
)
6903 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
6904 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
6905 bool isCapClient
= false;
6907 IOPMServiceInterestNotifier
*notifier
;
6909 notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, (OSObject
*)object
);
6912 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
6913 (!isCapMsg
|| !_joinedCapabilityClients
||
6914 !_joinedCapabilityClients
->containsObject((OSObject
*) object
))) {
6918 // Capability change message for app and kernel clients.
6922 if ((context
->notifyType
== kNotifyPriority
) ||
6923 (context
->notifyType
== kNotifyCapabilityChangePriority
)) {
6927 // powerd's systemCapabilityNotifier
6928 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
6929 (object
== (void *) systemCapabilityNotifier
.get())) {
6935 IOPMSystemCapabilityChangeParameters
* capArgs
=
6936 (IOPMSystemCapabilityChangeParameters
*) arg2
;
6938 if (kSystemTransitionNewCapClient
== _systemTransitionType
) {
6939 capArgs
->fromCapabilities
= 0;
6940 capArgs
->toCapabilities
= _currentCapability
;
6941 capArgs
->changeFlags
= 0;
6943 capArgs
->fromCapabilities
= _currentCapability
;
6944 capArgs
->toCapabilities
= _pendingCapability
;
6946 if (context
->isPreChange
) {
6947 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
6949 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
6952 if ((object
== (void *) systemCapabilityNotifier
.get()) &&
6953 context
->isPreChange
) {
6954 toldPowerdCapWillChange
= true;
6958 // Capability change messages only go to the PM configd plugin.
6959 // Wait for response post-change if capabilitiy is increasing.
6960 // Wait for response pre-change if capability is decreasing.
6962 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
6963 ((capabilityLoss
&& context
->isPreChange
) ||
6964 (!capabilityLoss
&& !context
->isPreChange
))) {
6965 // app has not replied yet, wait for it
6966 *((OSObject
**) arg3
) = kOSBooleanFalse
;
6973 // Capability client will always see kIOMessageCanSystemSleep,
6974 // even for demand sleep. It will also have a chance to veto
6975 // sleep one last time after all clients have responded to
6976 // kIOMessageSystemWillSleep
6978 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
6979 (kIOMessageSystemWillNotSleep
== context
->messageType
)) {
6980 if (object
== (OSObject
*) systemCapabilityNotifier
.get()) {
6985 // Not idle sleep, don't ask apps.
6986 if (context
->changeFlags
& kIOPMSkipAskPowerDown
) {
6991 if (kIOPMMessageLastCallBeforeSleep
== context
->messageType
) {
6992 if ((object
== (OSObject
*) systemCapabilityNotifier
.get()) &&
6993 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) &&
6994 (fullToDarkReason
== kIOPMSleepReasonIdle
)) {
7000 // Reject capability change messages for legacy clients.
7001 // Reject legacy system sleep messages for capability client.
7003 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
.get())) {
7007 // Filter system sleep messages.
7009 if ((context
->notifyType
== kNotifyApps
) &&
7010 (_systemMessageClientMask
& kSystemMessageClientLegacyApp
)) {
7015 if (notifier
->ackTimeoutCnt
>= 3) {
7016 *((OSObject
**) arg3
) = kOSBooleanFalse
;
7018 *((OSObject
**) arg3
) = kOSBooleanTrue
;
7022 } else if ((context
->notifyType
== kNotifyPriority
) &&
7023 (_systemMessageClientMask
& kSystemMessageClientKernel
)) {
7028 if (allow
&& isCapMsg
&& _joinedCapabilityClients
) {
7029 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
7030 if (_joinedCapabilityClients
->getCount() == 0) {
7031 DLOG("destroyed capability client set %p\n",
7032 OBFUSCATE(_joinedCapabilityClients
.get()));
7033 _joinedCapabilityClients
.reset();
7037 notifier
->msgType
= context
->messageType
;
7043 //******************************************************************************
7044 // setMaintenanceWakeCalendar
7046 //******************************************************************************
7049 IOPMrootDomain::setMaintenanceWakeCalendar(
7050 const IOPMCalendarStruct
* calendar
)
7052 OSSharedPtr
<OSData
> data
;
7056 return kIOReturnBadArgument
;
7059 data
= OSData::withBytes((void *) calendar
, sizeof(*calendar
));
7061 return kIOReturnNoMemory
;
7064 if (kPMCalendarTypeMaintenance
== calendar
->selector
) {
7065 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
.get(), data
.get());
7066 } else if (kPMCalendarTypeSleepService
== calendar
->selector
) {
7067 ret
= setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey
.get(), data
.get());
7074 // MARK: Display Wrangler
7076 //******************************************************************************
7077 // displayWranglerNotification
7079 // Handle the notification when the IODisplayWrangler changes power state.
7080 //******************************************************************************
7083 IOPMrootDomain::displayWranglerNotification(
7084 void * target
, void * refCon
,
7085 UInt32 messageType
, IOService
* service
,
7086 void * messageArgument
, vm_size_t argSize
)
7088 #if DISPLAY_WRANGLER_PRESENT
7089 IOPMPowerStateIndex displayPowerState
;
7090 IOPowerStateChangeNotification
* params
=
7091 (IOPowerStateChangeNotification
*) messageArgument
;
7093 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
7094 (messageType
!= kIOMessageDeviceHasPoweredOn
)) {
7095 return kIOReturnUnsupported
;
7100 return kIOReturnUnsupported
;
7103 displayPowerState
= params
->stateNumber
;
7104 DLOG("wrangler %s ps %d\n",
7105 getIOMessageString(messageType
), (uint32_t) displayPowerState
);
7107 switch (messageType
) {
7108 case kIOMessageDeviceWillPowerOff
:
7109 // Display wrangler has dropped power due to display idle
7110 // or force system sleep.
7112 // 4 Display ON kWranglerPowerStateMax
7113 // 3 Display Dim kWranglerPowerStateDim
7114 // 2 Display Sleep kWranglerPowerStateSleep
7115 // 1 Not visible to user
7116 // 0 Not visible to user kWranglerPowerStateMin
7118 if (displayPowerState
<= kWranglerPowerStateSleep
) {
7119 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
7123 case kIOMessageDeviceHasPoweredOn
:
7124 // Display wrangler has powered on due to user activity
7125 // or wake from sleep.
7127 if (kWranglerPowerStateMax
== displayPowerState
) {
7128 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
7130 // See comment in handleUpdatePowerClientForDisplayWrangler
7131 if (service
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
7132 kWranglerPowerStateMax
) {
7133 gRootDomain
->evaluatePolicy( kStimulusEnterUserActiveState
);
7138 #endif /* DISPLAY_WRANGLER_PRESENT */
7139 return kIOReturnUnsupported
;
7142 //******************************************************************************
7145 //******************************************************************************
7148 IOPMrootDomain::updateUserActivity( void )
7150 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
7151 clock_get_uptime(&userActivityTime
);
7152 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonSoftware
)
7153 || (lastSleepReason
== kIOPMSleepReasonIdle
)
7154 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
7156 userActivityCount
++;
7157 DLOG("user activity reported %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
7162 IOPMrootDomain::reportUserInput( void )
7165 wrangler
->activityTickle(0, 0);
7167 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
7168 // Update user activity
7169 updateUserActivity();
7171 if (!darkWakeExit
&& ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0)) {
7172 // update user active abs time
7173 clock_get_uptime(&gUserActiveAbsTime
);
7174 pmPowerStateQueue
->submitPowerEvent(
7175 kPowerEventPolicyStimulus
,
7176 (void *) kStimulusDarkWakeActivityTickle
,
7177 true /* set wake type */ );
7183 IOPMrootDomain::requestUserActive(IOService
*device
, const char *reason
)
7185 #if DISPLAY_WRANGLER_PRESENT
7187 wrangler
->activityTickle(0, 0);
7191 DLOG("requestUserActive: device is null\n");
7194 OSSharedPtr
<const OSSymbol
> deviceName
= device
->copyName();
7195 uint64_t registryID
= device
->getRegistryEntryID();
7197 if (!deviceName
|| !registryID
) {
7198 DLOG("requestUserActive: no device name or registry entry\n");
7201 const char *name
= deviceName
->getCStringNoCopy();
7203 snprintf(payload
, sizeof(payload
), "%s:%s", name
, reason
);
7204 DLOG("requestUserActive from %s (0x%llx) for %s\n", name
, registryID
, reason
);
7205 messageClient(kIOPMMessageRequestUserActive
, systemCapabilityNotifier
.get(), (void *)payload
, sizeof(payload
));
7209 //******************************************************************************
7210 // latchDisplayWranglerTickle
7211 //******************************************************************************
7214 IOPMrootDomain::latchDisplayWranglerTickle( bool latch
)
7216 #if DISPLAY_WRANGLER_PRESENT
7218 if (!(_currentCapability
& kIOPMSystemCapabilityGraphics
) &&
7219 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
7220 !checkSystemCanSustainFullWake()) {
7221 // Currently in dark wake, and not transitioning to full wake.
7222 // Full wake is unsustainable, so latch the tickle to prevent
7223 // the display from lighting up momentarily.
7224 wranglerTickled
= true;
7226 wranglerTickled
= false;
7228 } else if (wranglerTickled
&& checkSystemCanSustainFullWake()) {
7229 wranglerTickled
= false;
7231 pmPowerStateQueue
->submitPowerEvent(
7232 kPowerEventPolicyStimulus
,
7233 (void *) kStimulusDarkWakeActivityTickle
);
7236 return wranglerTickled
;
7237 #else /* ! DISPLAY_WRANGLER_PRESENT */
7239 #endif /* ! DISPLAY_WRANGLER_PRESENT */
7242 //******************************************************************************
7243 // setDisplayPowerOn
7245 // For root domain user client
7246 //******************************************************************************
7249 IOPMrootDomain::setDisplayPowerOn( uint32_t options
)
7251 pmPowerStateQueue
->submitPowerEvent( kPowerEventSetDisplayPowerOn
,
7252 (void *) NULL
, options
);
7256 // MARK: System PM Policy
7258 //******************************************************************************
7259 // checkSystemSleepAllowed
7261 //******************************************************************************
7264 IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options
,
7265 uint32_t sleepReason
)
7269 // Conditions that prevent idle and demand system sleep.
7272 if (userDisabledAllSleep
) {
7273 err
= kPMUserDisabledAllSleep
; // 1. user-space sleep kill switch
7277 if (systemBooting
|| systemShutdown
|| gWillShutdown
) {
7278 err
= kPMSystemRestartBootingInProgress
; // 2. restart or shutdown in progress
7286 // Conditions above pegs the system at full wake.
7287 // Conditions below prevent system sleep but does not prevent
7288 // dark wake, and must be called from gated context.
7291 err
= kPMConfigPreventSystemSleep
; // 3. config does not support sleep
7295 if (lowBatteryCondition
|| thermalWarningState
|| thermalEmergencyState
) {
7296 break; // always sleep on low battery or when in thermal warning/emergency state
7299 if (sleepReason
== kIOPMSleepReasonDarkWakeThermalEmergency
) {
7300 break; // always sleep on dark wake thermal emergencies
7303 if (preventSystemSleepList
->getCount() != 0) {
7304 err
= kPMChildPreventSystemSleep
; // 4. child prevent system sleep clamp
7308 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
7309 kIOPMDriverAssertionLevelOn
) {
7310 err
= kPMCPUAssertion
; // 5. CPU assertion
7314 if (pciCantSleepValid
) {
7315 if (pciCantSleepFlag
) {
7316 err
= kPMPCIUnsupported
; // 6. PCI card does not support PM (cached)
7319 } else if (sleepSupportedPEFunction
&&
7320 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
)) {
7322 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
7323 ret
= getPlatform()->callPlatformFunction(
7324 sleepSupportedPEFunction
.get(), false,
7325 NULL
, NULL
, NULL
, NULL
);
7326 pciCantSleepValid
= true;
7327 pciCantSleepFlag
= false;
7328 if ((platformSleepSupport
& kPCICantSleep
) ||
7329 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
))) {
7330 err
= 6; // 6. PCI card does not support PM
7331 pciCantSleepFlag
= true;
7338 DLOG("System sleep prevented by %s\n", getSystemSleepPreventerString(err
));
7345 IOPMrootDomain::checkSystemSleepEnabled( void )
7347 return checkSystemSleepAllowed(0, 0);
7351 IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason
)
7354 return checkSystemSleepAllowed(1, sleepReason
);
7357 //******************************************************************************
7358 // checkSystemCanSustainFullWake
7359 //******************************************************************************
7362 IOPMrootDomain::checkSystemCanSustainFullWake( void )
7364 if (lowBatteryCondition
|| thermalWarningState
|| thermalEmergencyState
) {
7365 // Low battery wake, or received a low battery notification
7366 // while system is awake. This condition will persist until
7367 // the following wake.
7371 if (clamshellExists
&& clamshellClosed
&& !clamshellSleepDisableMask
) {
7372 // Graphics state is unknown and external display might not be probed.
7373 // Do not incorporate state that requires graphics to be in max power
7374 // such as desktopMode or clamshellDisabled.
7376 if (!acAdaptorConnected
) {
7377 DLOG("full wake check: no AC\n");
7384 //******************************************************************************
7386 //******************************************************************************
7391 IOPMrootDomain::mustHibernate( void )
7393 return lowBatteryCondition
|| thermalWarningState
;
7396 #endif /* HIBERNATION */
7398 //******************************************************************************
7400 //******************************************************************************
7402 // Tables for accumulated days in year by month, latter used for leap years
7404 static const unsigned int daysbymonth
[] =
7405 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
7407 static const unsigned int lydaysbymonth
[] =
7408 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 };
7411 IOPMConvertSecondsToCalendar(clock_sec_t secs
, IOPMCalendarStruct
* dt
)
7413 const unsigned int * dbm
= daysbymonth
;
7414 clock_sec_t n
, x
, y
, z
;
7416 // Calculate seconds, minutes and hours
7418 n
= secs
% (24 * 3600);
7419 dt
->second
= n
% 60;
7421 dt
->minute
= n
% 60;
7422 dt
->hour
= (typeof(dt
->hour
))(n
/ 60);
7424 // Calculate day of week
7426 n
= secs
/ (24 * 3600);
7427 // dt->dayWeek = (n + 4) % 7;
7430 // Rebase from days since Unix epoch (1/1/1970) store in 'n',
7431 // to days since 1/1/1968 to start on 4 year cycle, beginning
7436 // Every 4 year cycle will be exactly (366 + 365 * 3) = 1461 days.
7437 // Valid before 2100, since 2100 is not a leap year.
7439 x
= n
/ 1461; // number of 4 year cycles
7440 y
= n
% 1461; // days into current 4 year cycle
7443 // Add in years in the current 4 year cycle
7446 y
-= 366; // days after the leap year
7447 n
= y
% 365; // days into the current year
7448 z
+= (1 + y
/ 365); // years after the past 4-yr cycle
7451 dbm
= lydaysbymonth
;
7457 dt
->year
= (typeof(dt
->year
))z
;
7459 // Adjust remaining days value to start at 1
7465 for (x
= 1; (n
> dbm
[x
]) && (x
< 12); x
++) {
7468 dt
->month
= (typeof(dt
->month
))x
;
7470 // Calculate day of month
7472 dt
->day
= (typeof(dt
->day
))(n
- dbm
[x
- 1]);
7478 IOPMConvertCalendarToSeconds(const IOPMCalendarStruct
* dt
)
7480 const unsigned int * dbm
= daysbymonth
;
7483 if (dt
->year
< 1970 || dt
->month
> 12) {
7487 // Seconds elapsed in the current day
7489 secs
= dt
->second
+ 60 * dt
->minute
+ 3600 * dt
->hour
;
7491 // Number of days from 1/1/70 to beginning of current year
7492 // Account for extra day every 4 years starting at 1973
7494 y
= dt
->year
- 1970;
7495 days
= (y
* 365) + ((y
+ 1) / 4);
7497 // Change table if current year is a leap year
7499 if ((dt
->year
% 4) == 0) {
7500 dbm
= lydaysbymonth
;
7503 // Add in days elapsed in the current year
7505 days
+= (dt
->day
- 1) + dbm
[dt
->month
- 1];
7507 // Add accumulated days to accumulated seconds
7509 secs
+= 24 * 3600 * days
;
7515 IOPMrootDomain::getRUN_STATE(void)
7517 return _aotNow
? AOT_STATE
: ON_STATE
;
7521 IOPMrootDomain::isAOTMode()
7527 IOPMrootDomain::setWakeTime(uint64_t wakeContinuousTime
)
7529 clock_sec_t nowsecs
, wakesecs
;
7530 clock_usec_t nowmicrosecs
, wakemicrosecs
;
7531 uint64_t nowAbs
, wakeAbs
;
7533 clock_gettimeofday_and_absolute_time(&nowsecs
, &nowmicrosecs
, &nowAbs
);
7534 wakeAbs
= continuoustime_to_absolutetime(wakeContinuousTime
);
7535 if (wakeAbs
< nowAbs
) {
7536 printf(LOG_PREFIX
"wakeAbs %qd < nowAbs %qd\n", wakeAbs
, nowAbs
);
7540 absolutetime_to_microtime(wakeAbs
, &wakesecs
, &wakemicrosecs
);
7542 wakesecs
+= nowsecs
;
7543 wakemicrosecs
+= nowmicrosecs
;
7544 if (wakemicrosecs
>= USEC_PER_SEC
) {
7546 wakemicrosecs
-= USEC_PER_SEC
;
7548 if (wakemicrosecs
>= (USEC_PER_SEC
/ 10)) {
7552 IOPMConvertSecondsToCalendar(wakesecs
, &_aotWakeTimeCalendar
);
7554 if (_aotWakeTimeContinuous
!= wakeContinuousTime
) {
7555 _aotWakeTimeContinuous
= wakeContinuousTime
;
7556 IOLog(LOG_PREFIX
"setWakeTime: " YMDTF
"\n", YMDT(&_aotWakeTimeCalendar
));
7558 _aotWakeTimeCalendar
.selector
= kPMCalendarTypeMaintenance
;
7559 _aotWakeTimeUTC
= wakesecs
;
7561 return kIOReturnSuccess
;
7564 // assumes WAKEEVENT_LOCK
7566 IOPMrootDomain::aotShouldExit(bool checkTimeSet
, bool software
)
7569 const char * reason
= "";
7573 _aotMetrics
->softwareRequestCount
++;
7574 reason
= "software request";
7575 } else if (kIOPMWakeEventAOTExitFlags
& _aotPendingFlags
) {
7577 reason
= gWakeReasonString
;
7578 } else if (checkTimeSet
&& (kPMCalendarTypeInvalid
== _aotWakeTimeCalendar
.selector
)) {
7580 _aotMetrics
->noTimeSetCount
++;
7581 reason
= "flipbook expired";
7582 } else if ((kIOPMAOTModeRespectTimers
& _aotMode
) && _calendarWakeAlarmUTC
) {
7585 clock_get_calendar_microtime(&sec
, &usec
);
7586 if (_calendarWakeAlarmUTC
<= sec
) {
7588 _aotMetrics
->rtcAlarmsCount
++;
7589 reason
= "user alarm";
7592 exitNow
= (_aotNow
&& _aotExit
);
7595 IOLog(LOG_PREFIX
"AOT exit for %s, sc %d po %d, cp %d, rj %d, ex %d, nt %d, rt %d\n",
7597 _aotMetrics
->sleepCount
,
7598 _aotMetrics
->possibleCount
,
7599 _aotMetrics
->confirmedPossibleCount
,
7600 _aotMetrics
->rejectedPossibleCount
,
7601 _aotMetrics
->expiredPossibleCount
,
7602 _aotMetrics
->noTimeSetCount
,
7603 _aotMetrics
->rtcAlarmsCount
);
7609 IOPMrootDomain::aotExit(bool cps
)
7611 uint32_t savedMessageMask
;
7614 _aotTasksSuspended
= false;
7615 _aotReadyToFullWake
= false;
7616 if (_aotTimerScheduled
) {
7617 _aotTimerES
->cancelTimeout();
7618 _aotTimerScheduled
= false;
7620 updateTasksSuspend();
7622 _aotMetrics
->totalTime
+= mach_absolute_time() - _aotLastWakeTime
;
7623 _aotLastWakeTime
= 0;
7624 if (_aotMetrics
->sleepCount
&& (_aotMetrics
->sleepCount
<= kIOPMAOTMetricsKernelWakeCountMax
)) {
7626 strlcpy(&_aotMetrics
->kernelWakeReason
[_aotMetrics
->sleepCount
- 1][0],
7628 sizeof(_aotMetrics
->kernelWakeReason
[_aotMetrics
->sleepCount
]));
7632 _aotWakeTimeCalendar
.selector
= kPMCalendarTypeInvalid
;
7634 // Preserve the message mask since a system wake transition
7635 // may have already started and initialized the mask.
7636 savedMessageMask
= _systemMessageClientMask
;
7637 _systemMessageClientMask
= kSystemMessageClientLegacyApp
;
7638 tellClients(kIOMessageSystemWillPowerOn
);
7639 _systemMessageClientMask
= savedMessageMask
| kSystemMessageClientLegacyApp
;
7642 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonAOTExit
);
7647 IOPMrootDomain::aotEvaluate(IOTimerEventSource
* timer
)
7651 IOLog("aotEvaluate(%d) 0x%x\n", (timer
!= NULL
), _aotPendingFlags
);
7654 exitNow
= aotShouldExit(false, false);
7655 if (timer
!= NULL
) {
7656 _aotTimerScheduled
= false;
7663 if (_aotLingerTime
) {
7665 IOLog("aot linger before sleep\n");
7666 clock_absolutetime_interval_to_deadline(_aotLingerTime
, &deadline
);
7667 clock_delay_until(deadline
);
7670 privateSleepSystem(kIOPMSleepReasonSoftware
);
7674 //******************************************************************************
7677 // Conditions that affect our wake/sleep decision has changed.
7678 // If conditions dictate that the system must remain awake, clamp power
7679 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
7680 // is TRUE, then remove the power clamp and allow the power state to drop
7682 //******************************************************************************
7685 IOPMrootDomain::adjustPowerState( bool sleepASAP
)
7687 DEBUG_LOG("adjustPowerState %s, asap %d, idleSleepEnabled %d\n",
7688 getPowerStateString((uint32_t) getPowerState()), sleepASAP
, idleSleepEnabled
);
7695 if (AOT_STATE
!= getPowerState()) {
7699 exitNow
= aotShouldExit(true, false);
7701 && !_aotTimerScheduled
7702 && (kIOPMWakeEventAOTPossibleExit
== (kIOPMWakeEventAOTPossibleFlags
& _aotPendingFlags
))) {
7703 _aotTimerScheduled
= true;
7704 if (_aotLingerTime
) {
7705 _aotTimerES
->setTimeout(_aotLingerTime
);
7707 _aotTimerES
->setTimeout(800, kMillisecondScale
);
7714 _aotReadyToFullWake
= true;
7715 if (!_aotTimerScheduled
) {
7716 privateSleepSystem(kIOPMSleepReasonSoftware
);
7722 if ((!idleSleepEnabled
) || !checkSystemSleepEnabled()) {
7723 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonAdjustPowerState
);
7724 } else if (sleepASAP
) {
7725 changePowerStateWithTagToPriv(SLEEP_STATE
, kCPSReasonAdjustPowerState
);
7730 IOPMrootDomain::handleSetDisplayPowerOn(bool powerOn
)
7733 if (!checkSystemCanSustainFullWake()) {
7734 DLOG("System cannot sustain full wake\n");
7738 // Force wrangler to max power state. If system is in dark wake
7739 // this alone won't raise the wrangler's power state.
7741 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMax
);
7744 // System in dark wake, always requesting full wake should
7745 // not have any bad side-effects, even if the request fails.
7747 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
)) {
7748 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeNotification
);
7749 requestFullWake( kFullWakeReasonDisplayOn
);
7752 // Relenquish desire to power up display.
7753 // Must first transition to state 1 since wrangler doesn't
7754 // power off the displays at state 0. At state 0 the root
7755 // domain is removed from the wrangler's power client list.
7757 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
+ 1);
7758 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
);
7763 //******************************************************************************
7764 // dispatchPowerEvent
7766 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
7767 //******************************************************************************
7770 IOPMrootDomain::dispatchPowerEvent(
7771 uint32_t event
, void * arg0
, uint64_t arg1
)
7776 case kPowerEventFeatureChanged
:
7777 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7778 messageClients(kIOPMMessageFeatureChange
, this);
7781 case kPowerEventReceivedPowerNotification
:
7782 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7783 handlePowerNotification((UInt32
)(uintptr_t) arg0
);
7786 case kPowerEventSystemBootCompleted
:
7787 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7788 if (systemBooting
) {
7789 systemBooting
= false;
7791 // read noidle setting from Device Tree
7792 OSSharedPtr
<IORegistryEntry
> defaults
= IORegistryEntry::fromPath("IODeviceTree:/defaults");
7793 if (defaults
!= NULL
) {
7794 OSSharedPtr
<OSObject
> noIdleProp
= defaults
->copyProperty("no-idle");
7795 OSData
*data
= OSDynamicCast(OSData
, noIdleProp
.get());
7796 if ((data
!= NULL
) && (data
->getLength() == 4)) {
7797 gNoIdleFlag
= *(uint32_t*)data
->getBytesNoCopy();
7798 DLOG("Setting gNoIdleFlag to %u from device tree\n", gNoIdleFlag
);
7801 if (lowBatteryCondition
|| thermalEmergencyState
) {
7802 if (lowBatteryCondition
) {
7803 privateSleepSystem(kIOPMSleepReasonLowPower
);
7805 privateSleepSystem(kIOPMSleepReasonThermalEmergency
);
7807 // The rest is unnecessary since the system is expected
7808 // to sleep immediately. The following wake will update
7813 sleepWakeDebugMemAlloc();
7814 saveFailureData2File();
7816 // If lid is closed, re-send lid closed notification
7817 // now that booting is complete.
7818 if (clamshellClosed
) {
7819 handlePowerNotification(kLocalEvalClamshellCommand
);
7821 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
7825 case kPowerEventSystemShutdown
:
7826 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7827 if (kOSBooleanTrue
== (OSBoolean
*) arg0
) {
7828 /* We set systemShutdown = true during shutdown
7829 * to prevent sleep at unexpected times while loginwindow is trying
7830 * to shutdown apps and while the OS is trying to transition to
7831 * complete power of.
7833 * Set to true during shutdown, as soon as loginwindow shows
7834 * the "shutdown countdown dialog", through individual app
7835 * termination, and through black screen kernel shutdown.
7837 systemShutdown
= true;
7840 * A shutdown was initiated, but then the shutdown
7841 * was cancelled, clearing systemShutdown to false here.
7843 systemShutdown
= false;
7847 case kPowerEventUserDisabledSleep
:
7848 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7849 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
7852 case kPowerEventRegisterSystemCapabilityClient
:
7853 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7855 // reset() handles the arg0 == nullptr case for us
7856 systemCapabilityNotifier
.reset((IONotifier
*) arg0
, OSRetain
);
7857 /* intentional fall-through */
7858 [[clang::fallthrough]];
7860 case kPowerEventRegisterKernelCapabilityClient
:
7861 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7862 if (!_joinedCapabilityClients
) {
7863 _joinedCapabilityClients
= OSSet::withCapacity(8);
7866 OSSharedPtr
<IONotifier
> notify((IONotifier
*) arg0
, OSNoRetain
);
7867 if (_joinedCapabilityClients
) {
7868 _joinedCapabilityClients
->setObject(notify
.get());
7869 synchronizePowerTree( kIOPMSyncNoChildNotify
);
7874 case kPowerEventPolicyStimulus
:
7875 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7877 int stimulus
= (int)(uintptr_t) arg0
;
7878 evaluatePolicy(stimulus
, (uint32_t) arg1
);
7882 case kPowerEventAssertionCreate
:
7883 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7885 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
7890 case kPowerEventAssertionRelease
:
7891 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7893 pmAssertions
->handleReleaseAssertion(arg1
);
7897 case kPowerEventAssertionSetLevel
:
7898 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7900 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
7904 case kPowerEventQueueSleepWakeUUID
:
7905 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7906 handleQueueSleepWakeUUID((OSObject
*)arg0
);
7908 case kPowerEventPublishSleepWakeUUID
:
7909 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7910 handlePublishSleepWakeUUID((bool)arg0
);
7913 case kPowerEventSetDisplayPowerOn
:
7914 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7916 displayPowerOnRequested
= true;
7918 displayPowerOnRequested
= false;
7920 handleSetDisplayPowerOn(displayPowerOnRequested
);
7923 case kPowerEventPublishWakeType
:
7924 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7926 // Don't replace wake type property if already set
7927 if ((arg0
== gIOPMWakeTypeUserKey
) ||
7928 !propertyExists(kIOPMRootDomainWakeTypeKey
)) {
7929 const char * wakeType
= NULL
;
7931 if (arg0
== gIOPMWakeTypeUserKey
) {
7932 requestUserActive(this, "WakeTypeUser");
7933 wakeType
= kIOPMRootDomainWakeTypeUser
;
7934 } else if (arg0
== gIOPMSettingDebugWakeRelativeKey
) {
7935 requestUserActive(this, "WakeTypeAlarm");
7936 wakeType
= kIOPMRootDomainWakeTypeAlarm
;
7937 } else if (arg0
== gIOPMSettingSleepServiceWakeCalendarKey
) {
7938 darkWakeSleepService
= true;
7939 wakeType
= kIOPMRootDomainWakeTypeSleepService
;
7940 } else if (arg0
== gIOPMSettingMaintenanceWakeCalendarKey
) {
7941 wakeType
= kIOPMRootDomainWakeTypeMaintenance
;
7945 setProperty(kIOPMRootDomainWakeTypeKey
, wakeType
);
7950 case kPowerEventAOTEvaluate
:
7951 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7952 if (_aotReadyToFullWake
) {
7959 //******************************************************************************
7960 // systemPowerEventOccurred
7962 // The power controller is notifying us of a hardware-related power management
7963 // event that we must handle.
7965 // systemPowerEventOccurred covers the same functionality that
7966 // receivePowerNotification does; it simply provides a richer API for conveying
7967 // more information.
7968 //******************************************************************************
7971 IOPMrootDomain::systemPowerEventOccurred(
7972 const OSSymbol
*event
,
7975 IOReturn attempt
= kIOReturnSuccess
;
7976 OSSharedPtr
<OSNumber
> newNumber
;
7979 return kIOReturnBadArgument
;
7982 newNumber
= OSNumber::withNumber(intValue
, 8 * sizeof(intValue
));
7984 return kIOReturnInternalError
;
7987 attempt
= systemPowerEventOccurred(event
, static_cast<OSObject
*>(newNumber
.get()));
7993 IOPMrootDomain::setThermalState(OSObject
*value
)
7997 if (gIOPMWorkLoop
->inGate() == false) {
7998 gIOPMWorkLoop
->runAction(
7999 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setThermalState
),
8005 if (value
&& (num
= OSDynamicCast(OSNumber
, value
))) {
8006 thermalWarningState
= ((num
->unsigned32BitValue() == kIOPMThermalLevelWarning
) ||
8007 (num
->unsigned32BitValue() == kIOPMThermalLevelTrap
)) ? 1 : 0;
8012 IOPMrootDomain::systemPowerEventOccurred(
8013 const OSSymbol
*event
,
8016 OSSharedPtr
<OSDictionary
> thermalsDict
;
8017 bool shouldUpdate
= true;
8019 if (!event
|| !value
) {
8020 return kIOReturnBadArgument
;
8024 // We reuse featuresDict Lock because it already exists and guards
8025 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
8026 // of stepping on that lock.
8027 if (featuresDictLock
) {
8028 IOLockLock(featuresDictLock
);
8031 OSSharedPtr
<OSObject
> origThermalsProp
= copyProperty(kIOPMRootDomainPowerStatusKey
);
8032 OSDictionary
* origThermalsDict
= OSDynamicCast(OSDictionary
, origThermalsProp
.get());
8034 if (origThermalsDict
) {
8035 thermalsDict
= OSDictionary::withDictionary(origThermalsDict
);
8037 thermalsDict
= OSDictionary::withCapacity(1);
8040 if (!thermalsDict
) {
8041 shouldUpdate
= false;
8045 thermalsDict
->setObject(event
, value
);
8047 setProperty(kIOPMRootDomainPowerStatusKey
, thermalsDict
.get());
8051 if (featuresDictLock
) {
8052 IOLockUnlock(featuresDictLock
);
8057 event
->isEqualTo(kIOPMThermalLevelWarningKey
)) {
8058 setThermalState(value
);
8060 messageClients(kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
8063 return kIOReturnSuccess
;
8066 //******************************************************************************
8067 // receivePowerNotification
8069 // The power controller is notifying us of a hardware-related power management
8070 // event that we must handle. This may be a result of an 'environment' interrupt
8071 // from the power mgt micro.
8072 //******************************************************************************
8075 IOPMrootDomain::receivePowerNotification( UInt32 msg
)
8077 if (msg
& kIOPMPowerButton
) {
8078 uint32_t currentPhase
= pmTracer
->getTracePhase();
8079 if (currentPhase
!= kIOPMTracePointSystemUp
&& currentPhase
> kIOPMTracePointSystemSleep
) {
8080 DEBUG_LOG("power button pressed during wake. phase = %u\n", currentPhase
);
8081 swd_flags
|= SWD_PWR_BTN_STACKSHOT
;
8082 thread_call_enter(powerButtonDown
);
8084 DEBUG_LOG("power button pressed when system is up\n");
8086 } else if (msg
& kIOPMPowerButtonUp
) {
8087 if (swd_flags
& SWD_PWR_BTN_STACKSHOT
) {
8088 swd_flags
&= ~SWD_PWR_BTN_STACKSHOT
;
8089 thread_call_enter(powerButtonUp
);
8092 pmPowerStateQueue
->submitPowerEvent(
8093 kPowerEventReceivedPowerNotification
, (void *)(uintptr_t) msg
);
8095 return kIOReturnSuccess
;
8099 IOPMrootDomain::handlePowerNotification( UInt32 msg
)
8101 bool eval_clamshell
= false;
8102 bool eval_clamshell_alarm
= false;
8107 * Local (IOPMrootDomain only) eval clamshell command
8109 if (msg
& kLocalEvalClamshellCommand
) {
8110 if ((gClamshellFlags
& kClamshell_WAR_47715679
) && isRTCAlarmWake
) {
8111 eval_clamshell_alarm
= true;
8113 // reset isRTCAlarmWake. This evaluation should happen only once
8114 // on RTC/Alarm wake. Any clamshell events after wake should follow
8115 // the regular evaluation
8116 isRTCAlarmWake
= false;
8118 eval_clamshell
= true;
8125 if (msg
& kIOPMOverTemp
) {
8126 DLOG("Thermal overtemp message received!\n");
8127 thermalEmergencyState
= true;
8128 privateSleepSystem(kIOPMSleepReasonThermalEmergency
);
8132 * Forward DW thermal notification to client, if system is not going to sleep
8134 if ((msg
& kIOPMDWOverTemp
) && (_systemTransitionType
!= kSystemTransitionSleep
)) {
8135 DLOG("DarkWake thermal limits message received!\n");
8136 messageClients(kIOPMMessageDarkWakeThermalEmergency
);
8142 if (msg
& kIOPMSleepNow
) {
8143 privateSleepSystem(kIOPMSleepReasonSoftware
);
8149 if (msg
& kIOPMPowerEmergency
) {
8150 DLOG("Low battery notification received\n");
8151 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
8152 // Wait for the next low battery notification if the system state is
8154 if ((_systemTransitionType
== kSystemTransitionNone
) &&
8155 CAP_CURRENT(kIOPMSystemCapabilityCPU
) &&
8156 !systemBooting
&& !systemShutdown
&& !gWillShutdown
) {
8157 // Setting lowBatteryCondition will prevent system sleep
8158 lowBatteryCondition
= true;
8160 // Notify userspace to initiate system shutdown
8161 messageClients(kIOPMMessageRequestSystemShutdown
);
8164 lowBatteryCondition
= true;
8165 privateSleepSystem(kIOPMSleepReasonLowPower
);
8172 if (msg
& kIOPMClamshellOpened
) {
8173 DLOG("Clamshell opened\n");
8174 // Received clamshel open message from clamshell controlling driver
8175 // Update our internal state and tell general interest clients
8176 clamshellClosed
= false;
8177 clamshellExists
= true;
8179 // Don't issue a hid tickle when lid is open and polled on wake
8180 if (msg
& kIOPMSetValue
) {
8181 setProperty(kIOPMRootDomainWakeTypeKey
, "Lid Open");
8186 informCPUStateChange(kInformLid
, 0);
8188 // Tell general interest clients
8189 sendClientClamshellNotification();
8191 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
8192 || (lastSleepReason
== kIOPMSleepReasonIdle
)
8193 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
8195 userActivityCount
++;
8197 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
8202 * Send the clamshell interest notification since the lid is closing.
8204 if (msg
& kIOPMClamshellClosed
) {
8205 if ((clamshellIgnoreClose
|| (gClamshellFlags
& kClamshell_WAR_38378787
)) &&
8206 clamshellClosed
&& clamshellExists
) {
8207 DLOG("Ignoring redundant Clamshell close event\n");
8209 DLOG("Clamshell closed\n");
8210 // Received clamshel open message from clamshell controlling driver
8211 // Update our internal state and tell general interest clients
8212 clamshellClosed
= true;
8213 clamshellExists
= true;
8215 // Ignore all following clamshell close events until the clamshell
8216 // is opened or the system sleeps. When a clamshell close triggers
8217 // a system wake, the lid driver may send us two clamshell close
8218 // events, one for the clamshell close event itself, and a second
8219 // close event when the driver polls the lid state on wake.
8220 clamshellIgnoreClose
= true;
8223 informCPUStateChange(kInformLid
, 1);
8225 // Tell general interest clients
8226 sendClientClamshellNotification();
8228 // And set eval_clamshell = so we can attempt
8229 eval_clamshell
= true;
8234 * Set Desktop mode (sent from graphics)
8236 * -> reevaluate lid state
8238 if (msg
& kIOPMSetDesktopMode
) {
8239 desktopMode
= (0 != (msg
& kIOPMSetValue
));
8240 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
8241 DLOG("Desktop mode %d\n", desktopMode
);
8243 sendClientClamshellNotification();
8245 // Re-evaluate the lid state
8246 eval_clamshell
= true;
8250 * AC Adaptor connected
8252 * -> reevaluate lid state
8254 if (msg
& kIOPMSetACAdaptorConnected
) {
8255 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
8256 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
8259 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
8261 // Tell BSD if AC is connected
8262 // 0 == external power source; 1 == on battery
8263 post_sys_powersource(acAdaptorConnected
? 0:1);
8265 sendClientClamshellNotification();
8267 // Re-evaluate the lid state
8268 eval_clamshell
= true;
8270 // Lack of AC may have latched a display wrangler tickle.
8271 // This mirrors the hardware's USB wake event latch, where a latched
8272 // USB wake event followed by an AC attach will trigger a full wake.
8273 latchDisplayWranglerTickle( false );
8276 // AC presence will reset the standy timer delay adjustment.
8277 _standbyTimerResetSeconds
= 0;
8279 if (!userIsActive
) {
8280 // Reset userActivityTime when power supply is changed(rdr 13789330)
8281 clock_get_uptime(&userActivityTime
);
8286 * Enable Clamshell (external display disappear)
8288 * -> reevaluate lid state
8290 if (msg
& kIOPMEnableClamshell
) {
8291 DLOG("Clamshell enabled\n");
8293 // Re-evaluate the lid state
8294 // System should sleep on external display disappearance
8295 // in lid closed operation.
8296 if (true == clamshellDisabled
) {
8297 eval_clamshell
= true;
8299 #if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
8300 // Also clear kClamshellSleepDisableInternal when graphics enables
8301 // the clamshell during a full wake. When graphics is behaving as
8302 // expected, this will allow clamshell close to be honored earlier
8303 // rather than waiting for the delayed evaluation.
8304 if ((clamshellSleepDisableMask
& kClamshellSleepDisableInternal
) &&
8305 (CAP_PENDING(kIOPMSystemCapabilityGraphics
) ||
8306 CAP_CURRENT(kIOPMSystemCapabilityGraphics
))) {
8307 setClamShellSleepDisable(false, kClamshellSleepDisableInternal
);
8309 // Cancel the TC to avoid an extra kLocalEvalClamshellCommand
8310 // when timer expires which is harmless but useless.
8311 thread_call_cancel(fullWakeThreadCall
);
8316 clamshellDisabled
= false;
8317 sendClientClamshellNotification();
8321 * Disable Clamshell (external display appeared)
8322 * We don't bother re-evaluating clamshell state. If the system is awake,
8323 * the lid is probably open.
8325 if (msg
& kIOPMDisableClamshell
) {
8326 DLOG("Clamshell disabled\n");
8327 clamshellDisabled
= true;
8328 sendClientClamshellNotification();
8332 * Evaluate clamshell and SLEEP if appropriate
8334 if (eval_clamshell_alarm
&& clamshellClosed
) {
8335 if (shouldSleepOnRTCAlarmWake()) {
8336 privateSleepSystem(kIOPMSleepReasonClamshell
);
8338 } else if (eval_clamshell
&& clamshellClosed
) {
8339 if (shouldSleepOnClamshellClosed()) {
8340 privateSleepSystem(kIOPMSleepReasonClamshell
);
8342 evaluatePolicy( kStimulusDarkWakeEvaluate
);
8346 if (msg
& kIOPMProModeEngaged
) {
8348 DLOG("ProModeEngaged\n");
8349 messageClient(kIOPMMessageProModeStateChange
, systemCapabilityNotifier
.get(), &newState
, sizeof(newState
));
8352 if (msg
& kIOPMProModeDisengaged
) {
8354 DLOG("ProModeDisengaged\n");
8355 messageClient(kIOPMMessageProModeStateChange
, systemCapabilityNotifier
.get(), &newState
, sizeof(newState
));
8359 //******************************************************************************
8362 // Evaluate root-domain policy in response to external changes.
8363 //******************************************************************************
8366 IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
8370 int idleSleepEnabled
: 1;
8371 int idleSleepDisabled
: 1;
8372 int displaySleep
: 1;
8373 int sleepDelayChanged
: 1;
8374 int evaluateDarkWake
: 1;
8375 int adjustPowerState
: 1;
8376 int userBecameInactive
: 1;
8377 int displaySleepEntry
: 1;
8387 case kStimulusDisplayWranglerSleep
:
8388 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8389 if (!wranglerPowerOff
) {
8390 // wrangler is in sleep state or lower
8391 flags
.bit
.displaySleep
= true;
8393 if (!wranglerAsleep
) {
8394 // transition from wrangler wake to wrangler sleep
8395 flags
.bit
.displaySleepEntry
= true;
8396 wranglerAsleep
= true;
8400 case kStimulusDisplayWranglerWake
:
8401 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8402 displayIdleForDemandSleep
= false;
8403 wranglerPowerOff
= false;
8404 wranglerAsleep
= false;
8407 case kStimulusEnterUserActiveState
:
8408 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8409 if (_preventUserActive
) {
8410 DLOG("user active dropped\n");
8413 if (!userIsActive
) {
8414 userIsActive
= true;
8415 userWasActive
= true;
8416 clock_get_uptime(&gUserActiveAbsTime
);
8418 // Stay awake after dropping demand for display power on
8419 if (kFullWakeReasonDisplayOn
== fullWakeReason
) {
8420 fullWakeReason
= fFullWakeReasonDisplayOnAndLocalUser
;
8421 DLOG("User activity while in notification wake\n");
8422 changePowerStateWithOverrideTo( getRUN_STATE(), 0);
8425 kdebugTrace(kPMLogUserActiveState
, 0, 1, 0);
8426 setProperty(gIOPMUserIsActiveKey
.get(), kOSBooleanTrue
);
8427 messageClients(kIOPMMessageUserIsActiveChanged
);
8429 flags
.bit
.idleSleepDisabled
= true;
8432 case kStimulusLeaveUserActiveState
:
8433 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8435 clock_get_uptime(&gUserInactiveAbsTime
);
8436 userIsActive
= false;
8437 clock_get_uptime(&userBecameInactiveTime
);
8438 flags
.bit
.userBecameInactive
= true;
8440 kdebugTrace(kPMLogUserActiveState
, 0, 0, 0);
8441 setProperty(gIOPMUserIsActiveKey
.get(), kOSBooleanFalse
);
8442 messageClients(kIOPMMessageUserIsActiveChanged
);
8446 case kStimulusAggressivenessChanged
:
8448 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8449 unsigned long aggressiveValue
;
8450 uint32_t minutesToIdleSleep
= 0;
8451 uint32_t minutesToDisplayDim
= 0;
8452 uint32_t minutesDelta
= 0;
8454 // Fetch latest display and system sleep slider values.
8455 aggressiveValue
= 0;
8456 getAggressiveness(kPMMinutesToSleep
, &aggressiveValue
);
8457 minutesToIdleSleep
= (uint32_t) aggressiveValue
;
8459 aggressiveValue
= 0;
8460 getAggressiveness(kPMMinutesToDim
, &aggressiveValue
);
8461 minutesToDisplayDim
= (uint32_t) aggressiveValue
;
8462 DLOG("aggressiveness changed: system %u->%u, display %u\n",
8463 sleepSlider
, minutesToIdleSleep
, minutesToDisplayDim
);
8465 DLOG("idle time -> %d secs (ena %d)\n",
8466 idleSeconds
, (minutesToIdleSleep
!= 0));
8468 // How long to wait before sleeping the system once
8469 // the displays turns off is indicated by 'extraSleepDelay'.
8471 if (minutesToIdleSleep
> minutesToDisplayDim
) {
8472 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
8473 } else if (minutesToIdleSleep
== minutesToDisplayDim
) {
8477 if ((!idleSleepEnabled
) && (minutesToIdleSleep
!= 0)) {
8478 idleSleepEnabled
= flags
.bit
.idleSleepEnabled
= true;
8481 if ((idleSleepEnabled
) && (minutesToIdleSleep
== 0)) {
8482 flags
.bit
.idleSleepDisabled
= true;
8483 idleSleepEnabled
= false;
8485 #if !defined(XNU_TARGET_OS_OSX)
8486 if (0x7fffffff == minutesToIdleSleep
) {
8487 minutesToIdleSleep
= idleSeconds
;
8489 #endif /* !defined(XNU_TARGET_OS_OSX) */
8491 if (((minutesDelta
!= extraSleepDelay
) ||
8492 (userActivityTime
!= userActivityTime_prev
)) &&
8493 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
) {
8494 flags
.bit
.sleepDelayChanged
= true;
8497 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
8498 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
)) {
8499 // Reconsider decision to remain in dark wake
8500 flags
.bit
.evaluateDarkWake
= true;
8503 sleepSlider
= minutesToIdleSleep
;
8504 extraSleepDelay
= minutesDelta
;
8505 userActivityTime_prev
= userActivityTime
;
8508 case kStimulusDemandSystemSleep
:
8509 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8510 displayIdleForDemandSleep
= true;
8511 if (wrangler
&& wranglerIdleSettings
) {
8512 // Request wrangler idle only when demand sleep is triggered
8514 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
)) {
8515 wrangler
->setProperties(wranglerIdleSettings
.get());
8516 DLOG("Requested wrangler idle\n");
8519 // arg = sleepReason
8520 changePowerStateWithOverrideTo( SLEEP_STATE
, arg
);
8523 case kStimulusAllowSystemSleepChanged
:
8524 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8525 flags
.bit
.adjustPowerState
= true;
8528 case kStimulusDarkWakeActivityTickle
:
8529 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8530 // arg == true implies real and not self generated wrangler tickle.
8531 // Update wake type on PM work loop instead of the tickle thread to
8532 // eliminate the possibility of an early tickle clobbering the wake
8533 // type set by the platform driver.
8535 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeHIDActivity
);
8538 if (!darkWakeExit
) {
8539 if (latchDisplayWranglerTickle(true)) {
8540 DLOG("latched tickle\n");
8544 darkWakeExit
= true;
8545 DLOG("Requesting full wake due to dark wake activity tickle\n");
8546 requestFullWake( kFullWakeReasonLocalUser
);
8550 case kStimulusDarkWakeEntry
:
8551 case kStimulusDarkWakeReentry
:
8552 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8553 // Any system transitions since the last dark wake transition
8554 // will invalid the stimulus.
8556 if (arg
== _systemStateGeneration
) {
8557 DLOG("dark wake entry\n");
8558 systemDarkWake
= true;
8560 // Keep wranglerPowerOff an invariant when wrangler is absent
8562 wranglerPowerOff
= true;
8565 if (kStimulusDarkWakeEntry
== stimulus
) {
8566 clock_get_uptime(&userBecameInactiveTime
);
8567 flags
.bit
.evaluateDarkWake
= true;
8568 if (activitySinceSleep()) {
8569 DLOG("User activity recorded while going to darkwake\n");
8574 // Always accelerate disk spindown while in dark wake,
8575 // even if system does not support/allow sleep.
8577 cancelIdleSleepTimer();
8578 setQuickSpinDownTimeout();
8582 case kStimulusDarkWakeEvaluate
:
8583 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8584 if (systemDarkWake
) {
8585 flags
.bit
.evaluateDarkWake
= true;
8589 case kStimulusNoIdleSleepPreventers
:
8590 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8591 flags
.bit
.adjustPowerState
= true;
8593 } /* switch(stimulus) */
8595 if (flags
.bit
.evaluateDarkWake
&& (kFullWakeReasonNone
== fullWakeReason
)) {
8596 DLOG("DarkWake: sleepASAP %d, clamshell closed %d, disabled %d/%x, desktopMode %d, ac %d\n",
8597 darkWakeToSleepASAP
, clamshellClosed
, clamshellDisabled
, clamshellSleepDisableMask
, desktopMode
, acAdaptorConnected
);
8598 if (darkWakeToSleepASAP
||
8599 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
))) {
8600 uint32_t newSleepReason
;
8602 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics
)) {
8603 // System was previously in full wake. Sleep reason from
8604 // full to dark already recorded in fullToDarkReason.
8606 if (lowBatteryCondition
) {
8607 newSleepReason
= kIOPMSleepReasonLowPower
;
8608 } else if (thermalEmergencyState
) {
8609 newSleepReason
= kIOPMSleepReasonThermalEmergency
;
8611 newSleepReason
= fullToDarkReason
;
8614 // In dark wake from system sleep.
8616 if (darkWakeSleepService
) {
8617 newSleepReason
= kIOPMSleepReasonSleepServiceExit
;
8619 newSleepReason
= kIOPMSleepReasonMaintenance
;
8623 if (checkSystemCanSleep(newSleepReason
)) {
8624 privateSleepSystem(newSleepReason
);
8626 } else { // non-maintenance (network) dark wake
8627 if (checkSystemCanSleep(kIOPMSleepReasonIdle
)) {
8628 // Release power clamp, and wait for children idle.
8629 adjustPowerState(true);
8631 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonDarkWakeCannotSleep
);
8636 if (systemDarkWake
) {
8637 // The rest are irrelevant while system is in dark wake.
8641 if ((flags
.bit
.displaySleepEntry
) &&
8642 (kFullWakeReasonDisplayOn
== fullWakeReason
)) {
8643 // kIOPMSleepReasonNotificationWakeExit
8644 DLOG("Display sleep while in notification wake\n");
8645 changePowerStateWithOverrideTo(SLEEP_STATE
, kIOPMSleepReasonNotificationWakeExit
);
8648 if (flags
.bit
.userBecameInactive
|| flags
.bit
.sleepDelayChanged
) {
8649 bool cancelQuickSpindown
= false;
8651 if (flags
.bit
.sleepDelayChanged
) {
8652 // Cancel existing idle sleep timer and quick disk spindown.
8653 // New settings will be applied by the idleSleepEnabled flag
8654 // handler below if idle sleep is enabled.
8656 DLOG("extra sleep timer changed\n");
8657 cancelIdleSleepTimer();
8658 cancelQuickSpindown
= true;
8660 DLOG("user inactive\n");
8663 if (!userIsActive
&& idleSleepEnabled
) {
8664 startIdleSleepTimer(getTimeToIdleSleep());
8667 if (cancelQuickSpindown
) {
8668 restoreUserSpinDownTimeout();
8672 if (flags
.bit
.idleSleepEnabled
) {
8673 DLOG("idle sleep timer enabled\n");
8675 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
8676 startIdleSleepTimer(getTimeToIdleSleep());
8678 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonIdleSleepEnabled
);
8679 startIdleSleepTimer( idleSeconds
);
8682 // Start idle timer if prefs now allow system sleep
8683 // and user is already inactive. Disk spindown is
8684 // accelerated upon timer expiration.
8686 if (!userIsActive
) {
8687 startIdleSleepTimer(getTimeToIdleSleep());
8692 if (flags
.bit
.idleSleepDisabled
) {
8693 DLOG("idle sleep timer disabled\n");
8694 cancelIdleSleepTimer();
8695 restoreUserSpinDownTimeout();
8699 if (flags
.bit
.adjustPowerState
) {
8700 bool sleepASAP
= false;
8702 if (!systemBooting
&& (0 == idleSleepPreventersCount())) {
8704 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonEvaluatePolicy
);
8705 if (idleSleepEnabled
) {
8706 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
8707 if (!extraSleepDelay
&& !idleSleepTimerPending
) {
8711 // stay awake for at least idleSeconds
8712 startIdleSleepTimer(idleSeconds
);
8715 } else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
) {
8720 adjustPowerState(sleepASAP
);
8724 //******************************************************************************
8727 IOPMrootDomain::idleSleepPreventersCount()
8730 unsigned int count __block
;
8732 preventIdleSleepList
->iterateObjects(^bool (OSObject
* obj
)
8734 count
+= (NULL
== obj
->metaCast("AppleARMBacklight"));
8740 return preventIdleSleepList
->getCount();
8744 //******************************************************************************
8747 // Request transition from dark wake to full wake
8748 //******************************************************************************
8751 IOPMrootDomain::requestFullWake( FullWakeReason reason
)
8753 uint32_t options
= 0;
8754 IOService
* pciRoot
= NULL
;
8755 bool promotion
= false;
8757 // System must be in dark wake and a valid reason for entering full wake
8758 if ((kFullWakeReasonNone
== reason
) ||
8759 (kFullWakeReasonNone
!= fullWakeReason
) ||
8760 (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))) {
8764 // Will clear reason upon exit from full wake
8765 fullWakeReason
= reason
;
8767 _desiredCapability
|= (kIOPMSystemCapabilityGraphics
|
8768 kIOPMSystemCapabilityAudio
);
8770 if ((kSystemTransitionWake
== _systemTransitionType
) &&
8771 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
8772 !darkWakePowerClamped
) {
8773 // Promote to full wake while waking up to dark wake due to tickle.
8774 // PM will hold off notifying the graphics subsystem about system wake
8775 // as late as possible, so if a HID tickle does arrive, graphics can
8776 // power up from this same wake transition. Otherwise, the latency to
8777 // power up graphics on the following transition can be huge on certain
8778 // systems. However, once any power clamping has taken effect, it is
8779 // too late to promote the current dark wake transition to a full wake.
8780 _pendingCapability
|= (kIOPMSystemCapabilityGraphics
|
8781 kIOPMSystemCapabilityAudio
);
8783 // Tell the PCI parent of audio and graphics drivers to stop
8784 // delaying the child notifications. Same for root domain.
8785 pciRoot
= pciHostBridgeDriver
.get();
8786 willEnterFullWake();
8790 // Unsafe to cancel once graphics was powered.
8791 // If system woke from dark wake, the return to sleep can
8792 // be cancelled. "awake -> dark -> sleep" transition
8793 // can be cancelled also, during the "dark -> sleep" phase
8794 // *prior* to driver power down.
8795 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) ||
8796 _pendingCapability
== 0) {
8797 options
|= kIOPMSyncCancelPowerDown
;
8800 synchronizePowerTree(options
, pciRoot
);
8802 if (kFullWakeReasonLocalUser
== fullWakeReason
) {
8803 // IOGraphics doesn't light the display even though graphics is
8804 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
8805 // So, do an explicit activity tickle
8807 wrangler
->activityTickle(0, 0);
8811 // Log a timestamp for the initial full wake request.
8812 // System may not always honor this full wake request.
8813 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
)) {
8817 clock_get_uptime(&now
);
8818 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
8819 absolutetime_to_nanoseconds(now
, &nsec
);
8820 MSG("full wake %s (reason %u) %u ms\n",
8821 promotion
? "promotion" : "request",
8822 fullWakeReason
, ((int)((nsec
) / NSEC_PER_MSEC
)));
8826 //******************************************************************************
8827 // willEnterFullWake
8829 // System will enter full wake from sleep, from dark wake, or from dark
8830 // wake promotion. This function aggregate things that are in common to
8831 // all three full wake transitions.
8833 // Assumptions: fullWakeReason was updated
8834 //******************************************************************************
8837 IOPMrootDomain::willEnterFullWake( void )
8839 hibernateRetry
= false;
8840 sleepToStandby
= false;
8841 standbyNixed
= false;
8842 resetTimers
= false;
8843 sleepTimerMaintenance
= false;
8845 assert(!CAP_CURRENT(kIOPMSystemCapabilityGraphics
));
8847 _systemMessageClientMask
= kSystemMessageClientPowerd
|
8848 kSystemMessageClientLegacyApp
;
8850 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0) {
8851 // First time to attain full wake capability since the last wake
8852 _systemMessageClientMask
|= kSystemMessageClientKernel
;
8854 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
8855 setProperty(gIOPMUserTriggeredFullWakeKey
.get(),
8856 (kFullWakeReasonLocalUser
== fullWakeReason
) ?
8857 kOSBooleanTrue
: kOSBooleanFalse
);
8860 IOHibernateSetWakeCapabilities(_pendingCapability
);
8863 IOService::setAdvisoryTickleEnable( true );
8864 tellClients(kIOMessageSystemWillPowerOn
);
8865 preventTransitionToUserActive(false);
8868 //******************************************************************************
8869 // fullWakeDelayedWork
8871 // System has already entered full wake. Invoked by a delayed thread call.
8872 //******************************************************************************
8875 IOPMrootDomain::fullWakeDelayedWork( void )
8877 #if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
8878 if (!gIOPMWorkLoop
->inGate()) {
8879 gIOPMWorkLoop
->runAction(
8880 OSMemberFunctionCast(IOWorkLoop::Action
, this,
8881 &IOPMrootDomain::fullWakeDelayedWork
), this);
8885 DLOG("fullWakeDelayedWork cap cur %x pend %x high %x, clamshell disable %x/%x\n",
8886 _currentCapability
, _pendingCapability
, _highestCapability
,
8887 clamshellDisabled
, clamshellSleepDisableMask
);
8889 if (clamshellExists
&&
8890 CAP_CURRENT(kIOPMSystemCapabilityGraphics
) &&
8891 !CAP_CHANGE(kIOPMSystemCapabilityGraphics
)) {
8892 if (clamshellSleepDisableMask
& kClamshellSleepDisableInternal
) {
8893 setClamShellSleepDisable(false, kClamshellSleepDisableInternal
);
8895 // Not the initial full wake after waking from sleep.
8896 // Evaluate the clamshell for rdar://problem/9157444.
8897 receivePowerNotification(kLocalEvalClamshellCommand
);
8903 //******************************************************************************
8904 // evaluateAssertions
8906 //******************************************************************************
8908 // Bitmask of all kernel assertions that prevent system idle sleep.
8909 // kIOPMDriverAssertionReservedBit7 is reserved for IOMediaBSDClient.
8910 #define NO_IDLE_SLEEP_ASSERTIONS_MASK \
8911 (kIOPMDriverAssertionReservedBit7 | \
8912 kIOPMDriverAssertionPreventSystemIdleSleepBit)
8915 IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions
, IOPMDriverAssertionType oldAssertions
)
8917 IOPMDriverAssertionType changedBits
= newAssertions
^ oldAssertions
;
8919 messageClients(kIOPMMessageDriverAssertionsChanged
);
8921 if (changedBits
& kIOPMDriverAssertionPreventDisplaySleepBit
) {
8923 bool value
= (newAssertions
& kIOPMDriverAssertionPreventDisplaySleepBit
) ? true : false;
8925 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value
);
8926 wrangler
->setIgnoreIdleTimer( value
);
8930 if (changedBits
& kIOPMDriverAssertionCPUBit
) {
8932 IOLog("CPU assertions %d\n", (0 != (kIOPMDriverAssertionCPUBit
& newAssertions
)));
8934 evaluatePolicy(_aotNow
? kStimulusNoIdleSleepPreventers
: kStimulusDarkWakeEvaluate
);
8935 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
8937 clock_usec_t microsecs
;
8938 clock_get_uptime(&now
);
8939 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
8940 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
8941 if (assertOnWakeReport
) {
8942 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
8943 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
8948 if (changedBits
& NO_IDLE_SLEEP_ASSERTIONS_MASK
) {
8949 if ((newAssertions
& NO_IDLE_SLEEP_ASSERTIONS_MASK
) != 0) {
8950 if ((oldAssertions
& NO_IDLE_SLEEP_ASSERTIONS_MASK
) == 0) {
8951 DLOG("PreventIdleSleep driver assertion raised\n");
8952 bool ok
= updatePreventIdleSleepList(this, true);
8953 if (ok
&& (changedBits
& kIOPMDriverAssertionPreventSystemIdleSleepBit
)) {
8954 // Cancel idle sleep if there is one in progress
8955 cancelIdlePowerDown(this);
8959 DLOG("PreventIdleSleep driver assertion dropped\n");
8960 updatePreventIdleSleepList(this, false);
8968 //******************************************************************************
8971 //******************************************************************************
8974 IOPMrootDomain::pmStatsRecordEvent(
8976 AbsoluteTime timestamp
)
8978 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
8979 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
8982 OSSharedPtr
<OSData
> publishPMStats
;
8984 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
8986 absolutetime_to_nanoseconds(timestamp
, &nsec
);
8988 switch (eventIndex
) {
8989 case kIOPMStatsHibernateImageWrite
:
8991 gPMStats
.hibWrite
.start
= nsec
;
8992 } else if (stopping
) {
8993 gPMStats
.hibWrite
.stop
= nsec
;
8997 delta
= gPMStats
.hibWrite
.stop
- gPMStats
.hibWrite
.start
;
8998 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/ NSEC_PER_MSEC
);
9001 case kIOPMStatsHibernateImageRead
:
9003 gPMStats
.hibRead
.start
= nsec
;
9004 } else if (stopping
) {
9005 gPMStats
.hibRead
.stop
= nsec
;
9009 delta
= gPMStats
.hibRead
.stop
- gPMStats
.hibRead
.start
;
9010 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/ NSEC_PER_MSEC
);
9012 publishPMStats
= OSData::withBytes(&gPMStats
, sizeof(gPMStats
));
9013 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
.get());
9014 bzero(&gPMStats
, sizeof(gPMStats
));
9021 * Appends a record of the application response to
9022 * IOPMrootDomain::pmStatsAppResponses
9025 IOPMrootDomain::pmStatsRecordApplicationResponse(
9026 const OSSymbol
*response
,
9032 IOPMPowerStateIndex powerState
,
9035 OSSharedPtr
<OSDictionary
> responseDescription
;
9036 OSSharedPtr
<OSNumber
> delayNum
;
9037 OSSharedPtr
<OSNumber
> powerCaps
;
9038 OSSharedPtr
<OSNumber
> pidNum
;
9039 OSSharedPtr
<OSNumber
> msgNum
;
9040 OSSharedPtr
<const OSSymbol
> appname
;
9041 OSSharedPtr
<const OSSymbol
> sleep
;
9042 OSSharedPtr
<const OSSymbol
> wake
;
9043 IOPMServiceInterestNotifier
*notify
= NULL
;
9045 if (object
&& (notify
= OSDynamicCast(IOPMServiceInterestNotifier
, object
))) {
9046 if (response
->isEqualTo(gIOPMStatsResponseTimedOut
.get())) {
9047 notify
->ackTimeoutCnt
++;
9049 notify
->ackTimeoutCnt
= 0;
9053 if (response
->isEqualTo(gIOPMStatsResponsePrompt
.get()) ||
9054 (_systemTransitionType
== kSystemTransitionNone
) || (_systemTransitionType
== kSystemTransitionNewCapClient
)) {
9059 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
.get())) {
9060 kdebugTrace(kPMLogDrvPSChangeDelay
, id
, messageType
, delay_ms
);
9061 } else if (notify
) {
9062 // User space app or kernel capability client
9064 kdebugTrace(kPMLogAppResponseDelay
, id
, notify
->msgType
, delay_ms
);
9066 kdebugTrace(kPMLogDrvResponseDelay
, notify
->uuid0
, messageType
, delay_ms
);
9068 notify
->msgType
= 0;
9071 responseDescription
= OSDictionary::withCapacity(5);
9072 if (responseDescription
) {
9074 responseDescription
->setObject(_statsResponseTypeKey
.get(), response
);
9077 msgNum
= OSNumber::withNumber(messageType
, 32);
9079 responseDescription
->setObject(_statsMessageTypeKey
.get(), msgNum
.get());
9082 if (!name
&& notify
&& notify
->identifier
) {
9083 name
= notify
->identifier
->getCStringNoCopy();
9086 if (name
&& (strlen(name
) > 0)) {
9087 appname
= OSSymbol::withCString(name
);
9089 responseDescription
->setObject(_statsNameKey
.get(), appname
.get());
9093 if (!id
&& notify
) {
9097 pidNum
= OSNumber::withNumber(id
, 64);
9099 responseDescription
->setObject(_statsPIDKey
.get(), pidNum
.get());
9103 delayNum
= OSNumber::withNumber(delay_ms
, 32);
9105 responseDescription
->setObject(_statsTimeMSKey
.get(), delayNum
.get());
9108 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
.get())) {
9109 powerCaps
= OSNumber::withNumber(powerState
, 32);
9111 #if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
9112 static const char * driverCallTypes
[] = {
9113 [kDriverCallInformPreChange
] = "powerStateWillChangeTo",
9114 [kDriverCallInformPostChange
] = "powerStateDidChangeTo",
9115 [kDriverCallSetPowerState
] = "setPowerState"
9118 if (messageType
< (sizeof(driverCallTypes
) / sizeof(driverCallTypes
[0]))) {
9119 DLOG("%s[0x%qx]::%s(%u) %stook %d ms\n",
9120 name
, id
, driverCallTypes
[messageType
], (uint32_t) powerState
,
9121 async
? "async " : "", delay_ms
);
9125 powerCaps
= OSNumber::withNumber(_pendingCapability
, 32);
9128 responseDescription
->setObject(_statsPowerCapsKey
.get(), powerCaps
.get());
9131 sleep
= OSSymbol::withCString("Sleep");
9132 wake
= OSSymbol::withCString("Wake");
9133 if (_systemTransitionType
== kSystemTransitionSleep
) {
9134 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
.get());
9135 } else if (_systemTransitionType
== kSystemTransitionWake
) {
9136 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
.get());
9137 } else if (_systemTransitionType
== kSystemTransitionCapability
) {
9138 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
)) {
9139 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
.get());
9140 } else if (CAP_GAIN(kIOPMSystemCapabilityGraphics
)) {
9141 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
.get());
9145 IOLockLock(pmStatsLock
);
9146 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount() < 50) {
9147 pmStatsAppResponses
->setObject(responseDescription
.get());
9149 IOLockUnlock(pmStatsLock
);
9156 // MARK: PMTraceWorker
9158 //******************************************************************************
9159 // TracePoint support
9161 //******************************************************************************
9163 #define kIOPMRegisterNVRAMTracePointHandlerKey \
9164 "IOPMRegisterNVRAMTracePointHandler"
9167 IOPMrootDomain::callPlatformFunction(
9168 const OSSymbol
* functionName
,
9169 bool waitForFunction
,
9170 void * param1
, void * param2
,
9171 void * param3
, void * param4
)
9173 if (pmTracer
&& functionName
&&
9174 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
9175 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
) {
9176 uint32_t tracePointPhases
, tracePointPCI
;
9177 uint64_t statusCode
;
9179 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
9180 pmTracer
->tracePointTarget
= (void *) param2
;
9181 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
9182 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
9183 if ((tracePointPhases
& 0xff) == kIOPMTracePointSystemSleep
) {
9184 OSSharedPtr
<IORegistryEntry
> node
= IORegistryEntry::fromPath( "/chosen", gIODTPlane
);
9186 OSSharedPtr
<OSObject
> bootRomFailureProp
;
9187 bootRomFailureProp
= node
->copyProperty(kIOEFIBootRomFailureKey
);
9188 OSData
*data
= OSDynamicCast(OSData
, bootRomFailureProp
.get());
9189 uint32_t bootFailureCode
;
9190 if (data
&& data
->getLength() == sizeof(bootFailureCode
)) {
9191 // Failure code from EFI/BootRom is a four byte structure
9192 memcpy(&bootFailureCode
, data
->getBytesNoCopy(), sizeof(bootFailureCode
));
9193 tracePointPCI
= OSSwapBigToHostInt32(bootFailureCode
);
9197 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
9198 if ((tracePointPhases
& 0xff) != kIOPMTracePointSystemUp
) {
9199 MSG("Sleep failure code 0x%08x 0x%08x\n",
9200 tracePointPCI
, tracePointPhases
);
9202 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
9203 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
9205 return kIOReturnSuccess
;
9208 else if (functionName
&&
9209 functionName
->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey
)) {
9210 if (gSleepPolicyHandler
) {
9211 return kIOReturnExclusiveAccess
;
9214 return kIOReturnBadArgument
;
9216 gSleepPolicyHandler
= (IOPMSystemSleepPolicyHandler
) param1
;
9217 gSleepPolicyTarget
= (void *) param2
;
9218 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue
);
9219 return kIOReturnSuccess
;
9223 return super::callPlatformFunction(
9224 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
9228 IOPMrootDomain::kdebugTrace(uint32_t event
, uint64_t id
,
9229 uintptr_t param1
, uintptr_t param2
, uintptr_t param3
)
9231 uint32_t code
= IODBG_POWER(event
);
9232 uint64_t regId
= id
;
9234 regId
= getRegistryEntryID();
9236 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE
, code
, (uintptr_t) regId
, param1
, param2
, param3
, 0);
9240 IOPMrootDomain::tracePoint( uint8_t point
)
9242 if (systemBooting
) {
9246 if (kIOPMTracePointWakeCapabilityClients
== point
) {
9247 acceptSystemWakeEvents(kAcceptSystemWakeEvents_Disable
);
9250 kdebugTrace(kPMLogSleepWakeTracePoint
, 0, point
, 0);
9251 pmTracer
->tracePoint(point
);
9255 kext_log_putc(char c
)
9257 if (gKextNameEnd
|| gKextNamePos
>= (sizeof(gKextNameBuf
) - 1)) {
9260 if (c
== '(' || c
== '[' || c
== ' ') {
9262 gKextNameEnd
= true;
9265 gKextNameBuf
[gKextNamePos
++] = c
;
9269 kext_log(const char *fmt
, ...)
9273 va_start(listp
, fmt
);
9274 _doprnt(fmt
, &listp
, &kext_log_putc
, 16);
9280 static OSPtr
<const OSSymbol
>
9281 copyKextIdentifierWithAddress(vm_address_t address
)
9283 OSSharedPtr
<const OSSymbol
> identifer
;
9285 IOLockLock(gHaltLogLock
);
9287 gKextNameEnd
= false;
9289 gKextNameBuf
[0] = 0;
9291 OSKext::printKextsInBacktrace(&address
, 1, kext_log
, OSKext::kPrintKextsLock
| OSKext::kPrintKextsTerse
);
9292 gKextNameBuf
[sizeof(gKextNameBuf
) - 1] = 0;
9293 identifer
= OSSymbol::withCString((gKextNameBuf
[0] != 0) ? gKextNameBuf
: kOSKextKernelIdentifier
);
9295 IOLockUnlock(gHaltLogLock
);
9300 // Caller serialized using PM workloop
9302 IOPMrootDomain::getNotificationClientName(OSObject
*object
)
9304 IOPMServiceInterestNotifier
*notifier
= (typeof(notifier
))object
;
9305 const char *clientName
= "UNKNOWN";
9307 if (!notifier
->clientName
) {
9308 // Check for user client
9309 if (systemCapabilityNotifier
&& (((IOPMServiceInterestNotifier
*) systemCapabilityNotifier
.get())->handler
== notifier
->handler
)) {
9310 OSNumber
*clientID
= NULL
;
9311 messageClient(kIOMessageCopyClientID
, object
, &clientID
);
9313 OSSharedPtr
<OSString
> string(IOCopyLogNameForPID(clientID
->unsigned32BitValue()), OSNoRetain
);
9315 notifier
->clientName
= OSSymbol::withString(string
.get());
9317 clientID
->release();
9319 } else if (notifier
->identifier
) {
9320 notifier
->clientName
.reset(notifier
->identifier
.get(), OSRetain
);
9324 if (notifier
->clientName
) {
9325 clientName
= notifier
->clientName
->getCStringNoCopy();
9332 IOPMrootDomain::traceNotification(OSObject
*object
, bool start
, uint64_t timestamp
, uint32_t msgIndex
)
9334 IOPMServiceInterestNotifier
*notifier
;
9336 if (systemBooting
) {
9339 notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, object
);
9345 pmTracer
->traceDetail(notifier
->uuid0
>> 32);
9346 kdebugTrace(kPMLogSleepWakeMessage
, pmTracer
->getTracePhase(),
9347 (uintptr_t) notifier
->msgType
, (uintptr_t) notifier
->uuid0
, (uintptr_t) notifier
->uuid1
);
9349 // Update notifier state used for response/ack logging
9350 notifier
->msgIndex
= msgIndex
;
9351 notifier
->msgAbsTime
= timestamp
;
9353 if (msgIndex
!= UINT_MAX
) {
9354 DLOG("%s[%u] to %s\n", getIOMessageString(notifier
->msgType
), msgIndex
, getNotificationClientName(notifier
));
9356 DLOG("%s to %s\n", getIOMessageString(notifier
->msgType
), getNotificationClientName(notifier
));
9359 assert(notifierObject
== NULL
);
9360 notifierThread
= current_thread();
9361 notifierObject
.reset(notifier
, OSRetain
);
9366 SUB_ABSOLUTETIME(×tamp
, ¬ifier
->msgAbsTime
);
9367 absolutetime_to_nanoseconds(timestamp
, &nsec
);
9368 delayMS
= (uint32_t)(nsec
/ 1000000ULL);
9369 if (delayMS
> notifier
->maxMsgDelayMS
) {
9370 notifier
->maxMsgDelayMS
= delayMS
;
9373 assert(notifierObject
== notifier
);
9374 notifierObject
.reset();
9375 notifierThread
= NULL
;
9380 IOPMrootDomain::traceNotificationAck(OSObject
*object
, uint32_t delay_ms
)
9382 if (systemBooting
) {
9385 IOPMServiceInterestNotifier
*notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, object
);
9390 kdebugTrace(kPMLogDrvResponseDelay
, notifier
->uuid0
,
9391 (uintptr_t) notifier
->uuid1
, (uintptr_t) 0, (uintptr_t) delay_ms
);
9393 DLOG("%s[%u] ack from %s took %d ms\n",
9394 getIOMessageString(notifier
->msgType
), notifier
->msgIndex
, getNotificationClientName(notifier
), delay_ms
);
9395 if (delay_ms
> notifier
->maxAckDelayMS
) {
9396 notifier
->maxAckDelayMS
= delay_ms
;
9401 IOPMrootDomain::traceNotificationResponse(OSObject
*object
, uint32_t delay_ms
, uint32_t ack_time_us
)
9403 if (systemBooting
) {
9406 IOPMServiceInterestNotifier
*notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, object
);
9411 kdebugTrace(kPMLogDrvResponseDelay
, notifier
->uuid0
,
9412 (uintptr_t) notifier
->uuid1
, (uintptr_t)(ack_time_us
/ 1000), (uintptr_t) delay_ms
);
9414 if (ack_time_us
== 0) {
9415 // Client work is done and ack will not be forthcoming
9416 DLOG("%s[%u] response from %s took %d ms\n",
9417 getIOMessageString(notifier
->msgType
), notifier
->msgIndex
, getNotificationClientName(notifier
), delay_ms
);
9419 // Client needs more time and it must ack within ack_time_us
9420 DLOG("%s[%u] response from %s took %d ms (ack in %d us)\n",
9421 getIOMessageString(notifier
->msgType
), notifier
->msgIndex
, getNotificationClientName(notifier
), delay_ms
, ack_time_us
);
9426 IOPMrootDomain::traceFilteredNotification(OSObject
*object
)
9428 if ((kIOLogDebugPower
& gIOKitDebug
) == 0) {
9431 if (systemBooting
) {
9434 IOPMServiceInterestNotifier
*notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, object
);
9439 DLOG("%s to %s dropped\n", getIOMessageString(notifier
->msgType
), getNotificationClientName(notifier
));
9443 IOPMrootDomain::traceDetail(uint32_t msgType
, uint32_t msgIndex
, uint32_t delay
)
9445 if (!systemBooting
) {
9446 uint32_t detail
= ((msgType
& 0xffff) << 16) | (delay
& 0xffff);
9447 pmTracer
->traceDetail( detail
);
9448 kdebugTrace(kPMLogSleepWakeTracePoint
, pmTracer
->getTracePhase(), msgType
, delay
);
9449 DLOG("trace point 0x%02x msgType 0x%x detail 0x%08x\n", pmTracer
->getTracePhase(), msgType
, delay
);
9454 IOPMrootDomain::configureReportGated(uint64_t channel_id
, uint64_t action
, void *result
)
9457 void **report
= NULL
;
9460 uint32_t *clientCnt
;
9465 if (channel_id
== kAssertDelayChID
) {
9466 report
= &assertOnWakeReport
;
9467 bktCnt
= kAssertDelayBcktCnt
;
9468 bktSize
= kAssertDelayBcktSize
;
9469 clientCnt
= &assertOnWakeClientCnt
;
9470 } else if (channel_id
== kSleepDelaysChID
) {
9471 report
= &sleepDelaysReport
;
9472 bktCnt
= kSleepDelaysBcktCnt
;
9473 bktSize
= kSleepDelaysBcktSize
;
9474 clientCnt
= &sleepDelaysClientCnt
;
9481 case kIOReportEnable
:
9488 reportSize
= HISTREPORT_BUFSIZE(bktCnt
);
9489 *report
= IOMalloc(reportSize
);
9490 if (*report
== NULL
) {
9493 bzero(*report
, reportSize
);
9494 HISTREPORT_INIT((uint16_t)bktCnt
, bktSize
, *report
, reportSize
,
9495 getRegistryEntryID(), channel_id
, kIOReportCategoryPower
);
9497 if (channel_id
== kAssertDelayChID
) {
9498 assertOnWakeSecs
= 0;
9503 case kIOReportDisable
:
9504 if (*clientCnt
== 0) {
9507 if (*clientCnt
== 1) {
9508 IOFree(*report
, HISTREPORT_BUFSIZE(bktCnt
));
9513 if (channel_id
== kAssertDelayChID
) {
9514 assertOnWakeSecs
= -1; // Invalid value to prevent updates
9518 case kIOReportGetDimensions
:
9520 HISTREPORT_UPDATERES(*report
, kIOReportGetDimensions
, result
);
9529 IOPMrootDomain::configureReport(IOReportChannelList
*channelList
,
9530 IOReportConfigureAction action
,
9535 uint64_t configAction
= (uint64_t)action
;
9537 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
9538 if ((channelList
->channels
[cnt
].channel_id
== kSleepCntChID
) ||
9539 (channelList
->channels
[cnt
].channel_id
== kDarkWkCntChID
) ||
9540 (channelList
->channels
[cnt
].channel_id
== kUserWkCntChID
)) {
9541 if (action
!= kIOReportGetDimensions
) {
9544 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions
, result
);
9545 } else if ((channelList
->channels
[cnt
].channel_id
== kAssertDelayChID
) ||
9546 (channelList
->channels
[cnt
].channel_id
== kSleepDelaysChID
)) {
9547 gIOPMWorkLoop
->runAction(
9548 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::configureReportGated
),
9549 (OSObject
*)this, (void *)channelList
->channels
[cnt
].channel_id
,
9550 (void *)configAction
, (void *)result
);
9554 return super::configureReport(channelList
, action
, result
, destination
);
9558 IOPMrootDomain::updateReportGated(uint64_t ch_id
, void *result
, IOBufferMemoryDescriptor
*dest
)
9567 if (ch_id
== kAssertDelayChID
) {
9568 report
= &assertOnWakeReport
;
9569 } else if (ch_id
== kSleepDelaysChID
) {
9570 report
= &sleepDelaysReport
;
9573 return kIOReturnBadArgument
;
9576 if (*report
== NULL
) {
9577 return kIOReturnNotOpen
;
9580 HISTREPORT_UPDATEPREP(*report
, data2cpy
, size2cpy
);
9581 if (size2cpy
> (dest
->getCapacity() - dest
->getLength())) {
9582 return kIOReturnOverrun
;
9585 HISTREPORT_UPDATERES(*report
, kIOReportCopyChannelData
, result
);
9586 dest
->appendBytes(data2cpy
, size2cpy
);
9588 return kIOReturnSuccess
;
9592 IOPMrootDomain::updateReport(IOReportChannelList
*channelList
,
9593 IOReportUpdateAction action
,
9599 uint8_t buf
[SIMPLEREPORT_BUFSIZE
];
9600 IOBufferMemoryDescriptor
*dest
= OSDynamicCast(IOBufferMemoryDescriptor
, (OSObject
*)destination
);
9604 if (action
!= kIOReportCopyChannelData
) {
9608 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
9609 ch_id
= channelList
->channels
[cnt
].channel_id
;
9611 if ((ch_id
== kAssertDelayChID
) || (ch_id
== kSleepDelaysChID
)) {
9612 gIOPMWorkLoop
->runAction(
9613 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::updateReportGated
),
9614 (OSObject
*)this, (void *)ch_id
,
9615 (void *)result
, (void *)dest
);
9617 } else if ((ch_id
== kSleepCntChID
) ||
9618 (ch_id
== kDarkWkCntChID
) || (ch_id
== kUserWkCntChID
)) {
9619 SIMPLEREPORT_INIT(buf
, sizeof(buf
), getRegistryEntryID(), ch_id
, kIOReportCategoryPower
);
9624 if (ch_id
== kSleepCntChID
) {
9625 SIMPLEREPORT_SETVALUE(buf
, sleepCnt
);
9626 } else if (ch_id
== kDarkWkCntChID
) {
9627 SIMPLEREPORT_SETVALUE(buf
, darkWakeCnt
);
9628 } else if (ch_id
== kUserWkCntChID
) {
9629 SIMPLEREPORT_SETVALUE(buf
, displayWakeCnt
);
9632 SIMPLEREPORT_UPDATEPREP(buf
, data2cpy
, size2cpy
);
9633 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData
, result
);
9634 dest
->appendBytes(data2cpy
, size2cpy
);
9638 return super::updateReport(channelList
, action
, result
, destination
);
9642 //******************************************************************************
9643 // PMTraceWorker Class
9645 //******************************************************************************
9648 #define super OSObject
9649 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
9651 #define kPMBestGuessPCIDevicesCount 25
9652 #define kPMMaxRTCBitfieldSize 32
9654 OSPtr
<PMTraceWorker
>
9655 PMTraceWorker::tracer(IOPMrootDomain
* owner
)
9657 OSSharedPtr
<PMTraceWorker
> me
= OSMakeShared
<PMTraceWorker
>();
9658 if (!me
|| !me
->init()) {
9662 DLOG("PMTraceWorker %p\n", OBFUSCATE(me
.get()));
9664 // Note that we cannot instantiate the PCI device -> bit mappings here, since
9665 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
9666 // this dictionary lazily.
9668 me
->pciDeviceBitMappings
= NULL
;
9669 me
->pmTraceWorkerLock
= IOLockAlloc();
9670 me
->tracePhase
= kIOPMTracePointSystemUp
;
9671 me
->traceData32
= 0;
9672 me
->loginWindowData
= 0;
9673 me
->coreDisplayData
= 0;
9674 me
->coreGraphicsData
= 0;
9679 PMTraceWorker::RTC_TRACE(void)
9681 if (tracePointHandler
&& tracePointTarget
) {
9684 IOLockLock(pmTraceWorkerLock
);
9685 wordA
= (loginWindowData
<< 24) | (coreDisplayData
<< 16) |
9686 (coreGraphicsData
<< 8) | tracePhase
;
9687 IOLockUnlock(pmTraceWorkerLock
);
9689 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
9690 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
9692 #if DEVELOPMENT || DEBUG
9693 if ((swd_panic_phase
!= 0) && (swd_panic_phase
== tracePhase
)) {
9694 DEBUG_LOG("Causing sleep wake failure in phase 0x%08x\n", tracePhase
);
9695 IOLock
*l
= IOLockAlloc();
9703 PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
9705 OSSharedPtr
<const OSSymbol
> deviceName
;
9708 IOLockLock(pmTraceWorkerLock
);
9710 if (!pciDeviceBitMappings
) {
9711 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
9712 if (!pciDeviceBitMappings
) {
9717 // Check for bitmask overflow.
9718 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
) {
9722 if ((deviceName
= pciDevice
->copyName()) &&
9723 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
.get(), 0) == (unsigned int)-1) &&
9724 pciDeviceBitMappings
->setObject(deviceName
.get())) {
9725 index
= pciDeviceBitMappings
->getCount() - 1;
9726 _LOG("PMTrace PCI array: set object %s => %d\n",
9727 deviceName
->getCStringNoCopy(), index
);
9730 if (!addedToRegistry
&& (index
>= 0)) {
9731 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
9735 IOLockUnlock(pmTraceWorkerLock
);
9740 PMTraceWorker::serialize(OSSerialize
*s
) const
9743 if (pciDeviceBitMappings
) {
9744 IOLockLock(pmTraceWorkerLock
);
9745 ok
= pciDeviceBitMappings
->serialize(s
);
9746 IOLockUnlock(pmTraceWorkerLock
);
9752 PMTraceWorker::tracePoint(uint8_t phase
)
9754 // clear trace detail when phase begins
9755 if (tracePhase
!= phase
) {
9761 DLOG("trace point 0x%02x\n", tracePhase
);
9766 PMTraceWorker::traceDetail(uint32_t detail
)
9768 if (detail
== traceData32
) {
9771 traceData32
= detail
;
9776 PMTraceWorker::traceComponentWakeProgress(uint32_t component
, uint32_t data
)
9778 switch (component
) {
9779 case kIOPMLoginWindowProgress
:
9780 loginWindowData
= data
& kIOPMLoginWindowProgressMask
;
9782 case kIOPMCoreDisplayProgress
:
9783 coreDisplayData
= data
& kIOPMCoreDisplayProgressMask
;
9785 case kIOPMCoreGraphicsProgress
:
9786 coreGraphicsData
= data
& kIOPMCoreGraphicsProgressMask
;
9792 DLOG("component trace point 0x%02x data 0x%08x\n", component
, data
);
9797 PMTraceWorker::tracePCIPowerChange(
9798 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
9801 uint32_t expectedFlag
;
9803 // Ignore PCI changes outside of system sleep/wake.
9804 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
9805 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
)) {
9809 // Only record the WillChange transition when going to sleep,
9810 // and the DidChange on the way up.
9811 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
9812 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
9813 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
9814 if (changeFlags
!= expectedFlag
) {
9818 // Mark this device off in our bitfield
9819 if (bitNum
< kPMMaxRTCBitfieldSize
) {
9820 bitMask
= (1 << bitNum
);
9822 if (kPowerChangeStart
== type
) {
9823 traceData32
|= bitMask
;
9824 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
9825 service
->getName(), bitNum
, bitMask
, traceData32
);
9826 owner
->kdebugTrace(kPMLogPCIDevChangeStart
, service
->getRegistryEntryID(), traceData32
, 0);
9828 traceData32
&= ~bitMask
;
9829 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
9830 service
->getName(), bitNum
, bitMask
, traceData32
);
9831 owner
->kdebugTrace(kPMLogPCIDevChangeDone
, service
->getRegistryEntryID(), traceData32
, 0);
9834 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
9840 PMTraceWorker::getPMStatusCode()
9842 return ((uint64_t)traceData32
<< 32) | ((uint64_t)tracePhase
);
9846 PMTraceWorker::getTracePhase()
9852 PMTraceWorker::getTraceData()
9858 // MARK: PMHaltWorker
9860 //******************************************************************************
9861 // PMHaltWorker Class
9863 //******************************************************************************
9866 PMHaltWorker::worker( void )
9872 me
= OSTypeAlloc( PMHaltWorker
);
9873 if (!me
|| !me
->init()) {
9877 me
->lock
= IOLockAlloc();
9882 DLOG("PMHaltWorker %p\n", OBFUSCATE(me
));
9883 me
->retain(); // thread holds extra retain
9884 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
)) {
9888 thread_deallocate(thread
);
9899 PMHaltWorker::free( void )
9901 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
9906 return OSObject::free();
9910 PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
9912 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
9914 IOLockLock( gPMHaltLock
);
9916 me
->depth
= gPMHaltDepth
;
9917 IOLockUnlock( gPMHaltLock
);
9919 while (me
->depth
>= 0) {
9920 PMHaltWorker::work( me
);
9922 IOLockLock( gPMHaltLock
);
9923 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
) {
9924 // This is the last thread to finish work on this level,
9925 // inform everyone to start working on next lower level.
9927 me
->depth
= gPMHaltDepth
;
9928 gPMHaltIdleCount
= 0;
9929 thread_wakeup((event_t
) &gPMHaltIdleCount
);
9931 // One or more threads are still working on this level,
9932 // this thread must wait.
9933 me
->depth
= gPMHaltDepth
- 1;
9935 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
9936 } while (me
->depth
!= gPMHaltDepth
);
9938 IOLockUnlock( gPMHaltLock
);
9941 // No more work to do, terminate thread
9942 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me
), me
->visits
);
9943 thread_wakeup( &gPMHaltDepth
);
9948 PMHaltWorker::work( PMHaltWorker
* me
)
9950 OSSharedPtr
<IOService
> service
;
9952 AbsoluteTime startTime
, elapsedTime
;
9959 // Claim an unit of work from the shared pool
9960 IOLockLock( gPMHaltLock
);
9961 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
9963 service
.reset(OSDynamicCast(IOService
, inner
->getAnyObject()), OSRetain
);
9965 inner
->removeObject(service
.get());
9968 IOLockUnlock( gPMHaltLock
);
9970 break; // no more work at this depth
9972 clock_get_uptime(&startTime
);
9974 if (!service
->isInactive() &&
9975 service
->setProperty(gPMHaltClientAcknowledgeKey
.get(), me
)) {
9976 IOLockLock(me
->lock
);
9977 me
->startTime
= startTime
;
9978 me
->service
= service
.get();
9979 me
->timeout
= false;
9980 IOLockUnlock(me
->lock
);
9982 service
->systemWillShutdown( gPMHaltMessageType
);
9984 // Wait for driver acknowledgement
9985 IOLockLock(me
->lock
);
9986 while (service
->propertyExists(gPMHaltClientAcknowledgeKey
.get())) {
9987 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
9990 timeout
= me
->timeout
;
9991 IOLockUnlock(me
->lock
);
9994 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
9995 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
) {
9996 LOG("%s driver %s (0x%llx) took %u ms\n",
9997 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ?
9998 "PowerOff" : "Restart",
9999 service
->getName(), service
->getRegistryEntryID(),
10000 (uint32_t) deltaTime
);
10001 halt_log_enter("PowerOff/Restart handler completed",
10002 OSMemberFunctionCast(const void *, service
.get(), &IOService::systemWillShutdown
),
10011 PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
10014 AbsoluteTime startTime
;
10015 AbsoluteTime endTime
;
10019 IOLockLock(me
->lock
);
10020 if (me
->service
&& !me
->timeout
) {
10021 startTime
= me
->startTime
;
10023 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0) {
10024 SUB_ABSOLUTETIME(&endTime
, &startTime
);
10025 absolutetime_to_nanoseconds(endTime
, &nano
);
10027 if (nano
> 3000000000ULL) {
10028 me
->timeout
= true;
10030 halt_log_enter("PowerOff/Restart still waiting on handler",
10031 OSMemberFunctionCast(const void *, me
->service
, &IOService::systemWillShutdown
),
10033 MSG("%s still waiting on %s\n",
10034 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" : "Restart",
10035 me
->service
->getName());
10038 IOLockUnlock(me
->lock
);
10041 //******************************************************************************
10042 // acknowledgeSystemWillShutdown
10044 // Acknowledgement from drivers that they have prepared for shutdown/restart.
10045 //******************************************************************************
10048 IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
10050 PMHaltWorker
* worker
;
10051 OSSharedPtr
<OSObject
> prop
;
10057 //DLOG("%s acknowledged\n", from->getName());
10058 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
.get());
10060 worker
= (PMHaltWorker
*) prop
.get();
10061 IOLockLock(worker
->lock
);
10062 from
->removeProperty( gPMHaltClientAcknowledgeKey
.get());
10063 thread_wakeup((event_t
) worker
);
10064 IOLockUnlock(worker
->lock
);
10066 DLOG("%s acknowledged without worker property\n",
10072 //******************************************************************************
10073 // notifySystemShutdown
10075 // Notify all objects in PM tree that system will shutdown or restart
10076 //******************************************************************************
10079 notifySystemShutdown( IOService
* root
, uint32_t messageType
)
10081 #define PLACEHOLDER ((OSSet *)gPMHaltArray.get())
10082 OSSharedPtr
<IORegistryIterator
> iter
;
10083 IORegistryEntry
* entry
;
10086 OSSharedPtr
<OSSet
> newInner
;
10087 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
10088 AbsoluteTime deadline
;
10089 unsigned int totalNodes
= 0;
10090 unsigned int depth
;
10091 unsigned int rootDepth
;
10092 unsigned int numWorkers
;
10093 unsigned int count
;
10098 DLOG("%s msgType = 0x%x\n", __FUNCTION__
, messageType
);
10100 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
10102 // Iterate the entire PM tree starting from root
10104 rootDepth
= root
->getDepth( gIOPowerPlane
);
10109 // debug - for repeated test runs
10110 while (PMHaltWorker::metaClass
->getInstanceCount()) {
10114 if (!gPMHaltArray
) {
10115 gPMHaltArray
= OSArray::withCapacity(40);
10116 if (!gPMHaltArray
) {
10120 gPMHaltArray
->flushCollection();
10123 if (!gPMHaltLock
) {
10124 gPMHaltLock
= IOLockAlloc();
10125 if (!gPMHaltLock
) {
10130 if (!gPMHaltClientAcknowledgeKey
) {
10131 gPMHaltClientAcknowledgeKey
=
10132 OSSymbol::withCStringNoCopy("PMShutdown");
10133 if (!gPMHaltClientAcknowledgeKey
) {
10138 gPMHaltMessageType
= messageType
;
10140 // Depth-first walk of PM plane
10142 iter
= IORegistryIterator::iterateOver(
10143 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
10146 while ((entry
= iter
->getNextObject())) {
10147 node
= OSDynamicCast(IOService
, entry
);
10153 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
)) {
10157 depth
= node
->getDepth( gIOPowerPlane
);
10158 if (depth
<= rootDepth
) {
10164 // adjust to zero based depth
10165 depth
-= (rootDepth
+ 1);
10167 // gPMHaltArray is an array of containers, each container
10168 // refers to nodes with the same depth.
10170 count
= gPMHaltArray
->getCount();
10171 while (depth
>= count
) {
10172 // expand array and insert placeholders
10173 gPMHaltArray
->setObject(PLACEHOLDER
);
10176 count
= gPMHaltArray
->getCount();
10177 if (depth
< count
) {
10178 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
10179 if (inner
== PLACEHOLDER
) {
10180 newInner
= OSSet::withCapacity(40);
10182 gPMHaltArray
->replaceObject(depth
, newInner
.get());
10183 inner
= newInner
.get();
10187 // PM nodes that appear more than once in the tree will have
10188 // the same depth, OSSet will refuse to add the node twice.
10190 ok
= inner
->setObject(node
);
10194 DLOG("Skipped PM node %s\n", node
->getName());
10200 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++) {
10202 if (inner
!= PLACEHOLDER
) {
10203 count
= inner
->getCount();
10205 DLOG("Nodes at depth %u = %u\n", i
, count
);
10208 // strip placeholders (not all depths are populated)
10210 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
));) {
10211 if (inner
== PLACEHOLDER
) {
10212 gPMHaltArray
->removeObject(i
);
10215 count
= inner
->getCount();
10216 if (count
> numWorkers
) {
10217 numWorkers
= count
;
10219 totalNodes
+= count
;
10223 if (gPMHaltArray
->getCount() == 0 || !numWorkers
) {
10227 gPMHaltBusyCount
= 0;
10228 gPMHaltIdleCount
= 0;
10229 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
10231 // Create multiple workers (and threads)
10233 if (numWorkers
> kPMHaltMaxWorkers
) {
10234 numWorkers
= kPMHaltMaxWorkers
;
10237 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
10238 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
10240 for (unsigned int i
= 0; i
< numWorkers
; i
++) {
10241 workers
[i
] = PMHaltWorker::worker();
10244 // Wait for workers to exhaust all available work
10246 IOLockLock(gPMHaltLock
);
10247 while (gPMHaltDepth
>= 0) {
10248 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
10250 waitResult
= IOLockSleepDeadline(
10251 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
10252 if (THREAD_TIMED_OUT
== waitResult
) {
10254 clock_get_uptime(&now
);
10256 IOLockUnlock(gPMHaltLock
);
10257 for (unsigned int i
= 0; i
< numWorkers
; i
++) {
10259 PMHaltWorker::checkTimeout(workers
[i
], &now
);
10262 IOLockLock(gPMHaltLock
);
10265 IOLockUnlock(gPMHaltLock
);
10267 // Release all workers
10269 for (unsigned int i
= 0; i
< numWorkers
; i
++) {
10271 workers
[i
]->release();
10273 // worker also retained by it's own thread
10277 DLOG("%s done\n", __FUNCTION__
);
10282 // MARK: Kernel Assertion
10284 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10286 IOPMDriverAssertionID
10287 IOPMrootDomain::createPMAssertion(
10288 IOPMDriverAssertionType whichAssertionBits
,
10289 IOPMDriverAssertionLevel assertionLevel
,
10290 IOService
*ownerService
,
10291 const char *ownerDescription
)
10294 IOPMDriverAssertionID newAssertion
;
10296 if (!pmAssertions
) {
10300 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
10302 if (kIOReturnSuccess
== ret
) {
10303 return newAssertion
;
10310 IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
10312 if (!pmAssertions
) {
10313 return kIOReturnInternalError
;
10316 return pmAssertions
->releaseAssertion(releaseAssertion
);
10321 IOPMrootDomain::setPMAssertionLevel(
10322 IOPMDriverAssertionID assertionID
,
10323 IOPMDriverAssertionLevel assertionLevel
)
10325 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
10328 IOPMDriverAssertionLevel
10329 IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
10331 IOPMDriverAssertionType sysLevels
;
10333 if (!pmAssertions
|| whichAssertion
== 0) {
10334 return kIOPMDriverAssertionLevelOff
;
10337 sysLevels
= pmAssertions
->getActivatedAssertions();
10339 // Check that every bit set in argument 'whichAssertion' is asserted
10340 // in the aggregate bits.
10341 if ((sysLevels
& whichAssertion
) == whichAssertion
) {
10342 return kIOPMDriverAssertionLevelOn
;
10344 return kIOPMDriverAssertionLevelOff
;
10349 IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
10351 if (!pmAssertions
) {
10352 return kIOReturnNotFound
;
10355 return pmAssertions
->setUserAssertionLevels(inLevels
);
10359 IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
10361 if (pmAssertions
) {
10362 pmAssertions
->publishProperties();
10364 return IOService::serializeProperties(s
);
10367 OSSharedPtr
<OSObject
>
10368 IOPMrootDomain::copyProperty( const char * aKey
) const
10370 OSSharedPtr
<OSObject
> obj
;
10371 obj
= IOService::copyProperty(aKey
);
10377 if (!strncmp(aKey
, kIOPMSleepWakeWdogRebootKey
,
10378 sizeof(kIOPMSleepWakeWdogRebootKey
))) {
10379 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
10380 return OSSharedPtr
<OSBoolean
>(kOSBooleanTrue
, OSNoRetain
);
10382 return OSSharedPtr
<OSBoolean
>(kOSBooleanFalse
, OSNoRetain
);
10386 if (!strncmp(aKey
, kIOPMSleepWakeWdogLogsValidKey
,
10387 sizeof(kIOPMSleepWakeWdogLogsValidKey
))) {
10388 if (swd_flags
& SWD_VALID_LOGS
) {
10389 return OSSharedPtr
<OSBoolean
>(kOSBooleanTrue
, OSNoRetain
);
10391 return OSSharedPtr
<OSBoolean
>(kOSBooleanFalse
, OSNoRetain
);
10396 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
10397 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
10398 * issued by DisplayWrangler on darkwake.
10400 if (!strcmp(aKey
, "DesktopMode")) {
10402 return OSSharedPtr
<OSBoolean
>(kOSBooleanTrue
, OSNoRetain
);
10404 return OSSharedPtr
<OSBoolean
>(kOSBooleanFalse
, OSNoRetain
);
10407 if (!strcmp(aKey
, "DisplayIdleForDemandSleep")) {
10408 if (displayIdleForDemandSleep
) {
10409 return OSSharedPtr
<OSBoolean
>(kOSBooleanTrue
, OSNoRetain
);
10411 return OSSharedPtr
<OSBoolean
>(kOSBooleanFalse
, OSNoRetain
);
10415 if (!strcmp(aKey
, kIOPMDriverWakeEventsKey
)) {
10416 OSSharedPtr
<OSArray
> array
;
10418 if (_systemWakeEventsArray
&& _systemWakeEventsArray
->getCount()) {
10419 OSSharedPtr
<OSCollection
> collection
= _systemWakeEventsArray
->copyCollection();
10421 array
= OSDynamicPtrCast
<OSArray
>(collection
);
10424 WAKEEVENT_UNLOCK();
10425 return os::move(array
);
10428 if (!strcmp(aKey
, kIOPMSleepStatisticsAppsKey
)) {
10429 OSSharedPtr
<OSArray
> array
;
10430 IOLockLock(pmStatsLock
);
10431 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount()) {
10432 OSSharedPtr
<OSCollection
> collection
= pmStatsAppResponses
->copyCollection();
10434 array
= OSDynamicPtrCast
<OSArray
>(collection
);
10437 IOLockUnlock(pmStatsLock
);
10438 return os::move(array
);
10441 if (!strcmp(aKey
, kIOPMIdleSleepPreventersKey
)) {
10442 OSArray
*idleSleepList
= NULL
;
10443 gRootDomain
->copySleepPreventersList(&idleSleepList
, NULL
);
10444 return OSSharedPtr
<OSArray
>(idleSleepList
, OSNoRetain
);
10447 if (!strcmp(aKey
, kIOPMSystemSleepPreventersKey
)) {
10448 OSArray
*systemSleepList
= NULL
;
10449 gRootDomain
->copySleepPreventersList(NULL
, &systemSleepList
);
10450 return OSSharedPtr
<OSArray
>(systemSleepList
, OSNoRetain
);
10453 if (!strcmp(aKey
, kIOPMIdleSleepPreventersWithIDKey
)) {
10454 OSArray
*idleSleepList
= NULL
;
10455 gRootDomain
->copySleepPreventersListWithID(&idleSleepList
, NULL
);
10456 return OSSharedPtr
<OSArray
>(idleSleepList
, OSNoRetain
);
10459 if (!strcmp(aKey
, kIOPMSystemSleepPreventersWithIDKey
)) {
10460 OSArray
*systemSleepList
= NULL
;
10461 gRootDomain
->copySleepPreventersListWithID(NULL
, &systemSleepList
);
10462 return OSSharedPtr
<OSArray
>(systemSleepList
, OSNoRetain
);
10468 // MARK: Wake Event Reporting
10471 IOPMrootDomain::copyWakeReasonString( char * outBuf
, size_t bufSize
)
10474 strlcpy(outBuf
, gWakeReasonString
, bufSize
);
10475 WAKEEVENT_UNLOCK();
10479 IOPMrootDomain::copyShutdownReasonString( char * outBuf
, size_t bufSize
)
10482 strlcpy(outBuf
, gShutdownReasonString
, bufSize
);
10483 WAKEEVENT_UNLOCK();
10486 //******************************************************************************
10487 // acceptSystemWakeEvents
10489 // Private control for the acceptance of driver wake event claims.
10490 //******************************************************************************
10493 IOPMrootDomain::acceptSystemWakeEvents( uint32_t control
)
10495 bool logWakeReason
= false;
10499 case kAcceptSystemWakeEvents_Enable
:
10500 assert(_acceptSystemWakeEvents
== false);
10501 if (!_systemWakeEventsArray
) {
10502 _systemWakeEventsArray
= OSArray::withCapacity(4);
10504 _acceptSystemWakeEvents
= (_systemWakeEventsArray
!= NULL
);
10505 if (!(_aotNow
&& (kIOPMWakeEventAOTExitFlags
& _aotPendingFlags
))) {
10506 gWakeReasonString
[0] = '\0';
10507 if (_systemWakeEventsArray
) {
10508 _systemWakeEventsArray
->flushCollection();
10512 // Remove stale WakeType property before system sleep
10513 removeProperty(kIOPMRootDomainWakeTypeKey
);
10514 removeProperty(kIOPMRootDomainWakeReasonKey
);
10517 case kAcceptSystemWakeEvents_Disable
:
10518 _acceptSystemWakeEvents
= false;
10519 #if defined(XNU_TARGET_OS_OSX)
10520 logWakeReason
= (gWakeReasonString
[0] != '\0');
10521 #else /* !defined(XNU_TARGET_OS_OSX) */
10522 logWakeReason
= gWakeReasonSysctlRegistered
;
10524 static int panic_allowed
= -1;
10526 if ((panic_allowed
== -1) &&
10527 (PE_parse_boot_argn("swd_wakereason_panic", &panic_allowed
, sizeof(panic_allowed
)) == false)) {
10531 if (panic_allowed
) {
10533 // Panic if wake reason is null or empty
10534 for (i
= 0; (i
< strlen(gWakeReasonString
)); i
++) {
10535 if ((gWakeReasonString
[i
] != ' ') && (gWakeReasonString
[i
] != '\t')) {
10539 if (i
>= strlen(gWakeReasonString
)) {
10540 panic("Wake reason is empty\n");
10543 #endif /* DEVELOPMENT */
10544 #endif /* !defined(XNU_TARGET_OS_OSX) */
10546 // publish kIOPMRootDomainWakeReasonKey if not already set
10547 if (!propertyExists(kIOPMRootDomainWakeReasonKey
)) {
10548 setProperty(kIOPMRootDomainWakeReasonKey
, gWakeReasonString
);
10552 case kAcceptSystemWakeEvents_Reenable
:
10553 assert(_acceptSystemWakeEvents
== false);
10554 _acceptSystemWakeEvents
= (_systemWakeEventsArray
!= NULL
);
10555 removeProperty(kIOPMRootDomainWakeReasonKey
);
10558 WAKEEVENT_UNLOCK();
10560 if (logWakeReason
) {
10561 MSG("system wake events: %s\n", gWakeReasonString
);
10565 //******************************************************************************
10566 // claimSystemWakeEvent
10568 // For a driver to claim a device is the source/conduit of a system wake event.
10569 //******************************************************************************
10572 IOPMrootDomain::claimSystemWakeEvent(
10573 IOService
* device
,
10574 IOOptionBits flags
,
10575 const char * reason
,
10576 OSObject
* details
)
10578 OSSharedPtr
<const OSSymbol
> deviceName
;
10579 OSSharedPtr
<OSNumber
> deviceRegId
;
10580 OSSharedPtr
<OSNumber
> claimTime
;
10581 OSSharedPtr
<OSData
> flagsData
;
10582 OSSharedPtr
<OSString
> reasonString
;
10583 OSSharedPtr
<OSDictionary
> dict
;
10584 uint64_t timestamp
;
10585 bool addWakeReason
;
10587 if (!device
|| !reason
) {
10591 pmEventTimeStamp(×tamp
);
10593 IOOptionBits aotFlags
= 0;
10594 bool needAOTEvaluate
= FALSE
;
10596 if (kIOPMAOTModeAddEventFlags
& _aotMode
) {
10597 if (!strcmp("hold", reason
)
10598 || !strcmp("help", reason
)
10599 || !strcmp("menu", reason
)
10600 || !strcmp("stockholm", reason
)
10601 || !strcmp("ringer", reason
)
10602 || !strcmp("ringerab", reason
)
10603 || !strcmp("smc0", reason
)
10604 || !strcmp("AOP.RTPWakeupAP", reason
)
10605 || !strcmp("BT.OutboxNotEmpty", reason
)
10606 || !strcmp("WL.OutboxNotEmpty", reason
)) {
10607 flags
|= kIOPMWakeEventAOTExit
;
10611 #if DEVELOPMENT || DEBUG
10612 if (_aotLingerTime
&& !strcmp("rtc", reason
)) {
10613 flags
|= kIOPMWakeEventAOTPossibleExit
;
10615 #endif /* DEVELOPMENT || DEBUG */
10617 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
10618 // Publishing the WakeType is serialized by the PM work loop
10619 if (!strcmp("rtc", reason
) && (_nextScheduledAlarmType
!= NULL
)) {
10620 pmPowerStateQueue
->submitPowerEvent(kPowerEventPublishWakeType
,
10621 (void *) _nextScheduledAlarmType
.get());
10624 // Workaround for the missing wake HID event
10625 if (gDarkWakeFlags
& kDarkWakeFlagUserWakeWorkaround
) {
10626 if (!strcmp("trackpadkeyboard", reason
)) {
10627 pmPowerStateQueue
->submitPowerEvent(kPowerEventPublishWakeType
,
10628 (void *) gIOPMWakeTypeUserKey
.get());
10633 deviceName
= device
->copyName(gIOServicePlane
);
10634 deviceRegId
= OSNumber::withNumber(device
->getRegistryEntryID(), 64);
10635 claimTime
= OSNumber::withNumber(timestamp
, 64);
10636 flagsData
= OSData::withBytes(&flags
, sizeof(flags
));
10637 reasonString
= OSString::withCString(reason
);
10638 dict
= OSDictionary::withCapacity(5 + (details
? 1 : 0));
10639 if (!dict
|| !deviceName
|| !deviceRegId
|| !claimTime
|| !flagsData
|| !reasonString
) {
10643 dict
->setObject(gIONameKey
, deviceName
.get());
10644 dict
->setObject(gIORegistryEntryIDKey
, deviceRegId
.get());
10645 dict
->setObject(kIOPMWakeEventTimeKey
, claimTime
.get());
10646 dict
->setObject(kIOPMWakeEventFlagsKey
, flagsData
.get());
10647 dict
->setObject(kIOPMWakeEventReasonKey
, reasonString
.get());
10649 dict
->setObject(kIOPMWakeEventDetailsKey
, details
);
10653 addWakeReason
= _acceptSystemWakeEvents
;
10655 IOLog("claimSystemWakeEvent(%s, %s, 0x%x) 0x%x %d\n", reason
, deviceName
->getCStringNoCopy(), (int)flags
, _aotPendingFlags
, _aotReadyToFullWake
);
10657 aotFlags
= (kIOPMWakeEventAOTFlags
& flags
);
10658 aotFlags
= (aotFlags
& ~_aotPendingFlags
);
10659 needAOTEvaluate
= false;
10660 if (_aotNow
&& aotFlags
) {
10661 if (kIOPMWakeEventAOTPossibleExit
& flags
) {
10662 _aotMetrics
->possibleCount
++;
10664 if (kIOPMWakeEventAOTConfirmedPossibleExit
& flags
) {
10665 _aotMetrics
->confirmedPossibleCount
++;
10667 if (kIOPMWakeEventAOTRejectedPossibleExit
& flags
) {
10668 _aotMetrics
->rejectedPossibleCount
++;
10670 if (kIOPMWakeEventAOTExpiredPossibleExit
& flags
) {
10671 _aotMetrics
->expiredPossibleCount
++;
10674 _aotPendingFlags
|= aotFlags
;
10675 addWakeReason
= _aotNow
&& _systemWakeEventsArray
&& ((kIOPMWakeEventAOTExitFlags
& aotFlags
));
10676 needAOTEvaluate
= _aotReadyToFullWake
;
10678 DMSG("claimSystemWakeEvent(%s, 0x%x, %s, 0x%llx) aot %d phase 0x%x add %d\n",
10679 reason
, (int)flags
, deviceName
->getCStringNoCopy(), device
->getRegistryEntryID(),
10680 _aotNow
, pmTracer
->getTracePhase(), addWakeReason
);
10682 if (!gWakeReasonSysctlRegistered
) {
10683 // Lazy registration until the platform driver stops registering
10685 gWakeReasonSysctlRegistered
= true;
10686 #if !defined(XNU_TARGET_OS_OSX)
10687 sysctl_register_oid(&sysctl__kern_wakereason
);
10688 #endif /* !defined(XNU_TARGET_OS_OSX) */
10690 if (addWakeReason
) {
10691 _systemWakeEventsArray
->setObject(dict
.get());
10692 if (gWakeReasonString
[0] != '\0') {
10693 strlcat(gWakeReasonString
, " ", sizeof(gWakeReasonString
));
10695 strlcat(gWakeReasonString
, reason
, sizeof(gWakeReasonString
));
10698 WAKEEVENT_UNLOCK();
10699 if (needAOTEvaluate
) {
10700 // Call aotEvaluate() on PM work loop since it may call
10701 // aotExit() which accesses PM state.
10702 pmPowerStateQueue
->submitPowerEvent(kPowerEventAOTEvaluate
);
10709 //******************************************************************************
10710 // claimSystemBootEvent
10712 // For a driver to claim a device is the source/conduit of a system boot event.
10713 //******************************************************************************
10716 IOPMrootDomain::claimSystemBootEvent(
10717 IOService
* device
,
10718 IOOptionBits flags
,
10719 const char * reason
,
10720 __unused OSObject
* details
)
10722 if (!device
|| !reason
) {
10726 DEBUG_LOG("claimSystemBootEvent(%s, %s, 0x%x)\n", reason
, device
->getName(), (uint32_t) flags
);
10728 if (!gBootReasonSysctlRegistered
) {
10729 // Lazy sysctl registration after setting gBootReasonString
10730 strlcat(gBootReasonString
, reason
, sizeof(gBootReasonString
));
10731 sysctl_register_oid(&sysctl__kern_bootreason
);
10732 gBootReasonSysctlRegistered
= true;
10734 WAKEEVENT_UNLOCK();
10737 //******************************************************************************
10738 // claimSystemShutdownEvent
10740 // For drivers to claim a system shutdown event on the ensuing boot.
10741 //******************************************************************************
10744 IOPMrootDomain::claimSystemShutdownEvent(
10745 IOService
* device
,
10746 IOOptionBits flags
,
10747 const char * reason
,
10748 __unused OSObject
* details
)
10750 if (!device
|| !reason
) {
10754 DEBUG_LOG("claimSystemShutdownEvent(%s, %s, 0x%x)\n", reason
, device
->getName(), (uint32_t) flags
);
10756 if (gShutdownReasonString
[0] != '\0') {
10757 strlcat(gShutdownReasonString
, " ", sizeof(gShutdownReasonString
));
10759 strlcat(gShutdownReasonString
, reason
, sizeof(gShutdownReasonString
));
10761 if (!gShutdownReasonSysctlRegistered
) {
10762 sysctl_register_oid(&sysctl__kern_shutdownreason
);
10763 gShutdownReasonSysctlRegistered
= true;
10765 WAKEEVENT_UNLOCK();
10768 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10771 // MARK: PMSettingHandle
10773 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
10776 PMSettingHandle::free( void )
10779 pmso
->clientHandleFreed();
10788 // MARK: PMSettingObject
10791 #define super OSObject
10792 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
10795 * Static constructor/initializer for PMSettingObject
10797 PMSettingObject
*PMSettingObject::pmSettingObject(
10798 IOPMrootDomain
* parent_arg
,
10799 IOPMSettingControllerCallback handler_arg
,
10800 OSObject
* target_arg
,
10801 uintptr_t refcon_arg
,
10802 uint32_t supportedPowerSources
,
10803 const OSSymbol
* settings
[],
10804 OSObject
* *handle_obj
)
10806 uint32_t settingCount
= 0;
10807 PMSettingObject
*pmso
= NULL
;
10808 PMSettingHandle
*pmsh
= NULL
;
10810 if (!parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
) {
10814 // count OSSymbol entries in NULL terminated settings array
10815 while (settings
[settingCount
]) {
10818 if (0 == settingCount
) {
10822 pmso
= new PMSettingObject
;
10823 if (!pmso
|| !pmso
->init()) {
10827 pmsh
= new PMSettingHandle
;
10828 if (!pmsh
|| !pmsh
->init()) {
10832 queue_init(&pmso
->calloutQueue
);
10833 pmso
->parent
= parent_arg
;
10834 pmso
->func
= handler_arg
;
10835 pmso
->target
= target_arg
;
10836 pmso
->refcon
= refcon_arg
;
10837 pmso
->settingCount
= settingCount
;
10839 pmso
->retain(); // handle holds a retain on pmso
10843 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t) * settingCount
);
10844 if (pmso
->publishedFeatureID
) {
10845 for (unsigned int i
= 0; i
< settingCount
; i
++) {
10846 // Since there is now at least one listener to this setting, publish
10847 // PM root domain support for it.
10848 parent_arg
->publishPMSetting( settings
[i
],
10849 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
10853 *handle_obj
= pmsh
;
10867 PMSettingObject::free( void )
10869 if (publishedFeatureID
) {
10870 for (uint32_t i
= 0; i
< settingCount
; i
++) {
10871 if (publishedFeatureID
[i
]) {
10872 parent
->removePublishedFeature( publishedFeatureID
[i
] );
10876 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
10883 PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
10885 return (*func
)(target
, type
, object
, refcon
);
10889 PMSettingObject::clientHandleFreed( void )
10891 parent
->deregisterPMSettingObject(this);
10895 // MARK: PMAssertionsTracker
10897 //*********************************************************************************
10898 //*********************************************************************************
10899 //*********************************************************************************
10900 // class PMAssertionsTracker Implementation
10902 #define kAssertUniqueIDStart 500
10904 PMAssertionsTracker
*
10905 PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
10907 PMAssertionsTracker
*me
;
10909 me
= new PMAssertionsTracker
;
10910 if (!me
|| !me
->init()) {
10917 me
->owner
= rootDomain
;
10918 me
->issuingUniqueID
= kAssertUniqueIDStart
;
10919 me
->assertionsArray
= OSArray::withCapacity(5);
10920 me
->assertionsKernel
= 0;
10921 me
->assertionsUser
= 0;
10922 me
->assertionsCombined
= 0;
10923 me
->assertionsArrayLock
= IOLockAlloc();
10924 me
->tabulateProducerCount
= me
->tabulateConsumerCount
= 0;
10926 assert(me
->assertionsArray
);
10927 assert(me
->assertionsArrayLock
);
10933 * - Update assertionsKernel to reflect the state of all
10934 * assertions in the kernel.
10935 * - Update assertionsCombined to reflect both kernel & user space.
10938 PMAssertionsTracker::tabulate(void)
10942 PMAssertStruct
*_a
= NULL
;
10945 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
10946 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
10950 assertionsKernel
= 0;
10951 assertionsCombined
= 0;
10953 if (!assertionsArray
) {
10957 if ((count
= assertionsArray
->getCount())) {
10958 for (i
= 0; i
< count
; i
++) {
10959 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
10961 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
10962 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
)) {
10963 assertionsKernel
|= _a
->assertionBits
;
10969 tabulateProducerCount
++;
10970 assertionsCombined
= assertionsKernel
| assertionsUser
;
10972 if ((assertionsKernel
!= oldKernel
) ||
10973 (assertionsCombined
!= oldCombined
)) {
10974 owner
->evaluateAssertions(assertionsCombined
, oldCombined
);
10979 PMAssertionsTracker::updateCPUBitAccounting( PMAssertStruct
*assertStruct
)
10984 if (((assertStruct
->assertionBits
& kIOPMDriverAssertionCPUBit
) == 0) ||
10985 (assertStruct
->assertCPUStartTime
== 0)) {
10989 now
= mach_absolute_time();
10990 SUB_ABSOLUTETIME(&now
, &assertStruct
->assertCPUStartTime
);
10991 absolutetime_to_nanoseconds(now
, &nsec
);
10992 assertStruct
->assertCPUDuration
+= nsec
;
10993 assertStruct
->assertCPUStartTime
= 0;
10995 if (assertStruct
->assertCPUDuration
> maxAssertCPUDuration
) {
10996 maxAssertCPUDuration
= assertStruct
->assertCPUDuration
;
10997 maxAssertCPUEntryId
= assertStruct
->registryEntryID
;
11002 PMAssertionsTracker::reportCPUBitAccounting( void )
11004 PMAssertStruct
*_a
;
11012 // Account for drivers that are still holding the CPU assertion
11013 if (assertionsKernel
& kIOPMDriverAssertionCPUBit
) {
11014 now
= mach_absolute_time();
11015 if ((count
= assertionsArray
->getCount())) {
11016 for (i
= 0; i
< count
; i
++) {
11017 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
11019 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
11020 if ((_a
->assertionBits
& kIOPMDriverAssertionCPUBit
) &&
11021 (_a
->level
== kIOPMDriverAssertionLevelOn
) &&
11022 (_a
->assertCPUStartTime
!= 0)) {
11023 // Don't modify PMAssertStruct, leave that
11024 // for updateCPUBitAccounting()
11025 SUB_ABSOLUTETIME(&now
, &_a
->assertCPUStartTime
);
11026 absolutetime_to_nanoseconds(now
, &nsec
);
11027 nsec
+= _a
->assertCPUDuration
;
11028 if (nsec
> maxAssertCPUDuration
) {
11029 maxAssertCPUDuration
= nsec
;
11030 maxAssertCPUEntryId
= _a
->registryEntryID
;
11038 if (maxAssertCPUDuration
) {
11039 DLOG("cpu assertion held for %llu ms by 0x%llx\n",
11040 (maxAssertCPUDuration
/ NSEC_PER_MSEC
), maxAssertCPUEntryId
);
11043 maxAssertCPUDuration
= 0;
11044 maxAssertCPUEntryId
= 0;
11048 PMAssertionsTracker::publishProperties( void )
11050 OSSharedPtr
<OSArray
> assertionsSummary
;
11052 if (tabulateConsumerCount
!= tabulateProducerCount
) {
11053 IOLockLock(assertionsArrayLock
);
11055 tabulateConsumerCount
= tabulateProducerCount
;
11057 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
11059 assertionsSummary
= copyAssertionsArray();
11060 if (assertionsSummary
) {
11061 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
.get());
11063 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
11066 /* Publish the IOPMrootDomain property "DriverPMAssertions"
11068 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
11070 IOLockUnlock(assertionsArrayLock
);
11074 PMAssertionsTracker::PMAssertStruct
*
11075 PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
11077 PMAssertStruct
*_a
= NULL
;
11083 if (assertionsArray
11084 && (count
= assertionsArray
->getCount())) {
11085 for (i
= 0; i
< count
; i
++) {
11086 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
11088 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
11089 if (_a
&& (_id
== _a
->id
)) {
11107 /* PMAssertionsTracker::handleCreateAssertion
11108 * Perform assertion work on the PM workloop. Do not call directly.
11111 PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
11113 PMAssertStruct
*assertStruct
;
11117 if (newAssertion
) {
11118 IOLockLock(assertionsArrayLock
);
11119 assertStruct
= (PMAssertStruct
*) newAssertion
->getBytesNoCopy();
11120 if ((assertStruct
->assertionBits
& kIOPMDriverAssertionCPUBit
) &&
11121 (assertStruct
->level
== kIOPMDriverAssertionLevelOn
)) {
11122 assertStruct
->assertCPUStartTime
= mach_absolute_time();
11124 assertionsArray
->setObject(newAssertion
);
11125 IOLockUnlock(assertionsArrayLock
);
11126 newAssertion
->release();
11130 return kIOReturnSuccess
;
11133 /* PMAssertionsTracker::createAssertion
11134 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
11138 PMAssertionsTracker::createAssertion(
11139 IOPMDriverAssertionType which
,
11140 IOPMDriverAssertionLevel level
,
11141 IOService
*serviceID
,
11142 const char *whoItIs
,
11143 IOPMDriverAssertionID
*outID
)
11145 OSSharedPtr
<OSData
> dataStore
;
11146 PMAssertStruct track
;
11148 // Warning: trillions and trillions of created assertions may overflow the unique ID.
11149 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
11150 track
.level
= level
;
11151 track
.assertionBits
= which
;
11153 // NB: ownerString is explicitly managed by PMAssertStruct
11154 // it will be released in `handleReleaseAssertion' below
11155 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
).detach():nullptr;
11156 track
.ownerService
= serviceID
;
11157 track
.registryEntryID
= serviceID
? serviceID
->getRegistryEntryID():0;
11158 track
.modifiedTime
= 0;
11159 pmEventTimeStamp(&track
.createdTime
);
11160 track
.assertCPUStartTime
= 0;
11161 track
.assertCPUDuration
= 0;
11163 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
11165 if (track
.ownerString
) {
11166 track
.ownerString
->release();
11167 track
.ownerString
= NULL
;
11169 return kIOReturnNoMemory
;
11174 if (owner
&& owner
->pmPowerStateQueue
) {
11175 // queue action is responsible for releasing dataStore
11176 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
.detach());
11179 return kIOReturnSuccess
;
11182 /* PMAssertionsTracker::handleReleaseAssertion
11183 * Runs in PM workloop. Do not call directly.
11186 PMAssertionsTracker::handleReleaseAssertion(
11187 IOPMDriverAssertionID _id
)
11192 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
11194 if (!assertStruct
) {
11195 return kIOReturnNotFound
;
11198 IOLockLock(assertionsArrayLock
);
11200 if ((assertStruct
->assertionBits
& kIOPMDriverAssertionCPUBit
) &&
11201 (assertStruct
->level
== kIOPMDriverAssertionLevelOn
)) {
11202 updateCPUBitAccounting(assertStruct
);
11205 if (assertStruct
->ownerString
) {
11206 assertStruct
->ownerString
->release();
11207 assertStruct
->ownerString
= NULL
;
11210 assertionsArray
->removeObject(index
);
11211 IOLockUnlock(assertionsArrayLock
);
11214 return kIOReturnSuccess
;
11217 /* PMAssertionsTracker::releaseAssertion
11218 * Releases an assertion and affects system behavior if appropiate.
11219 * Actual work happens on PM workloop.
11222 PMAssertionsTracker::releaseAssertion(
11223 IOPMDriverAssertionID _id
)
11225 if (owner
&& owner
->pmPowerStateQueue
) {
11226 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, NULL
, _id
);
11228 return kIOReturnSuccess
;
11231 /* PMAssertionsTracker::handleSetAssertionLevel
11232 * Runs in PM workloop. Do not call directly.
11235 PMAssertionsTracker::handleSetAssertionLevel(
11236 IOPMDriverAssertionID _id
,
11237 IOPMDriverAssertionLevel _level
)
11239 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
11243 if (!assertStruct
) {
11244 return kIOReturnNotFound
;
11247 IOLockLock(assertionsArrayLock
);
11248 pmEventTimeStamp(&assertStruct
->modifiedTime
);
11249 if ((assertStruct
->assertionBits
& kIOPMDriverAssertionCPUBit
) &&
11250 (assertStruct
->level
!= _level
)) {
11251 if (_level
== kIOPMDriverAssertionLevelOn
) {
11252 assertStruct
->assertCPUStartTime
= mach_absolute_time();
11254 updateCPUBitAccounting(assertStruct
);
11257 assertStruct
->level
= _level
;
11258 IOLockUnlock(assertionsArrayLock
);
11261 return kIOReturnSuccess
;
11264 /* PMAssertionsTracker::setAssertionLevel
11267 PMAssertionsTracker::setAssertionLevel(
11268 IOPMDriverAssertionID _id
,
11269 IOPMDriverAssertionLevel _level
)
11271 if (owner
&& owner
->pmPowerStateQueue
) {
11272 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
11273 (void *)(uintptr_t)_level
, _id
);
11276 return kIOReturnSuccess
;
11280 PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
11282 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
11286 if (new_user_levels
!= assertionsUser
) {
11287 DLOG("assertionsUser 0x%llx->0x%llx\n", assertionsUser
, new_user_levels
);
11288 assertionsUser
= new_user_levels
;
11292 return kIOReturnSuccess
;
11296 PMAssertionsTracker::setUserAssertionLevels(
11297 IOPMDriverAssertionType new_user_levels
)
11299 if (gIOPMWorkLoop
) {
11300 gIOPMWorkLoop
->runAction(
11301 OSMemberFunctionCast(
11302 IOWorkLoop::Action
,
11304 &PMAssertionsTracker::handleSetUserAssertionLevels
),
11306 (void *) &new_user_levels
, NULL
, NULL
, NULL
);
11309 return kIOReturnSuccess
;
11313 OSSharedPtr
<OSArray
>
11314 PMAssertionsTracker::copyAssertionsArray(void)
11318 OSSharedPtr
<OSArray
> outArray
= NULL
;
11320 if (!assertionsArray
|| (0 == (count
= assertionsArray
->getCount()))) {
11323 outArray
= OSArray::withCapacity(count
);
11328 for (i
= 0; i
< count
; i
++) {
11329 PMAssertStruct
*_a
= NULL
;
11331 OSSharedPtr
<OSDictionary
> details
;
11333 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
11334 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy())) {
11335 OSSharedPtr
<OSNumber
> _n
;
11337 details
= OSDictionary::withCapacity(7);
11342 outArray
->setObject(details
.get());
11344 _n
= OSNumber::withNumber(_a
->id
, 64);
11346 details
->setObject(kIOPMDriverAssertionIDKey
, _n
.get());
11348 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
11350 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
.get());
11352 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
11354 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
.get());
11356 _n
= OSNumber::withNumber((uintptr_t)_a
->registryEntryID
, 64);
11358 details
->setObject(kIOPMDriverAssertionRegistryEntryIDKey
, _n
.get());
11360 _n
= OSNumber::withNumber(_a
->level
, 64);
11362 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
.get());
11364 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
11366 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
.get());
11369 if (_a
->ownerString
) {
11370 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
11376 return os::move(outArray
);
11379 IOPMDriverAssertionType
11380 PMAssertionsTracker::getActivatedAssertions(void)
11382 return assertionsCombined
;
11385 IOPMDriverAssertionLevel
11386 PMAssertionsTracker::getAssertionLevel(
11387 IOPMDriverAssertionType type
)
11389 // FIXME: unused and also wrong
11390 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
)) {
11391 return kIOPMDriverAssertionLevelOn
;
11393 return kIOPMDriverAssertionLevelOff
;
11397 //*********************************************************************************
11398 //*********************************************************************************
11399 //*********************************************************************************
11403 pmEventTimeStamp(uint64_t *recordTS
)
11406 clock_usec_t tusec
;
11412 // We assume tsec fits into 32 bits; 32 bits holds enough
11413 // seconds for 136 years since the epoch in 1970.
11414 clock_get_calendar_microtime(&tsec
, &tusec
);
11417 // Pack the sec & microsec calendar time into a uint64_t, for fun.
11419 *recordTS
|= (uint32_t)tusec
;
11420 *recordTS
|= ((uint64_t)tsec
<< 32);
11426 // MARK: IORootParent
11428 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
11430 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
11432 // The reason that root domain needs a root parent is to facilitate demand
11433 // sleep, since a power change from the root parent cannot be vetoed.
11435 // The above statement is no longer true since root domain now performs
11436 // demand sleep using overrides. But root parent remains to avoid changing
11437 // the power tree stacking. Root parent is parked at the max power state.
11440 static IOPMPowerState patriarchPowerStates
[2] =
11442 {1, 0, ON_POWER
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
11443 {1, 0, ON_POWER
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
11447 IORootParent::initialize( void )
11450 gIOPMPSExternalConnectedKey
= OSSymbol::withCStringNoCopy(kIOPMPSExternalConnectedKey
);
11451 gIOPMPSExternalChargeCapableKey
= OSSymbol::withCStringNoCopy(kIOPMPSExternalChargeCapableKey
);
11452 gIOPMPSBatteryInstalledKey
= OSSymbol::withCStringNoCopy(kIOPMPSBatteryInstalledKey
);
11453 gIOPMPSIsChargingKey
= OSSymbol::withCStringNoCopy(kIOPMPSIsChargingKey
);
11454 gIOPMPSAtWarnLevelKey
= OSSymbol::withCStringNoCopy(kIOPMPSAtWarnLevelKey
);
11455 gIOPMPSAtCriticalLevelKey
= OSSymbol::withCStringNoCopy(kIOPMPSAtCriticalLevelKey
);
11456 gIOPMPSCurrentCapacityKey
= OSSymbol::withCStringNoCopy(kIOPMPSCurrentCapacityKey
);
11457 gIOPMPSMaxCapacityKey
= OSSymbol::withCStringNoCopy(kIOPMPSMaxCapacityKey
);
11458 gIOPMPSDesignCapacityKey
= OSSymbol::withCStringNoCopy(kIOPMPSDesignCapacityKey
);
11459 gIOPMPSTimeRemainingKey
= OSSymbol::withCStringNoCopy(kIOPMPSTimeRemainingKey
);
11460 gIOPMPSAmperageKey
= OSSymbol::withCStringNoCopy(kIOPMPSAmperageKey
);
11461 gIOPMPSVoltageKey
= OSSymbol::withCStringNoCopy(kIOPMPSVoltageKey
);
11462 gIOPMPSCycleCountKey
= OSSymbol::withCStringNoCopy(kIOPMPSCycleCountKey
);
11463 gIOPMPSMaxErrKey
= OSSymbol::withCStringNoCopy(kIOPMPSMaxErrKey
);
11464 gIOPMPSAdapterInfoKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterInfoKey
);
11465 gIOPMPSLocationKey
= OSSymbol::withCStringNoCopy(kIOPMPSLocationKey
);
11466 gIOPMPSErrorConditionKey
= OSSymbol::withCStringNoCopy(kIOPMPSErrorConditionKey
);
11467 gIOPMPSManufacturerKey
= OSSymbol::withCStringNoCopy(kIOPMPSManufacturerKey
);
11468 gIOPMPSManufactureDateKey
= OSSymbol::withCStringNoCopy(kIOPMPSManufactureDateKey
);
11469 gIOPMPSModelKey
= OSSymbol::withCStringNoCopy(kIOPMPSModelKey
);
11470 gIOPMPSSerialKey
= OSSymbol::withCStringNoCopy(kIOPMPSSerialKey
);
11471 gIOPMPSLegacyBatteryInfoKey
= OSSymbol::withCStringNoCopy(kIOPMPSLegacyBatteryInfoKey
);
11472 gIOPMPSBatteryHealthKey
= OSSymbol::withCStringNoCopy(kIOPMPSBatteryHealthKey
);
11473 gIOPMPSHealthConfidenceKey
= OSSymbol::withCStringNoCopy(kIOPMPSHealthConfidenceKey
);
11474 gIOPMPSCapacityEstimatedKey
= OSSymbol::withCStringNoCopy(kIOPMPSCapacityEstimatedKey
);
11475 gIOPMPSBatteryChargeStatusKey
= OSSymbol::withCStringNoCopy(kIOPMPSBatteryChargeStatusKey
);
11476 gIOPMPSBatteryTemperatureKey
= OSSymbol::withCStringNoCopy(kIOPMPSBatteryTemperatureKey
);
11477 gIOPMPSAdapterDetailsKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsKey
);
11478 gIOPMPSChargerConfigurationKey
= OSSymbol::withCStringNoCopy(kIOPMPSChargerConfigurationKey
);
11479 gIOPMPSAdapterDetailsIDKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsIDKey
);
11480 gIOPMPSAdapterDetailsWattsKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsWattsKey
);
11481 gIOPMPSAdapterDetailsRevisionKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsRevisionKey
);
11482 gIOPMPSAdapterDetailsSerialNumberKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsSerialNumberKey
);
11483 gIOPMPSAdapterDetailsFamilyKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsFamilyKey
);
11484 gIOPMPSAdapterDetailsAmperageKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsAmperageKey
);
11485 gIOPMPSAdapterDetailsDescriptionKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsDescriptionKey
);
11486 gIOPMPSAdapterDetailsPMUConfigurationKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsPMUConfigurationKey
);
11487 gIOPMPSAdapterDetailsSourceIDKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsSourceIDKey
);
11488 gIOPMPSAdapterDetailsErrorFlagsKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsErrorFlagsKey
);
11489 gIOPMPSAdapterDetailsSharedSourceKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsSharedSourceKey
);
11490 gIOPMPSAdapterDetailsCloakedKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsCloakedKey
);
11491 gIOPMPSInvalidWakeSecondsKey
= OSSymbol::withCStringNoCopy(kIOPMPSInvalidWakeSecondsKey
);
11492 gIOPMPSPostChargeWaitSecondsKey
= OSSymbol::withCStringNoCopy(kIOPMPSPostChargeWaitSecondsKey
);
11493 gIOPMPSPostDishargeWaitSecondsKey
= OSSymbol::withCStringNoCopy(kIOPMPSPostDishargeWaitSecondsKey
);
11497 IORootParent::start( IOService
* nub
)
11499 IOService::start(nub
);
11500 attachToParent( getRegistryRoot(), gIOPowerPlane
);
11502 registerPowerDriver(this, patriarchPowerStates
, 2);
11508 IORootParent::shutDownSystem( void )
11513 IORootParent::restartSystem( void )
11518 IORootParent::sleepSystem( void )
11523 IORootParent::dozeSystem( void )
11528 IORootParent::sleepToDoze( void )
11533 IORootParent::wakeSystem( void )
11537 OSSharedPtr
<OSObject
>
11538 IORootParent::copyProperty( const char * aKey
) const
11540 return IOService::copyProperty(aKey
);
11544 IOPMrootDomain::getWatchdogTimeout()
11546 if (gSwdSleepWakeTimeout
) {
11547 gSwdSleepTimeout
= gSwdWakeTimeout
= gSwdSleepWakeTimeout
;
11549 if ((pmTracer
->getTracePhase() < kIOPMTracePointSystemSleep
) ||
11550 (pmTracer
->getTracePhase() == kIOPMTracePointDarkWakeEntry
)) {
11551 return gSwdSleepTimeout
? gSwdSleepTimeout
: WATCHDOG_SLEEP_TIMEOUT
;
11553 return gSwdWakeTimeout
? gSwdWakeTimeout
: WATCHDOG_WAKE_TIMEOUT
;
11558 #if defined(__i386__) || defined(__x86_64__) || (defined(__arm64__) && HIBERNATION)
11560 IOPMrootDomain::restartWithStackshot()
11562 takeStackshot(true);
11564 return kIOReturnSuccess
;
11568 IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger
)
11570 takeStackshot(wdogTrigger
);
11574 IOPMrootDomain::tracePhase2String(uint32_t tracePhase
, const char **phaseString
, const char **description
)
11576 switch (tracePhase
) {
11577 case kIOPMTracePointSleepStarted
:
11578 *phaseString
= "kIOPMTracePointSleepStarted";
11579 *description
= "starting sleep";
11582 case kIOPMTracePointSleepApplications
:
11583 *phaseString
= "kIOPMTracePointSleepApplications";
11584 *description
= "notifying applications";
11587 case kIOPMTracePointSleepPriorityClients
:
11588 *phaseString
= "kIOPMTracePointSleepPriorityClients";
11589 *description
= "notifying clients about upcoming system capability changes";
11592 case kIOPMTracePointSleepWillChangeInterests
:
11593 *phaseString
= "kIOPMTracePointSleepWillChangeInterests";
11594 *description
= "creating hibernation file or while calling rootDomain's clients about upcoming rootDomain's state changes";
11597 case kIOPMTracePointSleepPowerPlaneDrivers
:
11598 *phaseString
= "kIOPMTracePointSleepPowerPlaneDrivers";
11599 *description
= "calling power state change callbacks";
11602 case kIOPMTracePointSleepDidChangeInterests
:
11603 *phaseString
= "kIOPMTracePointSleepDidChangeInterests";
11604 *description
= "calling rootDomain's clients about rootDomain's state changes";
11607 case kIOPMTracePointSleepCapabilityClients
:
11608 *phaseString
= "kIOPMTracePointSleepCapabilityClients";
11609 *description
= "notifying clients about current system capabilities";
11612 case kIOPMTracePointSleepPlatformActions
:
11613 *phaseString
= "kIOPMTracePointSleepPlatformActions";
11614 *description
= "calling Quiesce/Sleep action callbacks";
11617 case kIOPMTracePointSleepCPUs
:
11619 *phaseString
= "kIOPMTracePointSleepCPUs";
11620 #if defined(__i386__) || defined(__x86_64__)
11622 * We cannot use the getCPUNumber() method to get the cpu number, since
11623 * that cpu number is unrelated to the cpu number we need (we need the cpu
11624 * number as enumerated by the scheduler, NOT the CPU number enumerated
11625 * by ACPIPlatform as the CPUs are enumerated in MADT order).
11626 * Instead, pass the Mach processor pointer associated with the current
11627 * shutdown target so its associated cpu_id can be used in
11628 * processor_to_datastring.
11630 if (currentShutdownTarget
!= NULL
&&
11631 currentShutdownTarget
->getMachProcessor() != NULL
) {
11632 const char *sbuf
= processor_to_datastring("halting all non-boot CPUs",
11633 currentShutdownTarget
->getMachProcessor());
11634 *description
= sbuf
;
11636 *description
= "halting all non-boot CPUs";
11639 *description
= "halting all non-boot CPUs";
11643 case kIOPMTracePointSleepPlatformDriver
:
11644 *phaseString
= "kIOPMTracePointSleepPlatformDriver";
11645 *description
= "executing platform specific code";
11648 case kIOPMTracePointHibernate
:
11649 *phaseString
= "kIOPMTracePointHibernate";
11650 *description
= "writing the hibernation image";
11653 case kIOPMTracePointSystemSleep
:
11654 *phaseString
= "kIOPMTracePointSystemSleep";
11655 *description
= "in EFI/Bootrom after last point of entry to sleep";
11658 case kIOPMTracePointWakePlatformDriver
:
11659 *phaseString
= "kIOPMTracePointWakePlatformDriver";
11660 *description
= "executing platform specific code";
11664 case kIOPMTracePointWakePlatformActions
:
11665 *phaseString
= "kIOPMTracePointWakePlatformActions";
11666 *description
= "calling Wake action callbacks";
11669 case kIOPMTracePointWakeCPUs
:
11670 *phaseString
= "kIOPMTracePointWakeCPUs";
11671 *description
= "starting non-boot CPUs";
11674 case kIOPMTracePointWakeWillPowerOnClients
:
11675 *phaseString
= "kIOPMTracePointWakeWillPowerOnClients";
11676 *description
= "sending kIOMessageSystemWillPowerOn message to kernel and userspace clients";
11679 case kIOPMTracePointWakeWillChangeInterests
:
11680 *phaseString
= "kIOPMTracePointWakeWillChangeInterests";
11681 *description
= "calling rootDomain's clients about upcoming rootDomain's state changes";
11684 case kIOPMTracePointWakeDidChangeInterests
:
11685 *phaseString
= "kIOPMTracePointWakeDidChangeInterests";
11686 *description
= "calling rootDomain's clients about completed rootDomain's state changes";
11689 case kIOPMTracePointWakePowerPlaneDrivers
:
11690 *phaseString
= "kIOPMTracePointWakePowerPlaneDrivers";
11691 *description
= "calling power state change callbacks";
11694 case kIOPMTracePointWakeCapabilityClients
:
11695 *phaseString
= "kIOPMTracePointWakeCapabilityClients";
11696 *description
= "informing clients about current system capabilities";
11699 case kIOPMTracePointWakeApplications
:
11700 *phaseString
= "kIOPMTracePointWakeApplications";
11701 *description
= "sending asynchronous kIOMessageSystemHasPoweredOn message to userspace clients";
11704 case kIOPMTracePointDarkWakeEntry
:
11705 *phaseString
= "kIOPMTracePointDarkWakeEntry";
11706 *description
= "entering darkwake on way to sleep";
11709 case kIOPMTracePointDarkWakeExit
:
11710 *phaseString
= "kIOPMTracePointDarkWakeExit";
11711 *description
= "entering fullwake from darkwake";
11715 *phaseString
= NULL
;
11716 *description
= NULL
;
11721 IOPMrootDomain::saveFailureData2File()
11723 unsigned int len
= 0;
11724 char failureStr
[512];
11727 OSNumber
*statusCode
;
11728 uint64_t pmStatusCode
= 0;
11729 uint32_t phaseData
= 0;
11730 uint32_t phaseDetail
= 0;
11731 bool efiFailure
= false;
11733 OSSharedPtr
<OSObject
> statusCodeProp
= copyProperty(kIOPMSleepWakeFailureCodeKey
);
11734 statusCode
= OSDynamicCast(OSNumber
, statusCodeProp
.get());
11736 pmStatusCode
= statusCode
->unsigned64BitValue();
11737 phaseData
= pmStatusCode
& 0xFFFFFFFF;
11738 phaseDetail
= (pmStatusCode
>> 32) & 0xFFFFFFFF;
11739 if ((phaseData
& 0xFF) == kIOPMTracePointSystemSleep
) {
11740 LOG("Sleep Wake failure in EFI\n");
11743 snprintf(failureStr
, sizeof(failureStr
), "Sleep Wake failure in EFI\n\nFailure code:: 0x%08x 0x%08x\n\nPlease IGNORE the below stackshot\n", phaseDetail
, phaseData
);
11744 len
= (typeof(len
))strnlen(failureStr
, sizeof(failureStr
));
11749 if (PEReadNVRAMProperty(kIOSleepWakeFailurePanic
, NULL
, &len
)) {
11750 swd_flags
|= SWD_BOOT_BY_SW_WDOG
;
11751 PERemoveNVRAMProperty(kIOSleepWakeFailurePanic
);
11752 // dump panic will handle saving nvram data
11756 /* Keeping this around for capturing data during power
11759 if (!PEReadNVRAMProperty(kIOSleepWakeFailureString
, NULL
, &len
)) {
11760 DLOG("No sleep wake failure string\n");
11764 DLOG("Ignoring zero byte SleepWake failure string\n");
11768 // if PMStatus code is zero, delete stackshot and return
11770 if (((pmStatusCode
& 0xFFFFFFFF) & 0xFF) == 0) {
11771 // there was no sleep wake failure
11772 // this can happen if delete stackshot was called
11773 // before take stackshot completed. Let us delete any
11774 // sleep wake failure data in nvram
11775 DLOG("Deleting stackshot on successful wake\n");
11781 if (len
> sizeof(failureStr
)) {
11782 len
= sizeof(failureStr
);
11785 PEReadNVRAMProperty(kIOSleepWakeFailureString
, failureStr
, &len
);
11787 if (failureStr
[0] != 0) {
11788 error
= sleepWakeDebugSaveFile(kSleepWakeFailureStringFile
, failureStr
, len
);
11790 DLOG("Failed to save SleepWake failure string to file. error:%d\n", error
);
11792 DLOG("Saved SleepWake failure string to file.\n");
11796 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
)) {
11801 unsigned int len
= 0;
11803 char nvram_var_name_buffer
[20];
11804 unsigned int concat_len
= 0;
11805 swd_hdr
*hdr
= NULL
;
11808 hdr
= (swd_hdr
*)swd_buffer
;
11809 outbuf
= (char *)hdr
+ hdr
->spindump_offset
;
11810 OSBoundedArrayRef
<char> boundedOutBuf(outbuf
, hdr
->alloc_size
- hdr
->spindump_offset
);
11812 for (int i
= 0; i
< 8; i
++) {
11813 snprintf(nvram_var_name_buffer
, sizeof(nvram_var_name_buffer
), "%s%02d", SWD_STACKSHOT_VAR_PREFIX
, i
+ 1);
11814 if (!PEReadNVRAMProperty(nvram_var_name_buffer
, NULL
, &len
)) {
11815 LOG("No SleepWake blob to read beyond chunk %d\n", i
);
11818 if (PEReadNVRAMProperty(nvram_var_name_buffer
, boundedOutBuf
.slice(concat_len
, len
).data(), &len
) == FALSE
) {
11819 PERemoveNVRAMProperty(nvram_var_name_buffer
);
11820 LOG("Could not read the property :-(\n");
11823 PERemoveNVRAMProperty(nvram_var_name_buffer
);
11826 LOG("Concatenated length for the SWD blob %d\n", concat_len
);
11829 error
= sleepWakeDebugSaveFile(kSleepWakeStacksFilename
, outbuf
, concat_len
);
11831 LOG("Failed to save SleepWake zipped data to file. error:%d\n", error
);
11833 LOG("Saved SleepWake zipped data to file.\n");
11836 // There is a sleep wake failure string but no stackshot
11837 // Write a placeholder stacks file so that swd runs
11838 snprintf(outbuf
, 20, "%s", "No stackshot data\n");
11839 error
= sleepWakeDebugSaveFile(kSleepWakeStacksFilename
, outbuf
, 20);
11841 LOG("Failed to save SleepWake zipped data to file. error:%d\n", error
);
11843 LOG("Saved SleepWake zipped data to file.\n");
11847 LOG("No buffer allocated to save failure stackshot\n");
11851 gRootDomain
->swd_lock
= 0;
11853 PERemoveNVRAMProperty(kIOSleepWakeFailureString
);
11859 IOPMrootDomain::getFailureData(thread_t
*thread
, char *failureStr
, size_t strLen
)
11861 OSSharedPtr
<IORegistryIterator
> iter
;
11862 OSSharedPtr
<const OSSymbol
> kextName
= NULL
;
11863 IORegistryEntry
* entry
;
11865 bool nodeFound
= false;
11867 const void * callMethod
= NULL
;
11868 const char * objectName
= NULL
;
11869 uint32_t timeout
= getWatchdogTimeout();
11870 const char * phaseString
= NULL
;
11871 const char * phaseDescription
= NULL
;
11873 IOPMServiceInterestNotifier
*notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, notifierObject
.get());
11874 uint32_t tracePhase
= pmTracer
->getTracePhase();
11877 if ((tracePhase
< kIOPMTracePointSystemSleep
) || (tracePhase
== kIOPMTracePointDarkWakeEntry
)) {
11878 snprintf(failureStr
, strLen
, "Sleep transition timed out after %d seconds", timeout
);
11880 snprintf(failureStr
, strLen
, "Wake transition timed out after %d seconds", timeout
);
11882 tracePhase2String(tracePhase
, &phaseString
, &phaseDescription
);
11884 if (notifierThread
) {
11885 if (notifier
&& (notifier
->identifier
)) {
11886 objectName
= notifier
->identifier
->getCStringNoCopy();
11888 *thread
= notifierThread
;
11890 iter
= IORegistryIterator::iterateOver(
11891 getPMRootDomain(), gIOPowerPlane
, kIORegistryIterateRecursively
);
11894 while ((entry
= iter
->getNextObject())) {
11895 node
= OSDynamicCast(IOService
, entry
);
11899 if (OSDynamicCast(IOPowerConnection
, node
)) {
11903 if (node
->getBlockingDriverCall(thread
, &callMethod
)) {
11910 kextName
= copyKextIdentifierWithAddress((vm_address_t
) callMethod
);
11912 objectName
= kextName
->getCStringNoCopy();
11916 if (phaseDescription
) {
11917 strlcat(failureStr
, " while ", strLen
);
11918 strlcat(failureStr
, phaseDescription
, strLen
);
11919 strlcat(failureStr
, ".", strLen
);
11922 strlcat(failureStr
, " Suspected bundle: ", strLen
);
11923 strlcat(failureStr
, objectName
, strLen
);
11924 strlcat(failureStr
, ".", strLen
);
11927 char threadName
[40];
11928 snprintf(threadName
, sizeof(threadName
), " Thread 0x%llx.", thread_tid(*thread
));
11929 strlcat(failureStr
, threadName
, strLen
);
11932 DLOG("%s\n", failureStr
);
11935 struct swd_stackshot_compressed_data
{
11936 z_output_func zoutput
;
11938 uint64_t totalbytes
;
11939 uint64_t lastpercent
;
11941 unsigned outremain
;
11946 struct swd_stackshot_compressed_data swd_zip_var
= { };
11949 swd_zs_alloc(void *__unused ref
, u_int items
, u_int size
)
11952 LOG("Alloc in zipping %d items of size %d\n", items
, size
);
11954 result
= (void *)(swd_zs_zmem
+ swd_zs_zoffset
);
11955 swd_zs_zoffset
+= ~31L & (31 + (items
* size
)); // 32b align for vector crc
11956 LOG("Offset %zu\n", swd_zs_zoffset
);
11961 swd_zinput(z_streamp strm
, Bytef
*buf
, unsigned size
)
11965 len
= strm
->avail_in
;
11974 if (strm
->next_in
!= (Bytef
*) strm
) {
11975 memcpy(buf
, strm
->next_in
, len
);
11980 strm
->adler
= z_crc32(strm
->adler
, buf
, len
);
11982 strm
->avail_in
-= len
;
11983 strm
->next_in
+= len
;
11984 strm
->total_in
+= len
;
11990 swd_zoutput(z_streamp strm
, Bytef
*buf
, unsigned len
)
11992 unsigned int i
= 0;
11993 // if outlen > max size don't add to the buffer
11994 assert(buf
!= NULL
);
11996 if (swd_zip_var
.outlen
+ len
> SWD_COMPRESSED_BUFSIZE
) {
11997 LOG("No space to GZIP... not writing to NVRAM\n");
12001 for (i
= 0; i
< len
; i
++) {
12002 *(swd_zip_var
.outbuf
+ swd_zip_var
.outlen
+ i
) = *(buf
+ i
);
12004 swd_zip_var
.outlen
+= len
;
12009 swd_zs_free(void * __unused ref
, void * __unused ptr
)
12014 swd_compress(char *inPtr
, char *outPtr
, size_t numBytes
)
12019 if (((unsigned int) numBytes
) != numBytes
) {
12023 if (!swd_zs
.zalloc
) {
12024 swd_zs
.zalloc
= swd_zs_alloc
;
12025 swd_zs
.zfree
= swd_zs_free
;
12026 if (deflateInit2(&swd_zs
, Z_BEST_SPEED
, Z_DEFLATED
, wbits
+ 16, memlevel
, Z_DEFAULT_STRATEGY
)) {
12027 // allocation failed
12028 bzero(&swd_zs
, sizeof(swd_zs
));
12029 // swd_zs_zoffset = 0;
12031 LOG("PMRD inited the zlib allocation routines\n");
12035 swd_zip_var
.zipped
= 0;
12036 swd_zip_var
.totalbytes
= 0; // should this be the max that we have?
12037 swd_zip_var
.lastpercent
= 0;
12038 swd_zip_var
.error
= kIOReturnSuccess
;
12039 swd_zip_var
.outremain
= 0;
12040 swd_zip_var
.outlen
= 0;
12041 swd_zip_var
.writes
= 0;
12042 swd_zip_var
.outbuf
= (Bytef
*)outPtr
;
12044 swd_zip_var
.totalbytes
= numBytes
;
12046 swd_zs
.avail_in
= 0;
12047 swd_zs
.next_in
= NULL
;
12048 swd_zs
.avail_out
= 0;
12049 swd_zs
.next_out
= NULL
;
12051 deflateResetWithIO(&swd_zs
, swd_zinput
, swd_zoutput
);
12057 while (swd_zip_var
.error
>= 0) {
12058 if (!zs
->avail_in
) {
12059 zs
->next_in
= (unsigned char *)inPtr
? (Bytef
*)inPtr
: (Bytef
*)zs
; /* zero marker? */
12060 zs
->avail_in
= (unsigned int) numBytes
;
12062 if (!zs
->avail_out
) {
12063 zs
->next_out
= (Bytef
*)zs
;
12064 zs
->avail_out
= UINT32_MAX
;
12066 zr
= deflate(zs
, Z_NO_FLUSH
);
12067 if (Z_STREAM_END
== zr
) {
12071 LOG("ZERR %d\n", zr
);
12072 swd_zip_var
.error
= zr
;
12074 if (zs
->total_in
== numBytes
) {
12080 //now flush the stream
12081 while (swd_zip_var
.error
>= 0) {
12082 if (!zs
->avail_out
) {
12083 zs
->next_out
= (Bytef
*)zs
;
12084 zs
->avail_out
= UINT32_MAX
;
12086 zr
= deflate(zs
, Z_FINISH
);
12087 if (Z_STREAM_END
== zr
) {
12091 LOG("ZERR %d\n", zr
);
12092 swd_zip_var
.error
= zr
;
12094 if (zs
->total_in
== numBytes
) {
12095 LOG("Total output size %d\n", swd_zip_var
.outlen
);
12101 return swd_zip_var
.outlen
;
12105 IOPMrootDomain::deleteStackshot()
12107 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
)) {
12108 // takeStackshot hasn't completed
12111 LOG("Deleting any sleepwake failure data in nvram\n");
12113 PERemoveNVRAMProperty(kIOSleepWakeFailureString
);
12114 char nvram_var_name_buf
[20];
12115 for (int i
= 0; i
< 8; i
++) {
12116 snprintf(nvram_var_name_buf
, sizeof(nvram_var_name_buf
), "%s%02d", SWD_STACKSHOT_VAR_PREFIX
, i
+ 1);
12117 if (PERemoveNVRAMProperty(nvram_var_name_buf
) == false) {
12118 LOG("Removing %s returned false\n", nvram_var_name_buf
);
12121 // force NVRAM sync
12122 if (PEWriteNVRAMProperty(kIONVRAMSyncNowPropertyKey
, kIONVRAMSyncNowPropertyKey
, (unsigned int) strlen(kIONVRAMSyncNowPropertyKey
)) == false) {
12123 DLOG("Failed to force nvram sync\n");
12125 gRootDomain
->swd_lock
= 0;
12129 IOPMrootDomain::takeStackshot(bool wdogTrigger
)
12131 swd_hdr
* hdr
= NULL
;
12135 kern_return_t kr
= KERN_SUCCESS
;
12140 uint32_t bytesRemaining
;
12141 unsigned bytesWritten
= 0;
12143 char failureStr
[512];
12144 thread_t thread
= NULL
;
12145 const char * swfPanic
= "swfPanic";
12150 #if defined(__i386__) || defined(__x86_64__)
12151 const bool concise
= false;
12153 const bool concise
= true;
12156 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
)) {
12161 if ((kIOSleepWakeWdogOff
& gIOKitDebug
) || systemBooting
|| systemShutdown
|| gWillShutdown
) {
12166 getFailureData(&thread
, failureStr
, sizeof(failureStr
));
12168 if (concise
|| (PEGetCoprocessorVersion() >= kCoprocessorVersion2
)) {
12169 goto skip_stackshot
;
12174 clock_get_uptime(&now
);
12175 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
12176 absolutetime_to_nanoseconds(now
, &nsec
);
12177 snprintf(failureStr
, sizeof(failureStr
), "Power button pressed during wake transition after %u ms.\n", ((int)((nsec
) / NSEC_PER_MSEC
)));
12180 if (swd_buffer
== NULL
) {
12181 sleepWakeDebugMemAlloc();
12182 if (swd_buffer
== NULL
) {
12186 hdr
= (swd_hdr
*)swd_buffer
;
12187 bufSize
= hdr
->alloc_size
;
12189 dstAddr
= (char*)hdr
+ hdr
->spindump_offset
;
12190 flags
= STACKSHOT_KCDATA_FORMAT
| STACKSHOT_NO_IO_STATS
| STACKSHOT_SAVE_KEXT_LOADINFO
| STACKSHOT_ACTIVE_KERNEL_THREADS_ONLY
| STACKSHOT_THREAD_WAITINFO
;
12191 /* If not wdogTrigger only take kernel tasks stackshot
12199 /* Attempt to take stackshot with all ACTIVE_KERNEL_THREADS
12200 * If we run out of space, take stackshot with only kernel task
12202 while (success
== 0 && cnt
< max_cnt
) {
12203 bytesRemaining
= bufSize
- hdr
->spindump_offset
;
12205 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining
);
12207 size
= bytesRemaining
;
12208 kr
= stack_snapshot_from_kernel(pid
, dstAddr
, size
, flags
, 0, 0, &bytesWritten
);
12209 DLOG("stack_snapshot_from_kernel returned 0x%x. pid: %d bufsize:0x%x flags:0x%llx bytesWritten: %d\n",
12210 kr
, pid
, size
, flags
, bytesWritten
);
12211 if (kr
== KERN_INSUFFICIENT_BUFFER_SIZE
) {
12215 LOG("Insufficient buffer size for only kernel task\n");
12219 if (kr
== KERN_SUCCESS
) {
12220 if (bytesWritten
== 0) {
12221 MSG("Failed to get stackshot(0x%x) bufsize:0x%x flags:0x%llx\n", kr
, size
, flags
);
12224 bytesRemaining
-= bytesWritten
;
12225 hdr
->spindump_size
= (bufSize
- bytesRemaining
- hdr
->spindump_offset
);
12227 memset(hdr
->reason
, 0x20, sizeof(hdr
->reason
));
12229 // Compress stackshot and save to NVRAM
12231 char *outbuf
= (char *)swd_compressed_buffer
;
12233 int num_chunks
= 0;
12234 int max_chunks
= 0;
12236 char nvram_var_name_buffer
[20];
12238 outlen
= swd_compress((char*)hdr
+ hdr
->spindump_offset
, outbuf
, bytesWritten
);
12241 max_chunks
= outlen
/ (2096 - 200);
12242 leftover
= outlen
% (2096 - 200);
12244 if (max_chunks
< 8) {
12245 for (num_chunks
= 0; num_chunks
< max_chunks
; num_chunks
++) {
12246 snprintf(nvram_var_name_buffer
, sizeof(nvram_var_name_buffer
), "%s%02d", SWD_STACKSHOT_VAR_PREFIX
, num_chunks
+ 1);
12247 if (PEWriteNVRAMPropertyWithCopy(nvram_var_name_buffer
, (outbuf
+ (num_chunks
* (2096 - 200))), (2096 - 200)) == FALSE
) {
12248 LOG("Failed to update NVRAM %d\n", num_chunks
);
12253 snprintf(nvram_var_name_buffer
, sizeof(nvram_var_name_buffer
), "%s%02d", SWD_STACKSHOT_VAR_PREFIX
, num_chunks
+ 1);
12254 if (PEWriteNVRAMPropertyWithCopy(nvram_var_name_buffer
, (outbuf
+ (num_chunks
* (2096 - 200))), leftover
) == FALSE
) {
12255 LOG("Failed to update NVRAM with leftovers\n");
12259 LOG("Successfully saved stackshot to NVRAM\n");
12261 LOG("Compressed failure stackshot is too large. size=%d bytes\n", outlen
);
12265 LOG("Compressed failure stackshot of only kernel is too large size=%d bytes\n", outlen
);
12274 if (failureStr
[0]) {
12275 // append sleep-wake failure code
12276 char traceCode
[80];
12277 snprintf(traceCode
, sizeof(traceCode
), "\nFailure code:: 0x%08x %08x\n",
12278 pmTracer
->getTraceData(), pmTracer
->getTracePhase());
12279 strlcat(failureStr
, traceCode
, sizeof(failureStr
));
12280 if (PEWriteNVRAMProperty(kIOSleepWakeFailureString
, failureStr
, (unsigned int) strnlen(failureStr
, sizeof(failureStr
))) == false) {
12281 DLOG("Failed to write SleepWake failure string\n");
12285 // force NVRAM sync
12286 if (PEWriteNVRAMProperty(kIONVRAMSyncNowPropertyKey
, kIONVRAMSyncNowPropertyKey
, (unsigned int) strlen(kIONVRAMSyncNowPropertyKey
)) == false) {
12287 DLOG("Failed to force nvram sync\n");
12292 if (PEGetCoprocessorVersion() < kCoprocessorVersion2
) {
12293 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
12294 // If current boot is due to this watch dog trigger restart in previous boot,
12295 // then don't trigger again until at least 1 successful sleep & wake.
12296 if (!(sleepCnt
&& (displayWakeCnt
|| darkWakeCnt
))) {
12297 LOG("Shutting down due to repeated Sleep/Wake failures\n");
12298 if (!tasksSuspended
) {
12299 tasksSuspended
= TRUE
;
12300 updateTasksSuspend();
12302 PEHaltRestart(kPEHaltCPU
);
12306 if (gSwdPanic
== 0) {
12307 LOG("Calling panic prevented by swd_panic boot-args. Calling restart");
12308 if (!tasksSuspended
) {
12309 tasksSuspended
= TRUE
;
12310 updateTasksSuspend();
12312 PEHaltRestart(kPERestartCPU
);
12315 if (!concise
&& (PEWriteNVRAMProperty(kIOSleepWakeFailurePanic
, swfPanic
, (unsigned int) strlen(swfPanic
)) == false)) {
12316 DLOG("Failed to write SleepWake failure panic key\n");
12318 #if defined(__x86_64__)
12320 panic_with_thread_context(0, NULL
, DEBUGGER_OPTION_ATTEMPTCOREDUMPANDREBOOT
, thread
, "%s", failureStr
);
12322 #endif /* defined(__x86_64__) */
12324 panic_with_options(0, NULL
, DEBUGGER_OPTION_ATTEMPTCOREDUMPANDREBOOT
, "%s", failureStr
);
12327 gRootDomain
->swd_lock
= 0;
12333 IOPMrootDomain::sleepWakeDebugMemAlloc()
12335 vm_size_t size
= SWD_STACKSHOT_SIZE
+ SWD_COMPRESSED_BUFSIZE
+ SWD_ZLIB_BUFSIZE
;
12337 swd_hdr
*hdr
= NULL
;
12338 void *bufPtr
= NULL
;
12340 OSSharedPtr
<IOBufferMemoryDescriptor
> memDesc
;
12343 if (kIOSleepWakeWdogOff
& gIOKitDebug
) {
12347 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
)) {
12351 memDesc
= IOBufferMemoryDescriptor::inTaskWithOptions(
12352 kernel_task
, kIODirectionIn
| kIOMemoryMapperNone
,
12354 if (memDesc
== NULL
) {
12355 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
12359 bufPtr
= memDesc
->getBytesNoCopy();
12361 // Carve out memory for zlib routines
12362 swd_zs_zmem
= (vm_offset_t
)bufPtr
;
12363 bufPtr
= (char *)bufPtr
+ SWD_ZLIB_BUFSIZE
;
12365 // Carve out memory for compressed stackshots
12366 swd_compressed_buffer
= bufPtr
;
12367 bufPtr
= (char *)bufPtr
+ SWD_COMPRESSED_BUFSIZE
;
12369 // Remaining is used for holding stackshot
12370 hdr
= (swd_hdr
*)bufPtr
;
12371 memset(hdr
, 0, sizeof(swd_hdr
));
12373 hdr
->signature
= SWD_HDR_SIGNATURE
;
12374 hdr
->alloc_size
= SWD_STACKSHOT_SIZE
;
12376 hdr
->spindump_offset
= sizeof(swd_hdr
);
12377 swd_buffer
= (void *)hdr
;
12378 swd_memDesc
= os::move(memDesc
);
12379 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr
->alloc_size
, hdr
->spindump_offset
);
12382 gRootDomain
->swd_lock
= 0;
12386 IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc()
12389 vm_size_t size
= SWD_SPINDUMP_SIZE
;
12391 swd_hdr
*hdr
= NULL
;
12393 OSSharedPtr
<IOBufferMemoryDescriptor
> memDesc
;
12395 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
)) {
12399 memDesc
= IOBufferMemoryDescriptor::inTaskWithOptions(
12400 kernel_task
, kIODirectionIn
| kIOMemoryMapperNone
,
12401 SWD_SPINDUMP_SIZE
);
12403 if (memDesc
== NULL
) {
12404 DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
12409 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
12410 memset(hdr
, 0, sizeof(swd_hdr
));
12412 hdr
->signature
= SWD_HDR_SIGNATURE
;
12413 hdr
->alloc_size
= size
;
12415 hdr
->spindump_offset
= sizeof(swd_hdr
);
12416 swd_spindump_buffer
= (void *)hdr
;
12417 swd_spindump_memDesc
= os::move(memDesc
);
12420 gRootDomain
->swd_lock
= 0;
12421 #endif /* UNUSED */
12425 IOPMrootDomain::sleepWakeDebugEnableWdog()
12430 IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
12432 return !systemBooting
&& !systemShutdown
&& !gWillShutdown
;
12436 IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
12438 swd_hdr
*hdr
= NULL
;
12439 errno_t error
= EIO
;
12441 if (swd_spindump_buffer
&& gSpinDumpBufferFull
) {
12442 hdr
= (swd_hdr
*)swd_spindump_buffer
;
12444 error
= sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
12445 (char*)hdr
+ hdr
->spindump_offset
, hdr
->spindump_size
);
12451 sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
12452 (char*)hdr
+ offsetof(swd_hdr
, UUID
),
12453 sizeof(swd_hdr
) - offsetof(swd_hdr
, UUID
));
12455 gSpinDumpBufferFull
= false;
12460 IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)
12462 struct vnode
*vp
= NULL
;
12463 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
12464 kauth_cred_t cred
= vfs_context_ucred(ctx
);
12465 struct vnode_attr va
;
12466 errno_t error
= EIO
;
12468 if (vnode_open(name
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
12469 S_IRUSR
| S_IRGRP
| S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0) {
12470 LOG("Failed to open the file %s\n", name
);
12471 swd_flags
|= SWD_FILEOP_ERROR
;
12475 VATTR_WANTED(&va
, va_nlink
);
12476 /* Don't dump to non-regular files or files with links. */
12477 if (vp
->v_type
!= VREG
||
12478 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
12479 LOG("Bailing as this is not a regular file\n");
12480 swd_flags
|= SWD_FILEOP_ERROR
;
12484 VATTR_SET(&va
, va_data_size
, 0);
12485 vnode_setattr(vp
, &va
, ctx
);
12489 error
= vn_rdwr(UIO_WRITE
, vp
, buf
, len
, 0,
12490 UIO_SYSSPACE
, IO_NODELOCKED
| IO_UNIT
, cred
, (int *) NULL
, vfs_context_proc(ctx
));
12492 LOG("Failed to save sleep wake log. err 0x%x\n", error
);
12493 swd_flags
|= SWD_FILEOP_ERROR
;
12495 DLOG("Saved %d bytes to file %s\n", len
, name
);
12501 vnode_close(vp
, FWRITE
, ctx
);
12504 vfs_context_rele(ctx
);
12510 #else /* defined(__i386__) || defined(__x86_64__) */
12513 IOPMrootDomain::sleepWakeDebugTrig(bool restart
)
12516 if (gSwdPanic
== 0) {
12519 panic("Sleep/Wake hang detected");
12525 IOPMrootDomain::takeStackshot(bool restart
)
12527 #pragma unused(restart)
12531 IOPMrootDomain::deleteStackshot()
12536 IOPMrootDomain::sleepWakeDebugMemAlloc()
12541 IOPMrootDomain::saveFailureData2File()
12546 IOPMrootDomain::sleepWakeDebugEnableWdog()
12551 IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
12557 IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
12562 IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)
12567 #endif /* defined(__i386__) || defined(__x86_64__) */