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>
61 #include <arm64/ppl/ppl_hib.h>
62 #endif /* __arm64__ */
63 #endif /* HIBERNATION */
64 #include <console/video_console.h>
65 #include <sys/syslog.h>
66 #include <sys/sysctl.h>
67 #include <sys/vnode.h>
68 #include <sys/vnode_internal.h>
69 #include <sys/fcntl.h>
71 #include <pexpert/protos.h>
72 #include <AssertMacros.h>
75 #include "IOServicePrivate.h" // _IOServiceInterestNotifier
76 #include "IOServicePMPrivate.h"
78 #include <libkern/zlib.h>
79 #include <os/cpp_util.h>
80 #include <libkern/c++/OSBoundedArrayRef.h>
83 #include <mach/shared_region.h>
84 #include <kern/clock.h>
87 #if defined(__i386__) || defined(__x86_64__)
89 #include "IOPMrootDomainInternal.h"
90 const char *processor_to_datastring(const char *prefix
, processor_t target_processor
);
94 #define kIOPMrootDomainClass "IOPMrootDomain"
95 #define LOG_PREFIX "PMRD: "
99 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
102 do { kprintf(LOG_PREFIX x); } while (false)
104 #if DEVELOPMENT || DEBUG
105 #define DEBUG_LOG(x...) do { \
106 if (kIOLogPMRootDomain & gIOKitDebug) \
107 kprintf(LOG_PREFIX x); \
108 os_log_debug(OS_LOG_DEFAULT, LOG_PREFIX x); \
111 #define DEBUG_LOG(x...)
114 #define DLOG(x...) do { \
115 if (kIOLogPMRootDomain & gIOKitDebug) \
116 kprintf(LOG_PREFIX x); \
118 os_log(OS_LOG_DEFAULT, LOG_PREFIX x); \
121 #define DMSG(x...) do { \
122 if (kIOLogPMRootDomain & gIOKitDebug) { \
123 kprintf(LOG_PREFIX x); \
130 #define CHECK_THREAD_CONTEXT
131 #ifdef CHECK_THREAD_CONTEXT
132 static IOWorkLoop
* gIOPMWorkLoop
= NULL
;
133 #define ASSERT_GATED() \
135 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
136 panic("RootDomain: not inside PM gate"); \
140 #define ASSERT_GATED()
141 #endif /* CHECK_THREAD_CONTEXT */
143 #define CAP_LOSS(c) \
144 (((_pendingCapability & (c)) == 0) && \
145 ((_currentCapability & (c)) != 0))
147 #define CAP_GAIN(c) \
148 (((_currentCapability & (c)) == 0) && \
149 ((_pendingCapability & (c)) != 0))
151 #define CAP_CHANGE(c) \
152 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
154 #define CAP_CURRENT(c) \
155 ((_currentCapability & (c)) != 0)
157 #define CAP_HIGHEST(c) \
158 ((_highestCapability & (c)) != 0)
160 #define CAP_PENDING(c) \
161 ((_pendingCapability & (c)) != 0)
163 // rdar://problem/9157444
164 #if defined(__i386__) || defined(__x86_64__)
165 #define DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY 20
168 // Event types for IOPMPowerStateQueue::submitPowerEvent()
170 kPowerEventFeatureChanged
= 1, // 1
171 kPowerEventReceivedPowerNotification
, // 2
172 kPowerEventSystemBootCompleted
, // 3
173 kPowerEventSystemShutdown
, // 4
174 kPowerEventUserDisabledSleep
, // 5
175 kPowerEventRegisterSystemCapabilityClient
, // 6
176 kPowerEventRegisterKernelCapabilityClient
, // 7
177 kPowerEventPolicyStimulus
, // 8
178 kPowerEventAssertionCreate
, // 9
179 kPowerEventAssertionRelease
, // 10
180 kPowerEventAssertionSetLevel
, // 11
181 kPowerEventQueueSleepWakeUUID
, // 12
182 kPowerEventPublishSleepWakeUUID
, // 13
183 kPowerEventSetDisplayPowerOn
, // 14
184 kPowerEventPublishWakeType
, // 15
185 kPowerEventAOTEvaluate
// 16
188 // For evaluatePolicy()
189 // List of stimuli that affects the root domain policy.
191 kStimulusDisplayWranglerSleep
, // 0
192 kStimulusDisplayWranglerWake
, // 1
193 kStimulusAggressivenessChanged
, // 2
194 kStimulusDemandSystemSleep
, // 3
195 kStimulusAllowSystemSleepChanged
, // 4
196 kStimulusDarkWakeActivityTickle
, // 5
197 kStimulusDarkWakeEntry
, // 6
198 kStimulusDarkWakeReentry
, // 7
199 kStimulusDarkWakeEvaluate
, // 8
200 kStimulusNoIdleSleepPreventers
, // 9
201 kStimulusEnterUserActiveState
, // 10
202 kStimulusLeaveUserActiveState
// 11
205 // Internal power state change reasons
206 // Must be less than kIOPMSleepReasonClamshell=101
208 kCPSReasonNone
= 0, // 0
211 kCPSReasonIdleSleepPrevent
, // 3
212 kCPSReasonIdleSleepAllow
, // 4
213 kCPSReasonPowerOverride
, // 5
214 kCPSReasonPowerDownCancel
, // 6
215 kCPSReasonAOTExit
, // 7
216 kCPSReasonAdjustPowerState
, // 8
217 kCPSReasonDarkWakeCannotSleep
, // 9
218 kCPSReasonIdleSleepEnabled
, // 10
219 kCPSReasonEvaluatePolicy
, // 11
220 kCPSReasonSustainFullWake
, // 12
221 kCPSReasonPMInternals
= (kIOPMSleepReasonClamshell
- 1)
225 IOReturn
OSKextSystemSleepOrWake( UInt32
);
227 extern "C" ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
);
228 extern "C" addr64_t
kvtophys(vm_offset_t va
);
229 extern "C" boolean_t
kdp_has_polled_corefile();
231 static void idleSleepTimerExpired( thread_call_param_t
, thread_call_param_t
);
232 static void notifySystemShutdown( IOService
* root
, uint32_t messageType
);
233 static void handleAggressivesFunction( thread_call_param_t
, thread_call_param_t
);
234 static void pmEventTimeStamp(uint64_t *recordTS
);
235 static void powerButtonUpCallout( thread_call_param_t
, thread_call_param_t
);
236 static void powerButtonDownCallout( thread_call_param_t
, thread_call_param_t
);
237 static OSPtr
<const OSSymbol
> copyKextIdentifierWithAddress(vm_address_t address
);
239 static int IOPMConvertSecondsToCalendar(clock_sec_t secs
, IOPMCalendarStruct
* dt
);
240 static clock_sec_t
IOPMConvertCalendarToSeconds(const IOPMCalendarStruct
* dt
);
241 #define YMDTF "%04d/%02d/%d %02d:%02d:%02d"
242 #define YMDT(cal) ((int)(cal)->year), (cal)->month, (cal)->day, (cal)->hour, (cal)->minute, (cal)->second
244 // "IOPMSetSleepSupported" callPlatformFunction name
245 static OSSharedPtr
<const OSSymbol
> sleepSupportedPEFunction
;
246 static OSSharedPtr
<const OSSymbol
> sleepMessagePEFunction
;
247 static OSSharedPtr
<const OSSymbol
> gIOPMWakeTypeUserKey
;
249 static OSSharedPtr
<const OSSymbol
> gIOPMPSExternalConnectedKey
;
250 static OSSharedPtr
<const OSSymbol
> gIOPMPSExternalChargeCapableKey
;
251 static OSSharedPtr
<const OSSymbol
> gIOPMPSBatteryInstalledKey
;
252 static OSSharedPtr
<const OSSymbol
> gIOPMPSIsChargingKey
;
253 static OSSharedPtr
<const OSSymbol
> gIOPMPSAtWarnLevelKey
;
254 static OSSharedPtr
<const OSSymbol
> gIOPMPSAtCriticalLevelKey
;
255 static OSSharedPtr
<const OSSymbol
> gIOPMPSCurrentCapacityKey
;
256 static OSSharedPtr
<const OSSymbol
> gIOPMPSMaxCapacityKey
;
257 static OSSharedPtr
<const OSSymbol
> gIOPMPSDesignCapacityKey
;
258 static OSSharedPtr
<const OSSymbol
> gIOPMPSTimeRemainingKey
;
259 static OSSharedPtr
<const OSSymbol
> gIOPMPSAmperageKey
;
260 static OSSharedPtr
<const OSSymbol
> gIOPMPSVoltageKey
;
261 static OSSharedPtr
<const OSSymbol
> gIOPMPSCycleCountKey
;
262 static OSSharedPtr
<const OSSymbol
> gIOPMPSMaxErrKey
;
263 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterInfoKey
;
264 static OSSharedPtr
<const OSSymbol
> gIOPMPSLocationKey
;
265 static OSSharedPtr
<const OSSymbol
> gIOPMPSErrorConditionKey
;
266 static OSSharedPtr
<const OSSymbol
> gIOPMPSManufacturerKey
;
267 static OSSharedPtr
<const OSSymbol
> gIOPMPSManufactureDateKey
;
268 static OSSharedPtr
<const OSSymbol
> gIOPMPSModelKey
;
269 static OSSharedPtr
<const OSSymbol
> gIOPMPSSerialKey
;
270 static OSSharedPtr
<const OSSymbol
> gIOPMPSLegacyBatteryInfoKey
;
271 static OSSharedPtr
<const OSSymbol
> gIOPMPSBatteryHealthKey
;
272 static OSSharedPtr
<const OSSymbol
> gIOPMPSHealthConfidenceKey
;
273 static OSSharedPtr
<const OSSymbol
> gIOPMPSCapacityEstimatedKey
;
274 static OSSharedPtr
<const OSSymbol
> gIOPMPSBatteryChargeStatusKey
;
275 static OSSharedPtr
<const OSSymbol
> gIOPMPSBatteryTemperatureKey
;
276 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsKey
;
277 static OSSharedPtr
<const OSSymbol
> gIOPMPSChargerConfigurationKey
;
278 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsIDKey
;
279 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsWattsKey
;
280 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsRevisionKey
;
281 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsSerialNumberKey
;
282 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsFamilyKey
;
283 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsAmperageKey
;
284 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsDescriptionKey
;
285 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsPMUConfigurationKey
;
286 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsSourceIDKey
;
287 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsErrorFlagsKey
;
288 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsSharedSourceKey
;
289 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsCloakedKey
;
290 static OSSharedPtr
<const OSSymbol
> gIOPMPSInvalidWakeSecondsKey
;
291 static OSSharedPtr
<const OSSymbol
> gIOPMPSPostChargeWaitSecondsKey
;
292 static OSSharedPtr
<const OSSymbol
> gIOPMPSPostDishargeWaitSecondsKey
;
294 #define kIOSleepSupportedKey "IOSleepSupported"
295 #define kIOPMSystemCapabilitiesKey "System Capabilities"
296 #define kIOPMSystemDefaultOverrideKey "SystemPowerProfileOverrideDict"
298 #define kIORequestWranglerIdleKey "IORequestIdle"
299 #define kDefaultWranglerIdlePeriod 1000 // in milliseconds
301 #define kIOSleepWakeFailureString "SleepWakeFailureString"
302 #define kIOEFIBootRomFailureKey "wake-failure"
303 #define kIOSleepWakeFailurePanic "SleepWakeFailurePanic"
305 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
306 | kIOPMSupportedOnBatt \
307 | kIOPMSupportedOnUPS)
309 #define kLocalEvalClamshellCommand (1 << 15)
310 #define kIdleSleepRetryInterval (3 * 60)
312 #define DISPLAY_WRANGLER_PRESENT (!NO_KERNEL_HID)
315 kWranglerPowerStateMin
= 0,
316 kWranglerPowerStateSleep
= 2,
317 kWranglerPowerStateDim
= 3,
318 kWranglerPowerStateMax
= 4
331 getPowerStateString( uint32_t state
)
333 #define POWER_STATE(x) {(uint32_t) x, #x}
335 static const IONamedValue powerStates
[] = {
336 POWER_STATE( OFF_STATE
),
337 POWER_STATE( RESTART_STATE
),
338 POWER_STATE( SLEEP_STATE
),
339 POWER_STATE( AOT_STATE
),
340 POWER_STATE( ON_STATE
),
343 return IOFindNameForValue(state
, powerStates
);
346 #define ON_POWER kIOPMPowerOn
347 #define RESTART_POWER kIOPMRestart
348 #define SLEEP_POWER kIOPMAuxPowerOn
350 static IOPMPowerState
351 ourPowerStates
[NUM_POWER_STATES
] =
354 .capabilityFlags
= 0,
355 .outputPowerCharacter
= 0,
356 .inputPowerRequirement
= 0 },
358 .capabilityFlags
= kIOPMRestartCapability
,
359 .outputPowerCharacter
= kIOPMRestart
,
360 .inputPowerRequirement
= RESTART_POWER
},
362 .capabilityFlags
= kIOPMSleepCapability
,
363 .outputPowerCharacter
= kIOPMSleep
,
364 .inputPowerRequirement
= SLEEP_POWER
},
366 .capabilityFlags
= kIOPMAOTCapability
,
367 .outputPowerCharacter
= kIOPMAOTPower
,
368 .inputPowerRequirement
= ON_POWER
},
370 .capabilityFlags
= kIOPMPowerOn
,
371 .outputPowerCharacter
= kIOPMPowerOn
,
372 .inputPowerRequirement
= ON_POWER
},
375 #define kIOPMRootDomainWakeTypeSleepService "SleepService"
376 #define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
377 #define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
378 #define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
379 #define kIOPMRootDomainWakeTypeUser "User"
380 #define kIOPMRootDomainWakeTypeAlarm "Alarm"
381 #define kIOPMRootDomainWakeTypeNetwork "Network"
382 #define kIOPMRootDomainWakeTypeHIDActivity "HID Activity"
383 #define kIOPMRootDomainWakeTypeNotification "Notification"
384 #define kIOPMRootDomainWakeTypeHibernateError "HibernateError"
386 // Special interest that entitles the interested client from receiving
387 // all system messages. Only used by powerd.
389 #define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
391 // Entitlement required for root domain clients
392 #define kRootDomainEntitlementSetProperty "com.apple.private.iokit.rootdomain-set-property"
394 #define WAKEEVENT_LOCK() IOLockLock(wakeEventLock)
395 #define WAKEEVENT_UNLOCK() IOLockUnlock(wakeEventLock)
400 #define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
401 #define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
403 #define kAggressivesMinValue 1
406 getAggressivenessTypeString( uint32_t type
)
408 #define AGGRESSIVENESS_TYPE(x) {(uint32_t) x, #x}
410 static const IONamedValue aggressivenessTypes
[] = {
411 AGGRESSIVENESS_TYPE( kPMGeneralAggressiveness
),
412 AGGRESSIVENESS_TYPE( kPMMinutesToDim
),
413 AGGRESSIVENESS_TYPE( kPMMinutesToSpinDown
),
414 AGGRESSIVENESS_TYPE( kPMMinutesToSleep
),
415 AGGRESSIVENESS_TYPE( kPMEthernetWakeOnLANSettings
),
416 AGGRESSIVENESS_TYPE( kPMSetProcessorSpeed
),
417 AGGRESSIVENESS_TYPE( kPMPowerSource
),
418 AGGRESSIVENESS_TYPE( kPMMotionSensor
),
419 AGGRESSIVENESS_TYPE( kPMLastAggressivenessType
),
422 return IOFindNameForValue(type
, aggressivenessTypes
);
426 kAggressivesStateBusy
= 0x01,
427 kAggressivesStateQuickSpindown
= 0x02
430 struct AggressivesRecord
{
436 struct AggressivesRequest
{
441 OSSharedPtr
<IOService
> service
;
442 AggressivesRecord record
;
447 kAggressivesRequestTypeService
= 1,
448 kAggressivesRequestTypeRecord
452 kAggressivesOptionSynchronous
= 0x00000001,
453 kAggressivesOptionQuickSpindownEnable
= 0x00000100,
454 kAggressivesOptionQuickSpindownDisable
= 0x00000200,
455 kAggressivesOptionQuickSpindownMask
= 0x00000300
459 kAggressivesRecordFlagModified
= 0x00000001,
460 kAggressivesRecordFlagMinValue
= 0x00000002
463 // System Sleep Preventers
466 kPMUserDisabledAllSleep
= 1,
467 kPMSystemRestartBootingInProgress
,
468 kPMConfigPreventSystemSleep
,
469 kPMChildPreventSystemSleep
,
475 getSystemSleepPreventerString( uint32_t preventer
)
477 #define SYSTEM_SLEEP_PREVENTER(x) {(int) x, #x}
478 static const IONamedValue systemSleepPreventers
[] = {
479 SYSTEM_SLEEP_PREVENTER( kPMUserDisabledAllSleep
),
480 SYSTEM_SLEEP_PREVENTER( kPMSystemRestartBootingInProgress
),
481 SYSTEM_SLEEP_PREVENTER( kPMConfigPreventSystemSleep
),
482 SYSTEM_SLEEP_PREVENTER( kPMChildPreventSystemSleep
),
483 SYSTEM_SLEEP_PREVENTER( kPMCPUAssertion
),
484 SYSTEM_SLEEP_PREVENTER( kPMPCIUnsupported
),
487 return IOFindNameForValue(preventer
, systemSleepPreventers
);
492 kDarkWakeFlagPromotionNone
= 0x0000,
493 kDarkWakeFlagPromotionEarly
= 0x0001, // promote before gfx clamp
494 kDarkWakeFlagPromotionLate
= 0x0002, // promote after gfx clamp
495 kDarkWakeFlagPromotionMask
= 0x0003,
496 kDarkWakeFlagAlarmIsDark
= 0x0100,
497 kDarkWakeFlagAudioNotSuppressed
= 0x0200,
498 kDarkWakeFlagUserWakeWorkaround
= 0x1000
502 // The workaround for 9157444 is enabled at compile time using the
503 // DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY macro and is not represented below.
505 kClamshell_WAR_38378787
= 0x00000001,
506 kClamshell_WAR_47715679
= 0x00000002,
507 kClamshell_WAR_58009435
= 0x00000004
510 // acceptSystemWakeEvents()
512 kAcceptSystemWakeEvents_Disable
= 0,
513 kAcceptSystemWakeEvents_Enable
,
514 kAcceptSystemWakeEvents_Reenable
517 static IOPMrootDomain
* gRootDomain
;
518 static IORootParent
* gPatriarch
;
519 static IONotifier
* gSysPowerDownNotifier
= NULL
;
520 static UInt32 gSleepOrShutdownPending
= 0;
521 static UInt32 gWillShutdown
= 0;
522 static UInt32 gPagingOff
= 0;
523 static UInt32 gSleepWakeUUIDIsSet
= false;
524 static uint32_t gAggressivesState
= 0;
525 static uint32_t gHaltTimeMaxLog
;
526 static uint32_t gHaltTimeMaxPanic
;
527 IOLock
* gHaltLogLock
;
528 static char * gHaltLog
;
529 enum { kHaltLogSize
= 2048 };
530 static size_t gHaltLogPos
;
531 static uint64_t gHaltStartTime
;
532 static char gKextNameBuf
[64];
533 static size_t gKextNamePos
;
534 static bool gKextNameEnd
;
536 uuid_string_t bootsessionuuid_string
;
538 #if defined(XNU_TARGET_OS_OSX)
539 #if DISPLAY_WRANGLER_PRESENT
540 static uint32_t gDarkWakeFlags
= kDarkWakeFlagPromotionNone
;
542 // Enable temporary full wake promotion workarounds
543 static uint32_t gDarkWakeFlags
= kDarkWakeFlagUserWakeWorkaround
;
545 // Enable full wake promotion workarounds
546 static uint32_t gDarkWakeFlags
= kDarkWakeFlagUserWakeWorkaround
;
548 #else /* !defined(XNU_TARGET_OS_OSX) */
549 static uint32_t gDarkWakeFlags
= kDarkWakeFlagPromotionEarly
;
550 #endif /* !defined(XNU_TARGET_OS_OSX) */
552 static uint32_t gNoIdleFlag
= 0;
553 static uint32_t gSwdPanic
= 1;
554 static uint32_t gSwdSleepTimeout
= 0;
555 static uint32_t gSwdWakeTimeout
= 0;
556 static uint32_t gSwdSleepWakeTimeout
= 0;
557 static PMStatsStruct gPMStats
;
558 #if DEVELOPMENT || DEBUG
559 static uint32_t swd_panic_phase
;
562 static uint32_t gClamshellFlags
= 0
563 #if defined(__i386__) || defined(__x86_64__)
564 | kClamshell_WAR_58009435
570 #if defined(__arm64__)
572 defaultSleepPolicyHandler(void *ctx
, const IOPMSystemSleepPolicyVariables
*vars
, IOPMSystemSleepParameters
*params
)
574 uint32_t sleepType
= kIOPMSleepTypeDeepIdle
;
576 assert(vars
->signature
== kIOPMSystemSleepPolicySignature
);
577 assert(vars
->version
== kIOPMSystemSleepPolicyVersion
);
579 // Hibernation enabled and either user forced hibernate or low battery sleep
580 if ((vars
->hibernateMode
& kIOHibernateModeOn
) &&
581 ppl_hib_hibernation_supported() &&
582 (((vars
->hibernateMode
& kIOHibernateModeSleep
) == 0) ||
583 (vars
->sleepFactors
& kIOPMSleepFactorBatteryLow
))) {
584 sleepType
= kIOPMSleepTypeHibernate
;
586 params
->version
= kIOPMSystemSleepParametersVersion
;
587 params
->sleepType
= sleepType
;
588 return kIOReturnSuccess
;
590 static IOPMSystemSleepPolicyHandler gSleepPolicyHandler
= &defaultSleepPolicyHandler
;
591 #else /* defined(__arm64__) */
592 static IOPMSystemSleepPolicyHandler gSleepPolicyHandler
= NULL
;
593 #endif /* defined(__arm64__) */
595 static IOPMSystemSleepPolicyVariables
* gSleepPolicyVars
= NULL
;
596 static void * gSleepPolicyTarget
;
599 struct timeval gIOLastSleepTime
;
600 struct timeval gIOLastWakeTime
;
601 AbsoluteTime gIOLastWakeAbsTime
;
602 AbsoluteTime gIOLastSleepAbsTime
;
604 struct timeval gIOLastUserSleepTime
;
606 static char gWakeReasonString
[128];
607 static char gBootReasonString
[80];
608 static char gShutdownReasonString
[80];
609 static bool gWakeReasonSysctlRegistered
= false;
610 static bool gBootReasonSysctlRegistered
= false;
611 static bool gShutdownReasonSysctlRegistered
= false;
612 static AbsoluteTime gUserActiveAbsTime
;
613 static AbsoluteTime gUserInactiveAbsTime
;
615 #if defined(__i386__) || defined(__x86_64__) || (defined(__arm64__) && HIBERNATION)
616 static bool gSpinDumpBufferFull
= false;
620 vm_offset_t swd_zs_zmem
;
621 //size_t swd_zs_zsize;
622 size_t swd_zs_zoffset
;
623 #if defined(__i386__) || defined(__x86_64__)
624 IOCPU
*currentShutdownTarget
= NULL
;
627 static unsigned int gPMHaltBusyCount
;
628 static unsigned int gPMHaltIdleCount
;
629 static int gPMHaltDepth
;
630 static uint32_t gPMHaltMessageType
;
631 static IOLock
* gPMHaltLock
= NULL
;
632 static OSSharedPtr
<OSArray
> gPMHaltArray
;
633 static OSSharedPtr
<const OSSymbol
> gPMHaltClientAcknowledgeKey
;
634 static bool gPMQuiesced
;
636 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
637 #define kCPUUnknownIndex 9999999
644 OSSharedPtr
<const OSSymbol
> gIOPMStatsResponseTimedOut
;
645 OSSharedPtr
<const OSSymbol
> gIOPMStatsResponseCancel
;
646 OSSharedPtr
<const OSSymbol
> gIOPMStatsResponseSlow
;
647 OSSharedPtr
<const OSSymbol
> gIOPMStatsResponsePrompt
;
648 OSSharedPtr
<const OSSymbol
> gIOPMStatsDriverPSChangeSlow
;
650 #define kBadPMFeatureID 0
654 * Opaque handle passed to clients of registerPMSettingController()
656 class PMSettingHandle
: public OSObject
658 OSDeclareFinalStructors( PMSettingHandle
);
659 friend class PMSettingObject
;
662 PMSettingObject
*pmso
;
663 void free(void) APPLE_KEXT_OVERRIDE
;
668 * Internal object to track each PM setting controller
670 class PMSettingObject
: public OSObject
672 OSDeclareFinalStructors( PMSettingObject
);
673 friend class IOPMrootDomain
;
676 queue_head_t calloutQueue
;
678 IOPMrootDomain
*parent
;
679 PMSettingHandle
*pmsh
;
680 IOPMSettingControllerCallback func
;
683 uint32_t *publishedFeatureID
;
684 uint32_t settingCount
;
687 void free(void) APPLE_KEXT_OVERRIDE
;
690 static PMSettingObject
*pmSettingObject(
691 IOPMrootDomain
*parent_arg
,
692 IOPMSettingControllerCallback handler_arg
,
693 OSObject
*target_arg
,
694 uintptr_t refcon_arg
,
695 uint32_t supportedPowerSources
,
696 const OSSymbol
*settings
[],
697 OSObject
**handle_obj
);
699 IOReturn
dispatchPMSetting(const OSSymbol
*type
, OSObject
*object
);
700 void clientHandleFreed(void);
703 struct PMSettingCallEntry
{
708 #define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
709 #define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
710 #define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
711 #define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
715 * Internal helper object for logging trace points to RTC
716 * IOPMrootDomain and only IOPMrootDomain should instantiate
717 * exactly one of these.
720 typedef void (*IOPMTracePointHandler
)(
721 void * target
, uint32_t code
, uint32_t data
);
723 class PMTraceWorker
: public OSObject
725 OSDeclareDefaultStructors(PMTraceWorker
);
727 typedef enum { kPowerChangeStart
, kPowerChangeCompleted
} change_t
;
729 static OSPtr
<PMTraceWorker
> tracer( IOPMrootDomain
* );
730 void tracePCIPowerChange(change_t
, IOService
*, uint32_t, uint32_t);
731 void tracePoint(uint8_t phase
);
732 void traceDetail(uint32_t detail
);
733 void traceComponentWakeProgress(uint32_t component
, uint32_t data
);
734 int recordTopLevelPCIDevice(IOService
*);
735 void RTC_TRACE(void);
736 virtual bool serialize(OSSerialize
*s
) const APPLE_KEXT_OVERRIDE
;
738 IOPMTracePointHandler tracePointHandler
;
739 void * tracePointTarget
;
740 uint64_t getPMStatusCode();
741 uint8_t getTracePhase();
742 uint32_t getTraceData();
744 IOPMrootDomain
*owner
;
745 IOLock
*pmTraceWorkerLock
;
746 OSSharedPtr
<OSArray
> pciDeviceBitMappings
;
748 uint8_t addedToRegistry
;
750 uint32_t traceData32
;
751 uint8_t loginWindowData
;
752 uint8_t coreDisplayData
;
753 uint8_t coreGraphicsData
;
757 * PMAssertionsTracker
758 * Tracks kernel and user space PM assertions
760 class PMAssertionsTracker
: public OSObject
762 OSDeclareFinalStructors(PMAssertionsTracker
);
764 static PMAssertionsTracker
*pmAssertionsTracker( IOPMrootDomain
* );
766 IOReturn
createAssertion(IOPMDriverAssertionType
, IOPMDriverAssertionLevel
, IOService
*, const char *, IOPMDriverAssertionID
*);
767 IOReturn
releaseAssertion(IOPMDriverAssertionID
);
768 IOReturn
setAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
769 IOReturn
setUserAssertionLevels(IOPMDriverAssertionType
);
771 OSSharedPtr
<OSArray
> copyAssertionsArray(void);
772 IOPMDriverAssertionType
getActivatedAssertions(void);
773 IOPMDriverAssertionLevel
getAssertionLevel(IOPMDriverAssertionType
);
775 IOReturn
handleCreateAssertion(OSData
*);
776 IOReturn
handleReleaseAssertion(IOPMDriverAssertionID
);
777 IOReturn
handleSetAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
778 IOReturn
handleSetUserAssertionLevels(void * arg0
);
779 void publishProperties(void);
780 void reportCPUBitAccounting(void);
784 * this should be treated as POD, as it's byte-copied around
785 * and we cannot rely on d'tor firing at the right time
788 IOPMDriverAssertionID id
;
789 IOPMDriverAssertionType assertionBits
;
790 uint64_t createdTime
;
791 uint64_t modifiedTime
;
792 const OSSymbol
*ownerString
;
793 IOService
*ownerService
;
794 uint64_t registryEntryID
;
795 IOPMDriverAssertionLevel level
;
796 uint64_t assertCPUStartTime
;
797 uint64_t assertCPUDuration
;
800 uint32_t tabulateProducerCount
;
801 uint32_t tabulateConsumerCount
;
803 uint64_t maxAssertCPUDuration
;
804 uint64_t maxAssertCPUEntryId
;
806 PMAssertStruct
*detailsForID(IOPMDriverAssertionID
, int *);
808 void updateCPUBitAccounting(PMAssertStruct
* assertStruct
);
810 IOPMrootDomain
*owner
;
811 OSSharedPtr
<OSArray
> assertionsArray
;
812 IOLock
*assertionsArrayLock
;
813 IOPMDriverAssertionID issuingUniqueID
__attribute__((aligned(8)));/* aligned for atomic access */
814 IOPMDriverAssertionType assertionsKernel
;
815 IOPMDriverAssertionType assertionsUser
;
816 IOPMDriverAssertionType assertionsCombined
;
819 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker
, OSObject
);
823 * Internal helper object for Shutdown/Restart notifications.
825 #define kPMHaltMaxWorkers 8
826 #define kPMHaltTimeoutMS 100
828 class PMHaltWorker
: public OSObject
830 OSDeclareFinalStructors( PMHaltWorker
);
833 IOService
* service
;// service being worked on
834 AbsoluteTime startTime
; // time when work started
835 int depth
; // work on nubs at this PM-tree depth
836 int visits
; // number of nodes visited (debug)
838 bool timeout
;// service took too long
840 static PMHaltWorker
* worker( void );
841 static void main( void * arg
, wait_result_t waitResult
);
842 static void work( PMHaltWorker
* me
);
843 static void checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
);
844 virtual void free( void ) APPLE_KEXT_OVERRIDE
;
847 OSDefineMetaClassAndFinalStructors( PMHaltWorker
, OSObject
)
850 #define super IOService
851 OSDefineMetaClassAndFinalStructors(IOPMrootDomain
, IOService
)
854 IOPMRootDomainGetWillShutdown(void)
856 return gWillShutdown
!= 0;
860 IOPMRootDomainWillShutdown(void)
862 if (OSCompareAndSwap(0, 1, &gWillShutdown
)) {
863 IOService::willShutdown();
864 for (int i
= 0; i
< 100; i
++) {
865 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending
)) {
873 extern "C" IONotifier
*
874 registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
876 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
).detach();
879 extern "C" IONotifier
*
880 registerPrioritySleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
882 return gRootDomain
->registerInterest( gIOPriorityPowerStateInterest
, handler
, self
, ref
).detach();
886 acknowledgeSleepWakeNotification(void * PMrefcon
)
888 return gRootDomain
->allowPowerChange((unsigned long)PMrefcon
);
892 vetoSleepWakeNotification(void * PMrefcon
)
894 return gRootDomain
->cancelPowerChange((unsigned long)PMrefcon
);
898 rootDomainRestart( void )
900 return gRootDomain
->restartSystem();
904 rootDomainShutdown( void )
906 return gRootDomain
->shutdownSystem();
910 halt_log_putc(char c
)
912 if (gHaltLogPos
>= (kHaltLogSize
- 2)) {
915 gHaltLog
[gHaltLogPos
++] = c
;
919 _doprnt_log(const char *fmt
,
925 halt_log(const char *fmt
, ...)
929 va_start(listp
, fmt
);
930 _doprnt_log(fmt
, &listp
, &halt_log_putc
, 16);
937 halt_log_enter(const char * what
, const void * pc
, uint64_t time
)
939 uint64_t nano
, millis
;
944 absolutetime_to_nanoseconds(time
, &nano
);
945 millis
= nano
/ NSEC_PER_MSEC
;
950 IOLockLock(gHaltLogLock
);
952 halt_log("%s: %qd ms @ 0x%lx, ", what
, millis
, VM_KERNEL_UNSLIDE(pc
));
953 OSKext::printKextsInBacktrace((vm_offset_t
*) &pc
, 1, &halt_log
,
954 OSKext::kPrintKextsLock
| OSKext::kPrintKextsUnslide
| OSKext::kPrintKextsTerse
);
956 halt_log("%s: %qd ms\n", what
, millis
);
959 gHaltLog
[gHaltLogPos
] = 0;
960 IOLockUnlock(gHaltLogLock
);
963 extern uint32_t gFSState
;
966 IOSystemShutdownNotification(int stage
)
970 if (kIOSystemShutdownNotificationStageRootUnmount
== stage
) {
971 #if defined(XNU_TARGET_OS_OSX)
972 uint64_t nano
, millis
;
973 startTime
= mach_absolute_time();
974 IOService::getPlatform()->waitQuiet(30 * NSEC_PER_SEC
);
975 absolutetime_to_nanoseconds(mach_absolute_time() - startTime
, &nano
);
976 millis
= nano
/ NSEC_PER_MSEC
;
977 if (gHaltTimeMaxLog
&& (millis
>= gHaltTimeMaxLog
)) {
978 printf("waitQuiet() for unmount %qd ms\n", millis
);
980 #endif /* defined(XNU_TARGET_OS_OSX) */
984 assert(kIOSystemShutdownNotificationStageProcessExit
== stage
);
986 IOLockLock(gHaltLogLock
);
988 gHaltLog
= IONew(char, kHaltLogSize
);
989 gHaltStartTime
= mach_absolute_time();
994 IOLockUnlock(gHaltLogLock
);
996 startTime
= mach_absolute_time();
997 IOPMRootDomainWillShutdown();
998 halt_log_enter("IOPMRootDomainWillShutdown", NULL
, mach_absolute_time() - startTime
);
1000 startTime
= mach_absolute_time();
1001 IOHibernateSystemPostWake(true);
1002 halt_log_enter("IOHibernateSystemPostWake", NULL
, mach_absolute_time() - startTime
);
1004 if (OSCompareAndSwap(0, 1, &gPagingOff
)) {
1005 gRootDomain
->handlePlatformHaltRestart(kPEPagingOff
);
1010 extern "C" int sync_internal(void);
1013 * A device is always in the highest power state which satisfies its driver,
1014 * its policy-maker, and any power children it has, but within the constraint
1015 * of the power state provided by its parent. The driver expresses its desire by
1016 * calling changePowerStateTo(), the policy-maker expresses its desire by calling
1017 * changePowerStateToPriv(), and the children express their desires by calling
1018 * requestPowerDomainState().
1020 * The Root Power Domain owns the policy for idle and demand sleep for the system.
1021 * It is a power-managed IOService just like the others in the system.
1022 * It implements several power states which map to what we see as Sleep and On.
1024 * The sleep policy is as follows:
1025 * 1. Sleep is prevented if the case is open so that nobody will think the machine
1026 * is off and plug/unplug cards.
1027 * 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
1028 * 3. System cannot Sleep if some object in the tree is in a power state marked
1029 * kIOPMPreventSystemSleep.
1031 * These three conditions are enforced using the "driver clamp" by calling
1032 * changePowerStateTo(). For example, if the case is opened,
1033 * changePowerStateTo(ON_STATE) is called to hold the system on regardless
1034 * of the desires of the children of the root or the state of the other clamp.
1036 * Demand Sleep is initiated by pressing the front panel power button, closing
1037 * the clamshell, or selecting the menu item. In this case the root's parent
1038 * actually initiates the power state change so that the root domain has no
1039 * choice and does not give applications the opportunity to veto the change.
1041 * Idle Sleep occurs if no objects in the tree are in a state marked
1042 * kIOPMPreventIdleSleep. When this is true, the root's children are not holding
1043 * the root on, so it sets the "policy-maker clamp" by calling
1044 * changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
1045 * This timer is set for the difference between the sleep timeout slider and the
1046 * display dim timeout slider. When the timer expires, it releases its clamp and
1047 * now nothing is holding it awake, so it falls asleep.
1049 * Demand sleep is prevented when the system is booting. When preferences are
1050 * transmitted by the loginwindow at the end of boot, a flag is cleared,
1051 * and this allows subsequent Demand Sleep.
1054 //******************************************************************************
1057 IOPMrootDomain::construct( void )
1059 IOPMrootDomain
*root
;
1061 root
= new IOPMrootDomain
;
1069 //******************************************************************************
1070 // updateConsoleUsersCallout
1072 //******************************************************************************
1075 updateConsoleUsersCallout(thread_call_param_t p0
, thread_call_param_t p1
)
1077 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
1078 rootDomain
->updateConsoleUsers();
1082 IOPMrootDomain::updateConsoleUsers(void)
1084 IOService::updateConsoleUsers(NULL
, kIOMessageSystemHasPoweredOn
);
1085 if (tasksSuspended
) {
1086 tasksSuspended
= FALSE
;
1087 updateTasksSuspend();
1092 IOPMrootDomain::updateTasksSuspend(void)
1096 newSuspend
= (tasksSuspended
|| _aotTasksSuspended
);
1097 if (newSuspend
== tasksSuspendState
) {
1100 tasksSuspendState
= newSuspend
;
1101 tasks_system_suspend(newSuspend
);
1104 //******************************************************************************
1107 disk_sync_callout( thread_call_param_t p0
, thread_call_param_t p1
)
1109 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
1110 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
1111 uint32_t powerState
= rootDomain
->getPowerState();
1113 DLOG("disk_sync_callout ps=%u\n", powerState
);
1115 if (ON_STATE
== powerState
) {
1119 // Block sleep until trim issued on previous wake path is completed.
1120 IOHibernateSystemPostWake(true);
1125 IOHibernateSystemPostWake(false);
1127 rootDomain
->sleepWakeDebugSaveSpinDumpFile();
1131 rootDomain
->allowPowerChange(notifyRef
);
1132 DLOG("disk_sync_callout finish\n");
1135 //******************************************************************************
1137 computeDeltaTimeMS( const AbsoluteTime
* startTime
, AbsoluteTime
* elapsedTime
)
1139 AbsoluteTime endTime
;
1142 clock_get_uptime(&endTime
);
1143 if (CMP_ABSOLUTETIME(&endTime
, startTime
) <= 0) {
1146 SUB_ABSOLUTETIME(&endTime
, startTime
);
1147 absolutetime_to_nanoseconds(endTime
, &nano
);
1148 *elapsedTime
= endTime
;
1151 return (UInt32
)(nano
/ NSEC_PER_MSEC
);
1154 //******************************************************************************
1157 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
1159 struct timeval
*swt
= (struct timeval
*)arg1
;
1160 struct proc
*p
= req
->p
;
1162 if (p
== kernproc
) {
1163 return sysctl_io_opaque(req
, swt
, sizeof(*swt
), NULL
);
1164 } else if (proc_is64bit(p
)) {
1165 struct user64_timeval t
= {};
1166 t
.tv_sec
= swt
->tv_sec
;
1167 t
.tv_usec
= swt
->tv_usec
;
1168 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
1170 struct user32_timeval t
= {};
1171 t
.tv_sec
= (typeof(t
.tv_sec
))swt
->tv_sec
;
1172 t
.tv_usec
= swt
->tv_usec
;
1173 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
1177 static SYSCTL_PROC(_kern
, OID_AUTO
, sleeptime
,
1178 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1179 &gIOLastUserSleepTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
1181 static SYSCTL_PROC(_kern
, OID_AUTO
, waketime
,
1182 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1183 &gIOLastWakeTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
1185 SYSCTL_QUAD(_kern
, OID_AUTO
, wake_abs_time
, CTLFLAG_RD
| CTLFLAG_LOCKED
, &gIOLastWakeAbsTime
, "");
1186 SYSCTL_QUAD(_kern
, OID_AUTO
, sleep_abs_time
, CTLFLAG_RD
| CTLFLAG_LOCKED
, &gIOLastSleepAbsTime
, "");
1187 SYSCTL_QUAD(_kern
, OID_AUTO
, useractive_abs_time
, CTLFLAG_RD
| CTLFLAG_LOCKED
, &gUserActiveAbsTime
, "");
1188 SYSCTL_QUAD(_kern
, OID_AUTO
, userinactive_abs_time
, CTLFLAG_RD
| CTLFLAG_LOCKED
, &gUserInactiveAbsTime
, "");
1192 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
1194 int new_value
, changed
;
1195 int error
= sysctl_io_number(req
, gWillShutdown
, sizeof(int), &new_value
, &changed
);
1197 if (!gWillShutdown
&& (new_value
== 1)) {
1198 IOPMRootDomainWillShutdown();
1206 static SYSCTL_PROC(_kern
, OID_AUTO
, willshutdown
,
1207 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1208 NULL
, 0, sysctl_willshutdown
, "I", "");
1210 extern struct sysctl_oid sysctl__kern_iokittest
;
1211 extern struct sysctl_oid sysctl__debug_iokit
;
1213 #if defined(XNU_TARGET_OS_OSX)
1216 sysctl_progressmeterenable
1217 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
1220 int new_value
, changed
;
1222 error
= sysctl_io_number(req
, vc_progressmeter_enable
, sizeof(int), &new_value
, &changed
);
1225 vc_enable_progressmeter(new_value
);
1232 sysctl_progressmeter
1233 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
1236 int new_value
, changed
;
1238 error
= sysctl_io_number(req
, vc_progressmeter_value
, sizeof(int), &new_value
, &changed
);
1241 vc_set_progressmeter(new_value
);
1247 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeterenable
,
1248 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1249 NULL
, 0, sysctl_progressmeterenable
, "I", "");
1251 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeter
,
1252 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1253 NULL
, 0, sysctl_progressmeter
, "I", "");
1255 #endif /* defined(XNU_TARGET_OS_OSX) */
1260 sysctl_consoleoptions
1261 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
1266 error
= sysctl_io_number(req
, vc_user_options
.options
, sizeof(uint32_t), &new_value
, &changed
);
1269 vc_user_options
.options
= new_value
;
1275 static SYSCTL_PROC(_kern
, OID_AUTO
, consoleoptions
,
1276 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1277 NULL
, 0, sysctl_consoleoptions
, "I", "");
1281 sysctl_progressoptions SYSCTL_HANDLER_ARGS
1283 return sysctl_io_opaque(req
, &vc_user_options
, sizeof(vc_user_options
), NULL
);
1286 static SYSCTL_PROC(_kern
, OID_AUTO
, progressoptions
,
1287 CTLTYPE_STRUCT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
| CTLFLAG_ANYBODY
,
1288 NULL
, 0, sysctl_progressoptions
, "S,vc_progress_user_options", "");
1292 sysctl_wakereason SYSCTL_HANDLER_ARGS
1294 char wr
[sizeof(gWakeReasonString
)];
1298 gRootDomain
->copyWakeReasonString(wr
, sizeof(wr
));
1301 return sysctl_io_string(req
, wr
, 0, 0, NULL
);
1304 SYSCTL_PROC(_kern
, OID_AUTO
, wakereason
,
1305 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1306 NULL
, 0, sysctl_wakereason
, "A", "wakereason");
1308 SYSCTL_STRING(_kern
, OID_AUTO
, bootreason
,
1309 CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1310 gBootReasonString
, sizeof(gBootReasonString
), "");
1313 sysctl_shutdownreason SYSCTL_HANDLER_ARGS
1315 char sr
[sizeof(gShutdownReasonString
)];
1319 gRootDomain
->copyShutdownReasonString(sr
, sizeof(sr
));
1322 return sysctl_io_string(req
, sr
, 0, 0, NULL
);
1325 SYSCTL_PROC(_kern
, OID_AUTO
, shutdownreason
,
1326 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1327 NULL
, 0, sysctl_shutdownreason
, "A", "shutdownreason");
1330 sysctl_targettype SYSCTL_HANDLER_ARGS
1333 OSSharedPtr
<OSObject
> obj
;
1338 root
= IOService::getServiceRoot();
1339 if (root
&& (obj
= root
->copyProperty(gIODTTargetTypeKey
))) {
1340 if ((data
= OSDynamicCast(OSData
, obj
.get()))) {
1341 strlcpy(tt
, (const char *) data
->getBytesNoCopy(), sizeof(tt
));
1344 return sysctl_io_string(req
, tt
, 0, 0, NULL
);
1347 SYSCTL_PROC(_hw
, OID_AUTO
, targettype
,
1348 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1349 NULL
, 0, sysctl_targettype
, "A", "targettype");
1351 static SYSCTL_INT(_debug
, OID_AUTO
, noidle
, CTLFLAG_RW
, &gNoIdleFlag
, 0, "");
1352 static SYSCTL_INT(_debug
, OID_AUTO
, swd_sleep_timeout
, CTLFLAG_RW
, &gSwdSleepTimeout
, 0, "");
1353 static SYSCTL_INT(_debug
, OID_AUTO
, swd_wake_timeout
, CTLFLAG_RW
, &gSwdWakeTimeout
, 0, "");
1354 static SYSCTL_INT(_debug
, OID_AUTO
, swd_timeout
, CTLFLAG_RW
, &gSwdSleepWakeTimeout
, 0, "");
1355 static SYSCTL_INT(_debug
, OID_AUTO
, swd_panic
, CTLFLAG_RW
, &gSwdPanic
, 0, "");
1356 #if DEVELOPMENT || DEBUG
1357 static SYSCTL_INT(_debug
, OID_AUTO
, swd_panic_phase
, CTLFLAG_RW
, &swd_panic_phase
, 0, "");
1358 #if defined(XNU_TARGET_OS_OSX)
1359 static SYSCTL_INT(_debug
, OID_AUTO
, clamshell
, CTLFLAG_RW
, &gClamshellFlags
, 0, "");
1360 static SYSCTL_INT(_debug
, OID_AUTO
, darkwake
, CTLFLAG_RW
, &gDarkWakeFlags
, 0, "");
1361 #endif /* defined(XNU_TARGET_OS_OSX) */
1362 #endif /* DEVELOPMENT || DEBUG */
1364 //******************************************************************************
1368 sysctl_aotmetrics SYSCTL_HANDLER_ARGS
1370 if (NULL
== gRootDomain
) {
1373 if (NULL
== gRootDomain
->_aotMetrics
) {
1376 return sysctl_io_opaque(req
, gRootDomain
->_aotMetrics
, sizeof(IOPMAOTMetrics
), NULL
);
1379 static SYSCTL_PROC(_kern
, OID_AUTO
, aotmetrics
,
1380 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
| CTLFLAG_ANYBODY
,
1381 NULL
, 0, sysctl_aotmetrics
, "S,IOPMAOTMetrics", "");
1385 update_aotmode(uint32_t mode
)
1389 if (!gIOPMWorkLoop
) {
1392 result
= gIOPMWorkLoop
->runActionBlock(^IOReturn (void) {
1393 unsigned int oldCount
;
1395 if (mode
&& !gRootDomain
->_aotMetrics
) {
1396 gRootDomain
->_aotMetrics
= IONewZero(IOPMAOTMetrics
, 1);
1397 if (!gRootDomain
->_aotMetrics
) {
1402 oldCount
= gRootDomain
->idleSleepPreventersCount();
1403 gRootDomain
->_aotMode
= (mode
& kIOPMAOTModeMask
);
1404 gRootDomain
->updatePreventIdleSleepListInternal(NULL
, false, oldCount
);
1412 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
1417 if (NULL
== gRootDomain
) {
1420 error
= sysctl_io_number(req
, gRootDomain
->_aotMode
, sizeof(uint32_t), &new_value
, &changed
);
1421 if (changed
&& gIOPMWorkLoop
) {
1422 error
= update_aotmode(new_value
);
1428 static SYSCTL_PROC(_kern
, OID_AUTO
, aotmodebits
,
1429 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1430 NULL
, 0, sysctl_aotmodebits
, "I", "");
1434 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
1439 if (NULL
== gRootDomain
) {
1442 error
= sysctl_io_number(req
, gRootDomain
->_aotMode
, sizeof(uint32_t), &new_value
, &changed
);
1443 if (changed
&& gIOPMWorkLoop
) {
1445 new_value
= kIOPMAOTModeDefault
; // & ~kIOPMAOTModeRespectTimers;
1447 error
= update_aotmode(new_value
);
1453 static SYSCTL_PROC(_kern
, OID_AUTO
, aotmode
,
1454 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
| CTLFLAG_ANYBODY
,
1455 NULL
, 0, sysctl_aotmode
, "I", "");
1457 //******************************************************************************
1459 static OSSharedPtr
<const OSSymbol
> gIOPMSettingAutoWakeCalendarKey
;
1460 static OSSharedPtr
<const OSSymbol
> gIOPMSettingAutoWakeSecondsKey
;
1461 static OSSharedPtr
<const OSSymbol
> gIOPMSettingAutoPowerCalendarKey
;
1462 static OSSharedPtr
<const OSSymbol
> gIOPMSettingAutoPowerSecondsKey
;
1463 static OSSharedPtr
<const OSSymbol
> gIOPMSettingDebugWakeRelativeKey
;
1464 static OSSharedPtr
<const OSSymbol
> gIOPMSettingDebugPowerRelativeKey
;
1465 static OSSharedPtr
<const OSSymbol
> gIOPMSettingMaintenanceWakeCalendarKey
;
1466 static OSSharedPtr
<const OSSymbol
> gIOPMSettingSleepServiceWakeCalendarKey
;
1467 static OSSharedPtr
<const OSSymbol
> gIOPMSettingSilentRunningKey
;
1468 static OSSharedPtr
<const OSSymbol
> gIOPMUserTriggeredFullWakeKey
;
1469 static OSSharedPtr
<const OSSymbol
> gIOPMUserIsActiveKey
;
1470 static OSSharedPtr
<const OSSymbol
> gIOPMSettingLowLatencyAudioModeKey
;
1472 //******************************************************************************
1475 //******************************************************************************
1477 #define kRootDomainSettingsCount 20
1478 #define kRootDomainNoPublishSettingsCount 4
1481 IOPMrootDomain::start( IOService
* nub
)
1483 OSSharedPtr
<OSIterator
> psIterator
;
1484 OSSharedPtr
<OSDictionary
> tmpDict
;
1489 gIOPMSettingAutoWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
);
1490 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
1491 gIOPMSettingAutoPowerCalendarKey
= OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
);
1492 gIOPMSettingAutoPowerSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
);
1493 gIOPMSettingDebugWakeRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
);
1494 gIOPMSettingDebugPowerRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
);
1495 gIOPMSettingMaintenanceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
1496 gIOPMSettingSleepServiceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey
);
1497 gIOPMSettingSilentRunningKey
= OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey
);
1498 gIOPMUserTriggeredFullWakeKey
= OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey
);
1499 gIOPMUserIsActiveKey
= OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey
);
1500 gIOPMSettingLowLatencyAudioModeKey
= OSSymbol::withCStringNoCopy(kIOPMSettingLowLatencyAudioModeKey
);
1502 gIOPMStatsResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
1503 gIOPMStatsResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
1504 gIOPMStatsResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
1505 gIOPMStatsResponsePrompt
= OSSymbol::withCString(kIOPMStatsResponsePrompt
);
1506 gIOPMStatsDriverPSChangeSlow
= OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow
);
1508 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
1509 sleepMessagePEFunction
= OSSymbol::withCString("IOPMSystemSleepMessage");
1510 gIOPMWakeTypeUserKey
= OSSymbol::withCStringNoCopy(kIOPMRootDomainWakeTypeUser
);
1512 OSSharedPtr
<const OSSymbol
> settingsArr
[kRootDomainSettingsCount
] =
1514 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
1515 gIOPMSettingAutoWakeSecondsKey
,
1516 gIOPMSettingAutoPowerSecondsKey
,
1517 gIOPMSettingAutoWakeCalendarKey
,
1518 gIOPMSettingAutoPowerCalendarKey
,
1519 gIOPMSettingDebugWakeRelativeKey
,
1520 gIOPMSettingDebugPowerRelativeKey
,
1521 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
1522 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
1523 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
1524 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
1525 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
1526 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
1527 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
1528 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
1529 OSSymbol::withCString(kIOPMStateConsoleShutdown
),
1530 OSSymbol::withCString(kIOPMSettingProModeControl
),
1531 OSSymbol::withCString(kIOPMSettingProModeDefer
),
1532 gIOPMSettingSilentRunningKey
,
1533 gIOPMSettingLowLatencyAudioModeKey
,
1536 OSSharedPtr
<const OSSymbol
> noPublishSettingsArr
[kRootDomainNoPublishSettingsCount
] =
1538 OSSymbol::withCString(kIOPMSettingProModeControl
),
1539 OSSymbol::withCString(kIOPMSettingProModeDefer
),
1540 gIOPMSettingSilentRunningKey
,
1541 gIOPMSettingLowLatencyAudioModeKey
,
1544 #if DEVELOPMENT || DEBUG
1545 #if defined(XNU_TARGET_OS_OSX)
1546 PE_parse_boot_argn("darkwake", &gDarkWakeFlags
, sizeof(gDarkWakeFlags
));
1547 PE_parse_boot_argn("clamshell", &gClamshellFlags
, sizeof(gClamshellFlags
));
1548 #endif /* defined(XNU_TARGET_OS_OSX) */
1549 #endif /* DEVELOPMENT || DEBUG */
1551 PE_parse_boot_argn("noidle", &gNoIdleFlag
, sizeof(gNoIdleFlag
));
1552 PE_parse_boot_argn("swd_sleeptimeout", &gSwdSleepTimeout
, sizeof(gSwdSleepTimeout
));
1553 PE_parse_boot_argn("swd_waketimeout", &gSwdWakeTimeout
, sizeof(gSwdWakeTimeout
));
1554 PE_parse_boot_argn("swd_timeout", &gSwdSleepWakeTimeout
, sizeof(gSwdSleepWakeTimeout
));
1555 PE_parse_boot_argn("haltmspanic", &gHaltTimeMaxPanic
, sizeof(gHaltTimeMaxPanic
));
1556 PE_parse_boot_argn("haltmslog", &gHaltTimeMaxLog
, sizeof(gHaltTimeMaxLog
));
1558 queue_init(&aggressivesQueue
);
1559 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
1560 aggressivesData
= OSData::withCapacity(
1561 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
1563 featuresDictLock
= IOLockAlloc();
1564 settingsCtrlLock
= IOLockAlloc();
1565 wakeEventLock
= IOLockAlloc();
1566 gHaltLogLock
= IOLockAlloc();
1567 setPMRootDomain(this);
1569 extraSleepTimer
= thread_call_allocate(
1570 idleSleepTimerExpired
,
1571 (thread_call_param_t
) this);
1573 powerButtonDown
= thread_call_allocate(
1574 powerButtonDownCallout
,
1575 (thread_call_param_t
) this);
1577 powerButtonUp
= thread_call_allocate(
1578 powerButtonUpCallout
,
1579 (thread_call_param_t
) this);
1581 diskSyncCalloutEntry
= thread_call_allocate(
1583 (thread_call_param_t
) this);
1584 updateConsoleUsersEntry
= thread_call_allocate(
1585 &updateConsoleUsersCallout
,
1586 (thread_call_param_t
) this);
1588 #if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
1589 fullWakeThreadCall
= thread_call_allocate_with_options(
1590 OSMemberFunctionCast(thread_call_func_t
, this,
1591 &IOPMrootDomain::fullWakeDelayedWork
),
1592 (thread_call_param_t
) this, THREAD_CALL_PRIORITY_KERNEL
,
1593 THREAD_CALL_OPTIONS_ONCE
);
1596 setProperty(kIOSleepSupportedKey
, true);
1598 bzero(&gPMStats
, sizeof(gPMStats
));
1600 pmTracer
= PMTraceWorker::tracer(this);
1602 pmAssertions
= PMAssertionsTracker::pmAssertionsTracker(this);
1604 userDisabledAllSleep
= false;
1605 systemBooting
= true;
1606 idleSleepEnabled
= false;
1608 idleSleepTimerPending
= false;
1610 clamshellClosed
= false;
1611 clamshellExists
= false;
1612 #if DISPLAY_WRANGLER_PRESENT
1613 clamshellDisabled
= true;
1615 clamshellDisabled
= false;
1617 clamshellIgnoreClose
= false;
1618 acAdaptorConnected
= true;
1619 clamshellSleepDisableMask
= 0;
1620 gWakeReasonString
[0] = '\0';
1622 // Initialize to user active.
1623 // Will never transition to user inactive w/o wrangler.
1624 fullWakeReason
= kFullWakeReasonLocalUser
;
1625 userIsActive
= userWasActive
= true;
1626 clock_get_uptime(&gUserActiveAbsTime
);
1627 setProperty(gIOPMUserIsActiveKey
.get(), kOSBooleanTrue
);
1629 // Set the default system capabilities at boot.
1630 _currentCapability
= kIOPMSystemCapabilityCPU
|
1631 kIOPMSystemCapabilityGraphics
|
1632 kIOPMSystemCapabilityAudio
|
1633 kIOPMSystemCapabilityNetwork
;
1635 _pendingCapability
= _currentCapability
;
1636 _desiredCapability
= _currentCapability
;
1637 _highestCapability
= _currentCapability
;
1638 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
1640 queuedSleepWakeUUIDString
= NULL
;
1641 initializeBootSessionUUID();
1642 pmStatsAppResponses
= OSArray::withCapacity(5);
1643 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
1644 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
1645 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
1646 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
1647 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
1648 _statsPowerCapsKey
= OSSymbol::withCString(kIOPMStatsPowerCapabilityKey
);
1649 assertOnWakeSecs
= -1;// Invalid value to prevent updates
1651 pmStatsLock
= IOLockAlloc();
1652 idxPMCPUClamshell
= kCPUUnknownIndex
;
1653 idxPMCPULimitedPower
= kCPUUnknownIndex
;
1655 tmpDict
= OSDictionary::withCapacity(1);
1656 setProperty(kRootDomainSupportedFeatures
, tmpDict
.get());
1658 // Set a default "SystemPowerProfileOverrideDict" for platform
1659 // drivers without any overrides.
1660 if (!propertyExists(kIOPMSystemDefaultOverrideKey
)) {
1661 tmpDict
= OSDictionary::withCapacity(1);
1662 setProperty(kIOPMSystemDefaultOverrideKey
, tmpDict
.get());
1665 settingsCallbacks
= OSDictionary::withCapacity(1);
1667 // Create a list of the valid PM settings that we'll relay to
1668 // interested clients in setProperties() => setPMSetting()
1669 allowedPMSettings
= OSArray::withObjects(
1670 (const OSObject
**)settingsArr
,
1671 kRootDomainSettingsCount
,
1674 // List of PM settings that should not automatically publish itself
1675 // as a feature when registered by a listener.
1676 noPublishPMSettings
= OSArray::withObjects(
1677 (const OSObject
**)noPublishSettingsArr
,
1678 kRootDomainNoPublishSettingsCount
,
1681 fPMSettingsDict
= OSDictionary::withCapacity(5);
1682 preventIdleSleepList
= OSSet::withCapacity(8);
1683 preventSystemSleepList
= OSSet::withCapacity(2);
1685 PMinit(); // creates gIOPMWorkLoop
1686 gIOPMWorkLoop
= getIOPMWorkloop();
1688 // Create IOPMPowerStateQueue used to queue external power
1689 // events, and to handle those events on the PM work loop.
1690 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
1691 this, OSMemberFunctionCast(IOEventSource::Action
, this,
1692 &IOPMrootDomain::dispatchPowerEvent
));
1693 gIOPMWorkLoop
->addEventSource(pmPowerStateQueue
);
1696 _aotTimerES
= IOTimerEventSource::timerEventSource(this,
1697 OSMemberFunctionCast(IOTimerEventSource::Action
,
1698 this, &IOPMrootDomain::aotEvaluate
));
1699 gIOPMWorkLoop
->addEventSource(_aotTimerES
.get());
1701 // create our power parent
1702 gPatriarch
= new IORootParent
;
1704 gPatriarch
->attach(this);
1705 gPatriarch
->start(this);
1706 gPatriarch
->addPowerChild(this);
1708 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
1709 changePowerStateWithTagToPriv(ON_STATE
, kCPSReasonInit
);
1711 // install power change handler
1712 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, NULL
);
1714 #if DISPLAY_WRANGLER_PRESENT
1715 wranglerIdleSettings
= OSDictionary::withCapacity(1);
1716 OSSharedPtr
<OSNumber
> wranglerIdlePeriod
= OSNumber::withNumber(kDefaultWranglerIdlePeriod
, 32);
1718 if (wranglerIdleSettings
&& wranglerIdlePeriod
) {
1719 wranglerIdleSettings
->setObject(kIORequestWranglerIdleKey
,
1720 wranglerIdlePeriod
.get());
1723 #endif /* DISPLAY_WRANGLER_PRESENT */
1725 lowLatencyAudioNotifierDict
= OSDictionary::withCapacity(2);
1726 lowLatencyAudioNotifyStateSym
= OSSymbol::withCString("LowLatencyAudioNotifyState");
1727 lowLatencyAudioNotifyTimestampSym
= OSSymbol::withCString("LowLatencyAudioNotifyTimestamp");
1728 lowLatencyAudioNotifyStateVal
= OSNumber::withNumber(0ull, 32);
1729 lowLatencyAudioNotifyTimestampVal
= OSNumber::withNumber(0ull, 64);
1731 if (lowLatencyAudioNotifierDict
&& lowLatencyAudioNotifyStateSym
&& lowLatencyAudioNotifyTimestampSym
&&
1732 lowLatencyAudioNotifyStateVal
&& lowLatencyAudioNotifyTimestampVal
) {
1733 lowLatencyAudioNotifierDict
->setObject(lowLatencyAudioNotifyStateSym
.get(), lowLatencyAudioNotifyStateVal
.get());
1734 lowLatencyAudioNotifierDict
->setObject(lowLatencyAudioNotifyTimestampSym
.get(), lowLatencyAudioNotifyTimestampVal
.get());
1737 OSSharedPtr
<const OSSymbol
> ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
1738 setProperty(gIOUserClientClassKey
, const_cast<OSObject
*>(static_cast<const OSObject
*>(ucClassName
.get())));
1740 // IOBacklightDisplay can take a long time to load at boot, or it may
1741 // not load at all if you're booting with clamshell closed. We publish
1742 // 'DisplayDims' here redundantly to get it published early and at all.
1743 OSSharedPtr
<OSDictionary
> matching
;
1744 matching
= serviceMatching("IOPMPowerSource");
1745 psIterator
= getMatchingServices(matching
.get());
1747 if (psIterator
&& psIterator
->getNextObject()) {
1748 // There's at least one battery on the system, so we publish
1749 // 'DisplayDims' support for the LCD.
1750 publishFeature("DisplayDims");
1753 // read swd_panic boot-arg
1754 PE_parse_boot_argn("swd_panic", &gSwdPanic
, sizeof(gSwdPanic
));
1755 sysctl_register_oid(&sysctl__kern_sleeptime
);
1756 sysctl_register_oid(&sysctl__kern_waketime
);
1757 sysctl_register_oid(&sysctl__kern_willshutdown
);
1758 sysctl_register_oid(&sysctl__kern_iokittest
);
1759 sysctl_register_oid(&sysctl__debug_iokit
);
1760 sysctl_register_oid(&sysctl__hw_targettype
);
1762 #if defined(XNU_TARGET_OS_OSX)
1763 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
1764 sysctl_register_oid(&sysctl__kern_progressmeter
);
1765 sysctl_register_oid(&sysctl__kern_wakereason
);
1766 #endif /* defined(XNU_TARGET_OS_OSX) */
1767 sysctl_register_oid(&sysctl__kern_consoleoptions
);
1768 sysctl_register_oid(&sysctl__kern_progressoptions
);
1770 sysctl_register_oid(&sysctl__kern_aotmode
);
1771 sysctl_register_oid(&sysctl__kern_aotmodebits
);
1772 sysctl_register_oid(&sysctl__kern_aotmetrics
);
1775 #if defined(__arm64__)
1776 if (ppl_hib_hibernation_supported()) {
1777 publishFeature(kIOHibernateFeatureKey
);
1779 #endif /* defined(__arm64__) */
1780 IOHibernateSystemInit(this);
1783 registerService(); // let clients find us
1788 //******************************************************************************
1791 // Receive a setProperty call
1792 // The "System Boot" property means the system is completely booted.
1793 //******************************************************************************
1796 IOPMrootDomain::setProperties( OSObject
* props_obj
)
1798 IOReturn return_value
= kIOReturnSuccess
;
1799 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
1800 OSBoolean
*b
= NULL
;
1802 const OSSymbol
*key
= NULL
;
1803 OSObject
*obj
= NULL
;
1804 OSSharedPtr
<OSCollectionIterator
> iter
;
1807 return kIOReturnBadArgument
;
1810 bool clientEntitled
= false;
1812 OSSharedPtr
<OSObject
> obj
= IOUserClient::copyClientEntitlement(current_task(), kRootDomainEntitlementSetProperty
);
1813 clientEntitled
= (obj
== kOSBooleanTrue
);
1816 if (!clientEntitled
) {
1817 const char * errorSuffix
= NULL
;
1819 // IOPMSchedulePowerEvent() clients may not be entitled, but must be root.
1820 // That API can set 6 possible keys that are checked below.
1821 if ((dict
->getCount() == 1) &&
1822 (dict
->getObject(gIOPMSettingAutoWakeSecondsKey
.get()) ||
1823 dict
->getObject(gIOPMSettingAutoPowerSecondsKey
.get()) ||
1824 dict
->getObject(gIOPMSettingAutoWakeCalendarKey
.get()) ||
1825 dict
->getObject(gIOPMSettingAutoPowerCalendarKey
.get()) ||
1826 dict
->getObject(gIOPMSettingDebugWakeRelativeKey
.get()) ||
1827 dict
->getObject(gIOPMSettingDebugPowerRelativeKey
.get()))) {
1828 return_value
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
1829 if (return_value
!= kIOReturnSuccess
) {
1830 errorSuffix
= "privileged";
1833 return_value
= kIOReturnNotPermitted
;
1834 errorSuffix
= "entitled";
1837 if (return_value
!= kIOReturnSuccess
) {
1838 OSSharedPtr
<OSString
> procName(IOCopyLogNameForPID(proc_selfpid()), OSNoRetain
);
1839 DLOG("%s failed, process %s is not %s\n", __func__
,
1840 procName
? procName
->getCStringNoCopy() : "", errorSuffix
);
1841 return return_value
;
1845 OSSharedPtr
<const OSSymbol
> publish_simulated_battery_string
= OSSymbol::withCString("SoftwareSimulatedBatteries");
1846 OSSharedPtr
<const OSSymbol
> boot_complete_string
= OSSymbol::withCString("System Boot Complete");
1847 OSSharedPtr
<const OSSymbol
> sys_shutdown_string
= OSSymbol::withCString("System Shutdown");
1848 OSSharedPtr
<const OSSymbol
> stall_halt_string
= OSSymbol::withCString("StallSystemAtHalt");
1849 OSSharedPtr
<const OSSymbol
> battery_warning_disabled_string
= OSSymbol::withCString("BatteryWarningsDisabled");
1850 OSSharedPtr
<const OSSymbol
> idle_seconds_string
= OSSymbol::withCString("System Idle Seconds");
1851 OSSharedPtr
<const OSSymbol
> sleepdisabled_string
= OSSymbol::withCString("SleepDisabled");
1852 OSSharedPtr
<const OSSymbol
> ondeck_sleepwake_uuid_string
= OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
1853 OSSharedPtr
<const OSSymbol
> loginwindow_progress_string
= OSSymbol::withCString(kIOPMLoginWindowProgressKey
);
1854 OSSharedPtr
<const OSSymbol
> coredisplay_progress_string
= OSSymbol::withCString(kIOPMCoreDisplayProgressKey
);
1855 OSSharedPtr
<const OSSymbol
> coregraphics_progress_string
= OSSymbol::withCString(kIOPMCoreGraphicsProgressKey
);
1856 #if DEBUG || DEVELOPMENT
1857 OSSharedPtr
<const OSSymbol
> clamshell_close_string
= OSSymbol::withCString("IOPMTestClamshellClose");
1858 OSSharedPtr
<const OSSymbol
> clamshell_open_string
= OSSymbol::withCString("IOPMTestClamshellOpen");
1859 OSSharedPtr
<const OSSymbol
> ac_detach_string
= OSSymbol::withCString("IOPMTestACDetach");
1860 OSSharedPtr
<const OSSymbol
> ac_attach_string
= OSSymbol::withCString("IOPMTestACAttach");
1861 OSSharedPtr
<const OSSymbol
> desktopmode_set_string
= OSSymbol::withCString("IOPMTestDesktopModeSet");
1862 OSSharedPtr
<const OSSymbol
> desktopmode_remove_string
= OSSymbol::withCString("IOPMTestDesktopModeRemove");
1866 OSSharedPtr
<const OSSymbol
> hibernatemode_string
= OSSymbol::withCString(kIOHibernateModeKey
);
1867 OSSharedPtr
<const OSSymbol
> hibernatefile_string
= OSSymbol::withCString(kIOHibernateFileKey
);
1868 OSSharedPtr
<const OSSymbol
> hibernatefilemin_string
= OSSymbol::withCString(kIOHibernateFileMinSizeKey
);
1869 OSSharedPtr
<const OSSymbol
> hibernatefilemax_string
= OSSymbol::withCString(kIOHibernateFileMaxSizeKey
);
1870 OSSharedPtr
<const OSSymbol
> hibernatefreeratio_string
= OSSymbol::withCString(kIOHibernateFreeRatioKey
);
1871 OSSharedPtr
<const OSSymbol
> hibernatefreetime_string
= OSSymbol::withCString(kIOHibernateFreeTimeKey
);
1874 iter
= OSCollectionIterator::withCollection(dict
);
1876 return_value
= kIOReturnNoMemory
;
1880 while ((key
= (const OSSymbol
*) iter
->getNextObject()) &&
1881 (obj
= dict
->getObject(key
))) {
1882 if (key
->isEqualTo(publish_simulated_battery_string
.get())) {
1883 if (OSDynamicCast(OSBoolean
, obj
)) {
1884 publishResource(key
, kOSBooleanTrue
);
1886 } else if (key
->isEqualTo(idle_seconds_string
.get())) {
1887 if ((n
= OSDynamicCast(OSNumber
, obj
))) {
1888 setProperty(key
, n
);
1889 idleSeconds
= n
->unsigned32BitValue();
1891 } else if (key
->isEqualTo(boot_complete_string
.get())) {
1892 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemBootCompleted
);
1893 } else if (key
->isEqualTo(sys_shutdown_string
.get())) {
1894 if ((b
= OSDynamicCast(OSBoolean
, obj
))) {
1895 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
1897 } else if (key
->isEqualTo(battery_warning_disabled_string
.get())) {
1898 setProperty(key
, obj
);
1901 else if (key
->isEqualTo(hibernatemode_string
.get()) ||
1902 key
->isEqualTo(hibernatefilemin_string
.get()) ||
1903 key
->isEqualTo(hibernatefilemax_string
.get()) ||
1904 key
->isEqualTo(hibernatefreeratio_string
.get()) ||
1905 key
->isEqualTo(hibernatefreetime_string
.get())) {
1906 if ((n
= OSDynamicCast(OSNumber
, obj
))) {
1907 setProperty(key
, n
);
1909 } else if (key
->isEqualTo(hibernatefile_string
.get())) {
1910 OSString
* str
= OSDynamicCast(OSString
, obj
);
1912 setProperty(key
, str
);
1916 else if (key
->isEqualTo(sleepdisabled_string
.get())) {
1917 if ((b
= OSDynamicCast(OSBoolean
, obj
))) {
1918 setProperty(key
, b
);
1919 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
1921 } else if (key
->isEqualTo(ondeck_sleepwake_uuid_string
.get())) {
1923 pmPowerStateQueue
->submitPowerEvent(kPowerEventQueueSleepWakeUUID
, (void *)obj
);
1924 } else if (key
->isEqualTo(loginwindow_progress_string
.get())) {
1925 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1926 uint32_t data
= n
->unsigned32BitValue();
1927 pmTracer
->traceComponentWakeProgress(kIOPMLoginWindowProgress
, data
);
1928 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMLoginWindowProgress
, data
);
1930 } else if (key
->isEqualTo(coredisplay_progress_string
.get())) {
1931 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1932 uint32_t data
= n
->unsigned32BitValue();
1933 pmTracer
->traceComponentWakeProgress(kIOPMCoreDisplayProgress
, data
);
1934 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMCoreDisplayProgress
, data
);
1936 } else if (key
->isEqualTo(coregraphics_progress_string
.get())) {
1937 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1938 uint32_t data
= n
->unsigned32BitValue();
1939 pmTracer
->traceComponentWakeProgress(kIOPMCoreGraphicsProgress
, data
);
1940 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMCoreGraphicsProgress
, data
);
1942 } else if (key
->isEqualTo(kIOPMDeepSleepEnabledKey
) ||
1943 key
->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey
) ||
1944 key
->isEqualTo(kIOPMAutoPowerOffEnabledKey
) ||
1945 key
->isEqualTo(stall_halt_string
.get())) {
1946 if ((b
= OSDynamicCast(OSBoolean
, obj
))) {
1947 setProperty(key
, b
);
1949 } else if (key
->isEqualTo(kIOPMDeepSleepDelayKey
) ||
1950 key
->isEqualTo(kIOPMDeepSleepTimerKey
) ||
1951 key
->isEqualTo(kIOPMAutoPowerOffDelayKey
) ||
1952 key
->isEqualTo(kIOPMAutoPowerOffTimerKey
)) {
1953 if ((n
= OSDynamicCast(OSNumber
, obj
))) {
1954 setProperty(key
, n
);
1956 } else if (key
->isEqualTo(kIOPMUserWakeAlarmScheduledKey
)) {
1957 if (kOSBooleanTrue
== obj
) {
1958 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_userScheduledAlarmMask
);
1960 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_userScheduledAlarmMask
);
1962 DLOG("_userScheduledAlarmMask 0x%x\n", (uint32_t) _userScheduledAlarmMask
);
1964 #if DEBUG || DEVELOPMENT
1965 else if (key
->isEqualTo(clamshell_close_string
.get())) {
1966 DLOG("SetProperties: setting clamshell close\n");
1967 UInt32 msg
= kIOPMClamshellClosed
;
1968 pmPowerStateQueue
->submitPowerEvent(kPowerEventReceivedPowerNotification
, (void *)(uintptr_t)msg
);
1969 } else if (key
->isEqualTo(clamshell_open_string
.get())) {
1970 DLOG("SetProperties: setting clamshell open\n");
1971 UInt32 msg
= kIOPMClamshellOpened
;
1972 pmPowerStateQueue
->submitPowerEvent(kPowerEventReceivedPowerNotification
, (void *)(uintptr_t)msg
);
1973 } else if (key
->isEqualTo(ac_detach_string
.get())) {
1974 DLOG("SetProperties: setting ac detach\n");
1975 UInt32 msg
= kIOPMSetACAdaptorConnected
;
1976 pmPowerStateQueue
->submitPowerEvent(kPowerEventReceivedPowerNotification
, (void *)(uintptr_t)msg
);
1977 } else if (key
->isEqualTo(ac_attach_string
.get())) {
1978 DLOG("SetProperties: setting ac attach\n");
1979 UInt32 msg
= kIOPMSetACAdaptorConnected
| kIOPMSetValue
;
1980 pmPowerStateQueue
->submitPowerEvent(kPowerEventReceivedPowerNotification
, (void *)(uintptr_t)msg
);
1981 } else if (key
->isEqualTo(desktopmode_set_string
.get())) {
1982 DLOG("SetProperties: setting desktopmode");
1983 UInt32 msg
= kIOPMSetDesktopMode
| kIOPMSetValue
;
1984 pmPowerStateQueue
->submitPowerEvent(kPowerEventReceivedPowerNotification
, (void *)(uintptr_t)msg
);
1985 } else if (key
->isEqualTo(desktopmode_remove_string
.get())) {
1986 DLOG("SetProperties: removing desktopmode\n");
1987 UInt32 msg
= kIOPMSetDesktopMode
;
1988 pmPowerStateQueue
->submitPowerEvent(kPowerEventReceivedPowerNotification
, (void *)(uintptr_t)msg
);
1991 // Relay our allowed PM settings onto our registered PM clients
1992 else if ((allowedPMSettings
->getNextIndexOfObject(key
, 0) != (unsigned int) -1)) {
1993 return_value
= setPMSetting(key
, obj
);
1994 if (kIOReturnSuccess
!= return_value
) {
1998 DLOG("setProperties(%s) not handled\n", key
->getCStringNoCopy());
2003 return return_value
;
2007 // MARK: Aggressiveness
2009 //******************************************************************************
2010 // setAggressiveness
2012 // Override IOService::setAggressiveness()
2013 //******************************************************************************
2016 IOPMrootDomain::setAggressiveness(
2018 unsigned long value
)
2020 return setAggressiveness( type
, value
, 0 );
2024 * Private setAggressiveness() with an internal options argument.
2027 IOPMrootDomain::setAggressiveness(
2029 unsigned long value
,
2030 IOOptionBits options
)
2032 AggressivesRequest
* entry
;
2033 AggressivesRequest
* request
;
2036 if ((type
> UINT_MAX
) || (value
> UINT_MAX
)) {
2037 return kIOReturnBadArgument
;
2040 if (type
== kPMMinutesToDim
|| type
== kPMMinutesToSleep
) {
2041 DLOG("setAggressiveness(%x) %s = %u\n",
2042 (uint32_t) options
, getAggressivenessTypeString((uint32_t) type
), (uint32_t) value
);
2044 DEBUG_LOG("setAggressiveness(%x) %s = %u\n",
2045 (uint32_t) options
, getAggressivenessTypeString((uint32_t) type
), (uint32_t) value
);
2048 request
= IONew(AggressivesRequest
, 1);
2050 return kIOReturnNoMemory
;
2053 memset(request
, 0, sizeof(*request
));
2054 request
->options
= options
;
2055 request
->dataType
= kAggressivesRequestTypeRecord
;
2056 request
->data
.record
.type
= (uint32_t) type
;
2057 request
->data
.record
.value
= (uint32_t) value
;
2061 // Update disk quick spindown flag used by getAggressiveness().
2062 // Never merge requests with quick spindown flags set.
2064 if (options
& kAggressivesOptionQuickSpindownEnable
) {
2065 gAggressivesState
|= kAggressivesStateQuickSpindown
;
2066 } else if (options
& kAggressivesOptionQuickSpindownDisable
) {
2067 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
2069 // Coalesce requests with identical aggressives types.
2070 // Deal with callers that calls us too "aggressively".
2072 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
2074 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
2075 (entry
->data
.record
.type
== type
) &&
2076 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0)) {
2077 entry
->data
.record
.value
= (uint32_t) value
;
2085 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
2088 AGGRESSIVES_UNLOCK();
2091 IODelete(request
, AggressivesRequest
, 1);
2094 if (options
& kAggressivesOptionSynchronous
) {
2095 handleAggressivesRequests(); // not truly synchronous
2097 thread_call_enter(aggressivesThreadCall
);
2100 return kIOReturnSuccess
;
2103 //******************************************************************************
2104 // getAggressiveness
2106 // Override IOService::setAggressiveness()
2107 // Fetch the aggressiveness factor with the given type.
2108 //******************************************************************************
2111 IOPMrootDomain::getAggressiveness(
2113 unsigned long * outLevel
)
2118 if (!outLevel
|| (type
> UINT_MAX
)) {
2119 return kIOReturnBadArgument
;
2124 // Disk quick spindown in effect, report value = 1
2126 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
2127 (type
== kPMMinutesToSpinDown
)) {
2128 value
= kAggressivesMinValue
;
2132 // Consult the pending request queue.
2135 AggressivesRequest
* entry
;
2137 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
2139 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
2140 (entry
->data
.record
.type
== type
) &&
2141 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0)) {
2142 value
= entry
->data
.record
.value
;
2149 // Consult the backend records.
2151 if (!source
&& aggressivesData
) {
2152 AggressivesRecord
* record
;
2155 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
2156 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
2158 for (i
= 0; i
< count
; i
++, record
++) {
2159 if (record
->type
== type
) {
2160 value
= record
->value
;
2167 AGGRESSIVES_UNLOCK();
2170 *outLevel
= (unsigned long) value
;
2171 return kIOReturnSuccess
;
2173 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
2174 *outLevel
= 0; // default return = 0, driver may not check for error
2175 return kIOReturnInvalid
;
2179 //******************************************************************************
2180 // joinAggressiveness
2182 // Request from IOService to join future aggressiveness broadcasts.
2183 //******************************************************************************
2186 IOPMrootDomain::joinAggressiveness(
2187 IOService
* service
)
2189 AggressivesRequest
* request
;
2191 if (!service
|| (service
== this)) {
2192 return kIOReturnBadArgument
;
2195 DEBUG_LOG("joinAggressiveness %s %p\n", service
->getName(), OBFUSCATE(service
));
2197 request
= IONew(AggressivesRequest
, 1);
2199 return kIOReturnNoMemory
;
2202 memset(request
, 0, sizeof(*request
));
2203 request
->dataType
= kAggressivesRequestTypeService
;
2204 request
->data
.service
.reset(service
, OSRetain
); // released by synchronizeAggressives()
2207 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
2208 AGGRESSIVES_UNLOCK();
2210 thread_call_enter(aggressivesThreadCall
);
2212 return kIOReturnSuccess
;
2215 //******************************************************************************
2216 // handleAggressivesRequests
2218 // Backend thread processes all incoming aggressiveness requests in the queue.
2219 //******************************************************************************
2222 handleAggressivesFunction(
2223 thread_call_param_t param1
,
2224 thread_call_param_t param2
)
2227 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
2232 IOPMrootDomain::handleAggressivesRequests( void )
2234 AggressivesRecord
* start
;
2235 AggressivesRecord
* record
;
2236 AggressivesRequest
* request
;
2237 queue_head_t joinedQueue
;
2241 bool pingSelf
= false;
2245 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
2246 queue_empty(&aggressivesQueue
)) {
2250 gAggressivesState
|= kAggressivesStateBusy
;
2251 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
2252 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
2256 queue_init(&joinedQueue
);
2259 // Remove request from the incoming queue in FIFO order.
2260 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
2261 switch (request
->dataType
) {
2262 case kAggressivesRequestTypeRecord
:
2263 // Update existing record if found.
2265 for (i
= 0, record
= start
; i
< count
; i
++, record
++) {
2266 if (record
->type
== request
->data
.record
.type
) {
2269 if (request
->options
& kAggressivesOptionQuickSpindownEnable
) {
2270 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0) {
2272 record
->flags
|= (kAggressivesRecordFlagMinValue
|
2273 kAggressivesRecordFlagModified
);
2274 DLOG("disk spindown accelerated, was %u min\n",
2277 } else if (request
->options
& kAggressivesOptionQuickSpindownDisable
) {
2278 if (record
->flags
& kAggressivesRecordFlagMinValue
) {
2280 record
->flags
|= kAggressivesRecordFlagModified
;
2281 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
2282 DLOG("disk spindown restored to %u min\n",
2285 } else if (record
->value
!= request
->data
.record
.value
) {
2286 record
->value
= request
->data
.record
.value
;
2287 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0) {
2289 record
->flags
|= kAggressivesRecordFlagModified
;
2296 // No matching record, append a new record.
2298 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0)) {
2299 AggressivesRecord newRecord
;
2301 newRecord
.flags
= kAggressivesRecordFlagModified
;
2302 newRecord
.type
= request
->data
.record
.type
;
2303 newRecord
.value
= request
->data
.record
.value
;
2304 if (request
->options
& kAggressivesOptionQuickSpindownEnable
) {
2305 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
2306 DLOG("disk spindown accelerated\n");
2309 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
2311 // OSData may have switched to another (larger) buffer.
2312 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
2313 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
2317 // Finished processing the request, release it.
2318 IODelete(request
, AggressivesRequest
, 1);
2321 case kAggressivesRequestTypeService
:
2322 // synchronizeAggressives() will free request.
2323 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
2327 panic("bad aggressives request type %x\n", request
->dataType
);
2330 } while (!queue_empty(&aggressivesQueue
));
2332 // Release the lock to perform work, with busy flag set.
2333 if (!queue_empty(&joinedQueue
) || broadcast
) {
2334 AGGRESSIVES_UNLOCK();
2335 if (!queue_empty(&joinedQueue
)) {
2336 synchronizeAggressives(&joinedQueue
, start
, count
);
2339 broadcastAggressives(start
, count
);
2344 // Remove the modified flag from all records.
2345 for (i
= 0, record
= start
; i
< count
; i
++, record
++) {
2346 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
2347 ((record
->type
== kPMMinutesToDim
) ||
2348 (record
->type
== kPMMinutesToSleep
))) {
2352 record
->flags
&= ~kAggressivesRecordFlagModified
;
2355 // Check the incoming queue again since new entries may have been
2356 // added while lock was released above.
2357 } while (!queue_empty(&aggressivesQueue
));
2359 gAggressivesState
&= ~kAggressivesStateBusy
;
2362 AGGRESSIVES_UNLOCK();
2364 // Root domain is interested in system and display sleep slider changes.
2365 // Submit a power event to handle those changes on the PM work loop.
2367 if (pingSelf
&& pmPowerStateQueue
) {
2368 pmPowerStateQueue
->submitPowerEvent(
2369 kPowerEventPolicyStimulus
,
2370 (void *) kStimulusAggressivenessChanged
);
2374 //******************************************************************************
2375 // synchronizeAggressives
2377 // Push all known aggressiveness records to one or more IOService.
2378 //******************************************************************************
2381 IOPMrootDomain::synchronizeAggressives(
2382 queue_head_t
* joinedQueue
,
2383 const AggressivesRecord
* array
,
2386 OSSharedPtr
<IOService
> service
;
2387 AggressivesRequest
* request
;
2388 const AggressivesRecord
* record
;
2389 IOPMDriverCallEntry callEntry
;
2393 while (!queue_empty(joinedQueue
)) {
2394 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
2395 if (request
->dataType
== kAggressivesRequestTypeService
) {
2396 // retained by joinAggressiveness(), so take ownership
2397 service
= os::move(request
->data
.service
);
2402 IODelete(request
, AggressivesRequest
, 1);
2406 if (service
->assertPMDriverCall(&callEntry
, kIOPMDriverCallMethodSetAggressive
)) {
2407 for (i
= 0, record
= array
; i
< count
; i
++, record
++) {
2408 value
= record
->value
;
2409 if (record
->flags
& kAggressivesRecordFlagMinValue
) {
2410 value
= kAggressivesMinValue
;
2413 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
2414 record
->type
, value
, service
->getName());
2415 service
->setAggressiveness(record
->type
, value
);
2417 service
->deassertPMDriverCall(&callEntry
);
2423 //******************************************************************************
2424 // broadcastAggressives
2426 // Traverse PM tree and call setAggressiveness() for records that have changed.
2427 //******************************************************************************
2430 IOPMrootDomain::broadcastAggressives(
2431 const AggressivesRecord
* array
,
2434 OSSharedPtr
<IORegistryIterator
> iter
;
2435 IORegistryEntry
*entry
;
2436 OSSharedPtr
<IORegistryEntry
> child
;
2437 IOPowerConnection
*connect
;
2439 const AggressivesRecord
*record
;
2440 IOPMDriverCallEntry callEntry
;
2444 iter
= IORegistryIterator::iterateOver(
2445 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
2448 // !! reset the iterator
2450 while ((entry
= iter
->getNextObject())) {
2451 connect
= OSDynamicCast(IOPowerConnection
, entry
);
2452 if (!connect
|| !connect
->getReadyFlag()) {
2456 child
= connect
->copyChildEntry(gIOPowerPlane
);
2458 if ((service
= OSDynamicCast(IOService
, child
.get()))) {
2459 if (service
->assertPMDriverCall(&callEntry
, kIOPMDriverCallMethodSetAggressive
)) {
2460 for (i
= 0, record
= array
; i
< count
; i
++, record
++) {
2461 if (record
->flags
& kAggressivesRecordFlagModified
) {
2462 value
= record
->value
;
2463 if (record
->flags
& kAggressivesRecordFlagMinValue
) {
2464 value
= kAggressivesMinValue
;
2466 _LOG("broadcastAggressives %x = %u to %s\n",
2467 record
->type
, value
, service
->getName());
2468 service
->setAggressiveness(record
->type
, value
);
2471 service
->deassertPMDriverCall(&callEntry
);
2476 }while (!entry
&& !iter
->isValid());
2480 //*****************************************
2481 // stackshot on power button press
2482 // ***************************************
2484 powerButtonDownCallout(thread_call_param_t us
, thread_call_param_t
)
2486 /* Power button pressed during wake
2489 DEBUG_LOG("Powerbutton: down. Taking stackshot\n");
2490 ((IOPMrootDomain
*)us
)->takeStackshot(false);
2494 powerButtonUpCallout(thread_call_param_t us
, thread_call_param_t
)
2496 /* Power button released.
2497 * Delete any stackshot data
2499 DEBUG_LOG("PowerButton: up callout. Delete stackshot\n");
2500 ((IOPMrootDomain
*)us
)->deleteStackshot();
2502 //*************************************************************************
2506 // MARK: System Sleep
2508 //******************************************************************************
2509 // startIdleSleepTimer
2511 //******************************************************************************
2514 IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
2516 AbsoluteTime deadline
;
2520 DLOG("idle timer not set (noidle=%d)\n", gNoIdleFlag
);
2524 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
2525 thread_call_enter_delayed(extraSleepTimer
, deadline
);
2526 idleSleepTimerPending
= true;
2528 thread_call_enter(extraSleepTimer
);
2530 DLOG("idle timer set for %u seconds\n", inSeconds
);
2533 //******************************************************************************
2534 // cancelIdleSleepTimer
2536 //******************************************************************************
2539 IOPMrootDomain::cancelIdleSleepTimer( void )
2542 if (idleSleepTimerPending
) {
2543 DLOG("idle timer cancelled\n");
2544 thread_call_cancel(extraSleepTimer
);
2545 idleSleepTimerPending
= false;
2547 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
2549 clock_usec_t microsecs
;
2550 clock_get_uptime(&now
);
2551 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
2552 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
2553 if (assertOnWakeReport
) {
2554 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
2555 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
2561 //******************************************************************************
2562 // idleSleepTimerExpired
2564 //******************************************************************************
2567 idleSleepTimerExpired(
2568 thread_call_param_t us
, thread_call_param_t
)
2570 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
2573 //******************************************************************************
2574 // handleSleepTimerExpiration
2576 // The time between the sleep idle timeout and the next longest one has elapsed.
2577 // It's time to sleep. Start that by removing the clamp that's holding us awake.
2578 //******************************************************************************
2581 IOPMrootDomain::handleSleepTimerExpiration( void )
2583 if (!gIOPMWorkLoop
->inGate()) {
2584 gIOPMWorkLoop
->runAction(
2585 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2586 &IOPMrootDomain::handleSleepTimerExpiration
),
2591 DLOG("sleep timer expired\n");
2594 idleSleepTimerPending
= false;
2595 setQuickSpinDownTimeout();
2596 adjustPowerState(true);
2599 //******************************************************************************
2600 // getTimeToIdleSleep
2602 // Returns number of seconds left before going into idle sleep.
2603 // Caller has to make sure that idle sleep is allowed at the time of calling
2605 //******************************************************************************
2608 IOPMrootDomain::getTimeToIdleSleep( void )
2610 AbsoluteTime now
, lastActivityTime
;
2612 uint32_t minutesSinceUserInactive
= 0;
2613 uint32_t sleepDelay
= 0;
2615 if (!idleSleepEnabled
) {
2619 if (userActivityTime
) {
2620 lastActivityTime
= userActivityTime
;
2622 lastActivityTime
= userBecameInactiveTime
;
2625 // Ignore any lastActivityTime that predates the last system wake.
2626 // The goal is to avoid a sudden idle sleep right after a dark wake
2627 // due to sleepDelay=0 computed below. The alternative 60s minimum
2628 // timeout should be large enough to allow dark wake to complete,
2629 // at which point the idle timer will be promptly cancelled.
2630 clock_get_uptime(&now
);
2631 if ((CMP_ABSOLUTETIME(&lastActivityTime
, &gIOLastWakeAbsTime
) >= 0) &&
2632 (CMP_ABSOLUTETIME(&now
, &lastActivityTime
) > 0)) {
2633 SUB_ABSOLUTETIME(&now
, &lastActivityTime
);
2634 absolutetime_to_nanoseconds(now
, &nanos
);
2635 minutesSinceUserInactive
= nanos
/ (60000000000ULL);
2637 if (minutesSinceUserInactive
>= sleepSlider
) {
2640 sleepDelay
= sleepSlider
- minutesSinceUserInactive
;
2643 DLOG("ignoring lastActivityTime 0x%qx, now 0x%qx, wake 0x%qx\n",
2644 lastActivityTime
, now
, gIOLastWakeAbsTime
);
2645 sleepDelay
= sleepSlider
;
2648 DLOG("user inactive %u min, time to idle sleep %u min\n",
2649 minutesSinceUserInactive
, sleepDelay
);
2651 return sleepDelay
* 60;
2654 //******************************************************************************
2655 // setQuickSpinDownTimeout
2657 //******************************************************************************
2660 IOPMrootDomain::setQuickSpinDownTimeout( void )
2664 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
2667 //******************************************************************************
2668 // restoreUserSpinDownTimeout
2670 //******************************************************************************
2673 IOPMrootDomain::restoreUserSpinDownTimeout( void )
2677 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
2680 //******************************************************************************
2683 //******************************************************************************
2687 IOPMrootDomain::sleepSystem( void )
2689 return sleepSystemOptions(NULL
);
2694 IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
2696 OSObject
*obj
= NULL
;
2697 OSString
*reason
= NULL
;
2698 /* sleepSystem is a public function, and may be called by any kernel driver.
2699 * And that's bad - drivers should sleep the system by calling
2700 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2702 * Note that user space app calls to IOPMSleepSystem() will also travel
2703 * this code path and thus be correctly identified as software sleeps.
2706 if (options
&& options
->getObject("OSSwitch")) {
2707 // Log specific sleep cause for OS Switch hibernation
2708 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate
);
2711 if (options
&& (obj
= options
->getObject("Sleep Reason"))) {
2712 reason
= OSDynamicCast(OSString
, obj
);
2713 if (reason
&& reason
->isEqualTo(kIOPMDarkWakeThermalEmergencyKey
)) {
2714 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
2716 if (reason
&& reason
->isEqualTo(kIOPMNotificationWakeExitKey
)) {
2717 return privateSleepSystem(kIOPMSleepReasonNotificationWakeExit
);
2721 return privateSleepSystem( kIOPMSleepReasonSoftware
);
2726 IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
2728 /* Called from both gated and non-gated context */
2730 if (!checkSystemSleepEnabled() || !pmPowerStateQueue
) {
2731 return kIOReturnNotPermitted
;
2734 pmPowerStateQueue
->submitPowerEvent(
2735 kPowerEventPolicyStimulus
,
2736 (void *) kStimulusDemandSystemSleep
,
2739 return kIOReturnSuccess
;
2742 //******************************************************************************
2745 // This overrides powerChangeDone in IOService.
2746 //******************************************************************************
2748 IOPMrootDomain::powerChangeDone( unsigned long previousPowerState
)
2750 #if !__i386__ && !__x86_64__
2751 uint64_t timeSinceReset
= 0;
2754 unsigned long newState
;
2756 clock_usec_t microsecs
;
2757 uint32_t lastDebugWakeSeconds
;
2758 clock_sec_t adjWakeTime
;
2759 IOPMCalendarStruct nowCalendar
;
2762 newState
= getPowerState();
2763 DLOG("PowerChangeDone: %s->%s\n",
2764 getPowerStateString((uint32_t) previousPowerState
), getPowerStateString((uint32_t) getPowerState()));
2766 if (previousPowerState
== newState
) {
2770 notifierThread
= current_thread();
2771 switch (getPowerState()) {
2773 if (kPMCalendarTypeInvalid
!= _aotWakeTimeCalendar
.selector
) {
2776 PEGetUTCTimeOfDay(&secs
, µsecs
);
2779 if ((kIOPMAOTModeRespectTimers
& _aotMode
) && (_calendarWakeAlarmUTC
< _aotWakeTimeUTC
)) {
2780 IOLog("use _calendarWakeAlarmUTC\n");
2781 adjWakeTime
= _calendarWakeAlarmUTC
;
2782 } else if (_aotExit
|| (kIOPMWakeEventAOTExitFlags
& _aotPendingFlags
)) {
2783 IOLog("accelerate _aotWakeTime for exit\n");
2785 } else if (kIOPMDriverAssertionLevelOn
== getPMAssertionLevel(kIOPMDriverAssertionCPUBit
)) {
2786 IOLog("accelerate _aotWakeTime for assertion\n");
2790 IOPMConvertSecondsToCalendar(adjWakeTime
, &_aotWakeTimeCalendar
);
2793 IOPMConvertSecondsToCalendar(secs
, &nowCalendar
);
2794 IOLog("aotSleep at " YMDTF
" sched: " YMDTF
"\n", YMDT(&nowCalendar
), YMDT(&_aotWakeTimeCalendar
));
2796 IOReturn __unused ret
= setMaintenanceWakeCalendar(&_aotWakeTimeCalendar
);
2797 assert(kIOReturnSuccess
== ret
);
2799 if (_aotLastWakeTime
) {
2800 _aotMetrics
->totalTime
+= mach_absolute_time() - _aotLastWakeTime
;
2801 if (_aotMetrics
->sleepCount
&& (_aotMetrics
->sleepCount
<= kIOPMAOTMetricsKernelWakeCountMax
)) {
2802 strlcpy(&_aotMetrics
->kernelWakeReason
[_aotMetrics
->sleepCount
- 1][0],
2804 sizeof(_aotMetrics
->kernelWakeReason
[_aotMetrics
->sleepCount
]));
2807 _aotPendingFlags
&= ~kIOPMWakeEventAOTPerCycleFlags
;
2808 if (_aotTimerScheduled
) {
2809 _aotTimerES
->cancelTimeout();
2810 _aotTimerScheduled
= false;
2812 acceptSystemWakeEvents(kAcceptSystemWakeEvents_Enable
);
2814 // re-enable this timer for next sleep
2815 cancelIdleSleepTimer();
2817 if (clamshellExists
) {
2818 #if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
2819 if (gClamshellFlags
& kClamshell_WAR_58009435
) {
2820 // Disable clamshell sleep until system has completed full wake.
2821 // This prevents a system sleep request (due to a clamshell close)
2822 // from being queued until the end of system full wake - even if
2823 // other clamshell disable bits outside of our control is wrong.
2824 setClamShellSleepDisable(true, kClamshellSleepDisableInternal
);
2828 // Log the last known clamshell state before system sleep
2829 DLOG("clamshell closed %d, disabled %d/%x, desktopMode %d, ac %d\n",
2830 clamshellClosed
, clamshellDisabled
, clamshellSleepDisableMask
,
2831 desktopMode
, acAdaptorConnected
);
2834 clock_get_calendar_absolute_and_microtime(&secs
, µsecs
, &now
);
2836 gIOLastSleepTime
.tv_sec
= secs
;
2837 gIOLastSleepTime
.tv_usec
= microsecs
;
2838 if (!_aotLastWakeTime
) {
2839 gIOLastUserSleepTime
= gIOLastSleepTime
;
2842 gIOLastWakeTime
.tv_sec
= 0;
2843 gIOLastWakeTime
.tv_usec
= 0;
2844 gIOLastSleepAbsTime
= now
;
2846 if (wake2DarkwakeDelay
&& sleepDelaysReport
) {
2847 clock_sec_t wake2DarkwakeSecs
, darkwake2SleepSecs
;
2848 // Update 'wake2DarkwakeDelay' histogram if this is a fullwake->sleep transition
2850 SUB_ABSOLUTETIME(&now
, &ts_sleepStart
);
2851 absolutetime_to_microtime(now
, &darkwake2SleepSecs
, µsecs
);
2852 absolutetime_to_microtime(wake2DarkwakeDelay
, &wake2DarkwakeSecs
, µsecs
);
2853 HISTREPORT_TALLYVALUE(sleepDelaysReport
,
2854 (int64_t)(wake2DarkwakeSecs
+ darkwake2SleepSecs
));
2856 DLOG("Updated sleepDelaysReport %lu %lu\n", (unsigned long)wake2DarkwakeSecs
, (unsigned long)darkwake2SleepSecs
);
2857 wake2DarkwakeDelay
= 0;
2860 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
2862 IOHibernateSystemHasSlept();
2864 evaluateSystemSleepPolicyFinal();
2866 LOG("System Sleep\n");
2868 if (thermalWarningState
) {
2869 OSSharedPtr
<const OSSymbol
> event
= OSSymbol::withCString(kIOPMThermalLevelWarningKey
);
2871 systemPowerEventOccurred(event
.get(), kIOPMThermalLevelUnknown
);
2874 assertOnWakeSecs
= 0;
2875 lowBatteryCondition
= false;
2876 thermalEmergencyState
= false;
2878 #if DEVELOPMENT || DEBUG
2879 extern int g_should_log_clock_adjustments
;
2880 if (g_should_log_clock_adjustments
) {
2881 clock_sec_t secs
= 0;
2882 clock_usec_t microsecs
= 0;
2883 uint64_t now_b
= mach_absolute_time();
2887 PEGetUTCTimeOfDay(&secs
, µsecs
);
2889 uint64_t now_a
= mach_absolute_time();
2890 os_log(OS_LOG_DEFAULT
, "%s PMU before going to sleep %lu s %d u %llu abs_b_PEG %llu abs_a_PEG \n",
2891 __func__
, (unsigned long)secs
, microsecs
, now_b
, now_a
);
2895 getPlatform()->sleepKernel();
2897 // The CPU(s) are off at this point,
2898 // Code will resume execution here upon wake.
2900 clock_get_uptime(&gIOLastWakeAbsTime
);
2901 IOLog("gIOLastWakeAbsTime: %lld\n", gIOLastWakeAbsTime
);
2902 _highestCapability
= 0;
2905 IOHibernateSystemWake();
2908 // sleep transition complete
2909 gSleepOrShutdownPending
= 0;
2911 // trip the reset of the calendar clock
2912 clock_wakeup_calendar();
2913 clock_get_calendar_microtime(&secs
, µsecs
);
2914 gIOLastWakeTime
.tv_sec
= secs
;
2915 gIOLastWakeTime
.tv_usec
= microsecs
;
2918 if (_aotWakeTimeCalendar
.selector
!= kPMCalendarTypeInvalid
) {
2919 _aotWakeTimeCalendar
.selector
= kPMCalendarTypeInvalid
;
2922 PEGetUTCTimeOfDay(&secs
, µsecs
);
2923 IOPMConvertSecondsToCalendar(secs
, &nowCalendar
);
2924 IOLog("aotWake at " YMDTF
" sched: " YMDTF
"\n", YMDT(&nowCalendar
), YMDT(&_aotWakeTimeCalendar
));
2925 _aotMetrics
->sleepCount
++;
2926 _aotLastWakeTime
= gIOLastWakeAbsTime
;
2927 if (_aotMetrics
->sleepCount
<= kIOPMAOTMetricsKernelWakeCountMax
) {
2928 _aotMetrics
->kernelSleepTime
[_aotMetrics
->sleepCount
- 1]
2929 = (((uint64_t) gIOLastSleepTime
.tv_sec
) << 10) + (gIOLastSleepTime
.tv_usec
/ 1000);
2930 _aotMetrics
->kernelWakeTime
[_aotMetrics
->sleepCount
- 1]
2931 = (((uint64_t) gIOLastWakeTime
.tv_sec
) << 10) + (gIOLastWakeTime
.tv_usec
/ 1000);
2935 if (_aotWakeTimeUTC
<= secs
) {
2936 _aotTestTime
= _aotTestTime
+ _aotTestInterval
;
2938 setWakeTime(_aotTestTime
);
2943 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
2946 lastSleepReason
= 0;
2948 lastDebugWakeSeconds
= _debugWakeSeconds
;
2949 _debugWakeSeconds
= 0;
2950 _scheduledAlarmMask
= 0;
2951 _nextScheduledAlarmType
= NULL
;
2953 darkWakeExit
= false;
2954 darkWakePowerClamped
= false;
2955 darkWakePostTickle
= false;
2956 darkWakeHibernateError
= false;
2957 darkWakeToSleepASAP
= true;
2958 darkWakeLogClamp
= true;
2959 sleepTimerMaintenance
= false;
2960 sleepToStandby
= false;
2961 wranglerTickled
= false;
2962 userWasActive
= false;
2963 isRTCAlarmWake
= false;
2964 clamshellIgnoreClose
= false;
2965 fullWakeReason
= kFullWakeReasonNone
;
2967 #if defined(__i386__) || defined(__x86_64__)
2968 kdebugTrace(kPMLogSystemWake
, 0, 0, 0);
2970 OSSharedPtr
<OSObject
> wakeTypeProp
= copyProperty(kIOPMRootDomainWakeTypeKey
);
2971 OSSharedPtr
<OSObject
> wakeReasonProp
= copyProperty(kIOPMRootDomainWakeReasonKey
);
2972 OSString
* wakeType
= OSDynamicCast(OSString
, wakeTypeProp
.get());
2973 OSString
* wakeReason
= OSDynamicCast(OSString
, wakeReasonProp
.get());
2975 if (wakeReason
&& (wakeReason
->getLength() >= 2) &&
2976 gWakeReasonString
[0] == '\0') {
2978 // Until the platform driver can claim its wake reasons
2979 strlcat(gWakeReasonString
, wakeReason
->getCStringNoCopy(),
2980 sizeof(gWakeReasonString
));
2984 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
)) {
2985 lowBatteryCondition
= true;
2986 darkWakeMaintenance
= true;
2989 OSSharedPtr
<OSObject
> hibOptionsProp
= copyProperty(kIOHibernateOptionsKey
);
2990 OSNumber
* hibOptions
= OSDynamicCast( OSNumber
, hibOptionsProp
.get());
2991 if (hibernateAborted
|| ((hibOptions
&&
2992 !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
)))) {
2993 // Hibernate aborted, or EFI brought up graphics
2994 darkWakeExit
= true;
2995 if (hibernateAborted
) {
2996 DLOG("Hibernation aborted\n");
2998 DLOG("EFI brought up graphics. Going to full wake. HibOptions: 0x%x\n", hibOptions
->unsigned32BitValue());
3003 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeUser
) ||
3004 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
))) {
3005 // User wake or RTC alarm
3006 darkWakeExit
= true;
3007 if (wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
)) {
3008 isRTCAlarmWake
= true;
3010 } else if (wakeType
&&
3011 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
)) {
3012 // SMC standby timer trumps SleepX
3013 darkWakeMaintenance
= true;
3014 sleepTimerMaintenance
= true;
3015 } else if ((lastDebugWakeSeconds
!= 0) &&
3016 ((gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
) == 0)) {
3017 // SleepX before maintenance
3018 darkWakeExit
= true;
3019 } else if (wakeType
&&
3020 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
)) {
3021 darkWakeMaintenance
= true;
3022 } else if (wakeType
&&
3023 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepService
)) {
3024 darkWakeMaintenance
= true;
3025 darkWakeSleepService
= true;
3027 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) {
3028 sleepToStandby
= true;
3031 } else if (wakeType
&&
3032 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeHibernateError
)) {
3033 darkWakeMaintenance
= true;
3034 darkWakeHibernateError
= true;
3036 // Unidentified wake source, resume to full wake if debug
3037 // alarm is pending.
3039 if (lastDebugWakeSeconds
&&
3040 (!wakeReason
|| wakeReason
->isEqualTo(""))) {
3041 darkWakeExit
= true;
3047 darkWakeToSleepASAP
= false;
3048 fullWakeReason
= kFullWakeReasonLocalUser
;
3050 } else if (displayPowerOnRequested
&& checkSystemCanSustainFullWake()) {
3051 handleSetDisplayPowerOn(true);
3052 } else if (!darkWakeMaintenance
) {
3053 // Early/late tickle for non-maintenance wake.
3054 if ((gDarkWakeFlags
& kDarkWakeFlagPromotionMask
) != kDarkWakeFlagPromotionNone
) {
3055 darkWakePostTickle
= true;
3058 #else /* !__i386__ && !__x86_64__ */
3059 timeSinceReset
= ml_get_time_since_reset();
3060 kdebugTrace(kPMLogSystemWake
, 0, (uintptr_t)(timeSinceReset
>> 32), (uintptr_t) timeSinceReset
);
3062 if ((gDarkWakeFlags
& kDarkWakeFlagPromotionMask
) == kDarkWakeFlagPromotionEarly
) {
3063 wranglerTickled
= true;
3064 fullWakeReason
= kFullWakeReasonLocalUser
;
3065 requestUserActive(this, "Full wake on dark wake promotion boot-arg");
3066 } else if ((lastDebugWakeSeconds
!= 0) && !(gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
)) {
3067 isRTCAlarmWake
= true;
3068 fullWakeReason
= kFullWakeReasonLocalUser
;
3069 requestUserActive(this, "RTC debug alarm");
3072 // stay awake for at least 30 seconds
3073 startIdleSleepTimer(30);
3077 thread_call_enter(updateConsoleUsersEntry
);
3079 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonWake
);
3082 #if !__i386__ && !__x86_64__
3086 DLOG("Force re-evaluating aggressiveness\n");
3087 /* Force re-evaluate the aggressiveness values to set appropriate idle sleep timer */
3088 pmPowerStateQueue
->submitPowerEvent(
3089 kPowerEventPolicyStimulus
,
3090 (void *) kStimulusNoIdleSleepPreventers
);
3092 // After changing to ON_STATE, invalidate any previously queued
3093 // request to change to a state less than ON_STATE. This isn't
3094 // necessary for AOT_STATE or if the device has only one running
3095 // state since the changePowerStateToPriv() issued at the tail
3096 // end of SLEEP_STATE case should take care of that.
3097 if (getPowerState() == ON_STATE
) {
3098 changePowerStateWithTagToPriv(ON_STATE
, kCPSReasonWake
);
3102 #endif /* !__i386__ && !__x86_64__ */
3104 notifierThread
= NULL
;
3107 //******************************************************************************
3108 // requestPowerDomainState
3110 // Extend implementation in IOService. Running on PM work loop thread.
3111 //******************************************************************************
3114 IOPMrootDomain::requestPowerDomainState(
3115 IOPMPowerFlags childDesire
,
3116 IOPowerConnection
* childConnection
,
3117 unsigned long specification
)
3119 // Idle and system sleep prevention flags affects driver desire.
3120 // Children desire are irrelevant so they are cleared.
3122 return super::requestPowerDomainState(0, childConnection
, specification
);
3127 makeSleepPreventersListLog(const OSSharedPtr
<OSSet
> &preventers
, char *buf
, size_t buf_size
)
3129 if (!preventers
->getCount()) {
3133 char *buf_iter
= buf
+ strlen(buf
);
3134 char *buf_end
= buf
+ buf_size
;
3136 OSSharedPtr
<OSCollectionIterator
> iterator
= OSCollectionIterator::withCollection(preventers
.get());
3137 OSObject
*obj
= NULL
;
3139 while ((obj
= iterator
->getNextObject())) {
3140 IOService
*srv
= OSDynamicCast(IOService
, obj
);
3141 if (buf_iter
< buf_end
) {
3142 buf_iter
+= snprintf(buf_iter
, buf_end
- buf_iter
, " %s", srv
->getName());
3144 DLOG("Print buffer exhausted for sleep preventers list\n");
3150 //******************************************************************************
3151 // updatePreventIdleSleepList
3153 // Called by IOService on PM work loop.
3154 // Returns true if PM policy recognized the driver's desire to prevent idle
3155 // sleep and updated the list of idle sleep preventers. Returns false otherwise
3156 //******************************************************************************
3159 IOPMrootDomain::updatePreventIdleSleepList(
3160 IOService
* service
, bool addNotRemove
)
3162 unsigned int oldCount
;
3164 oldCount
= idleSleepPreventersCount();
3165 return updatePreventIdleSleepListInternal(service
, addNotRemove
, oldCount
);
3169 IOPMrootDomain::updatePreventIdleSleepListInternal(
3170 IOService
* service
, bool addNotRemove
, unsigned int oldCount
)
3172 unsigned int newCount
;
3176 #if defined(XNU_TARGET_OS_OSX)
3177 // Only the display wrangler and no-idle-sleep kernel assertions
3178 // can prevent idle sleep. The kIOPMPreventIdleSleep capability flag
3179 // reported by drivers in their power state table is ignored.
3180 if (service
&& (service
!= wrangler
) && (service
!= this)) {
3187 preventIdleSleepList
->setObject(service
);
3188 DLOG("Added %s to idle sleep preventers list (Total %u)\n",
3189 service
->getName(), preventIdleSleepList
->getCount());
3190 } else if (preventIdleSleepList
->member(service
)) {
3191 preventIdleSleepList
->removeObject(service
);
3192 DLOG("Removed %s from idle sleep preventers list (Total %u)\n",
3193 service
->getName(), preventIdleSleepList
->getCount());
3196 if (preventIdleSleepList
->getCount()) {
3197 char buf
[256] = "Idle Sleep Preventers:";
3198 makeSleepPreventersListLog(preventIdleSleepList
, buf
, sizeof(buf
));
3203 newCount
= idleSleepPreventersCount();
3205 if ((oldCount
== 0) && (newCount
!= 0)) {
3206 // Driver added to empty prevent list.
3207 // Update the driver desire to prevent idle sleep.
3208 // Driver desire does not prevent demand sleep.
3210 changePowerStateWithTagTo(getRUN_STATE(), kCPSReasonIdleSleepPrevent
);
3211 } else if ((oldCount
!= 0) && (newCount
== 0)) {
3212 // Last driver removed from prevent list.
3213 // Drop the driver clamp to allow idle sleep.
3215 changePowerStateWithTagTo(SLEEP_STATE
, kCPSReasonIdleSleepAllow
);
3216 evaluatePolicy( kStimulusNoIdleSleepPreventers
);
3218 messageClient(kIOPMMessageIdleSleepPreventers
, systemCapabilityNotifier
.get(),
3219 &newCount
, sizeof(newCount
));
3221 #if defined(XNU_TARGET_OS_OSX)
3222 if (addNotRemove
&& (service
== wrangler
) && !checkSystemCanSustainFullWake()) {
3223 DLOG("Cannot cancel idle sleep\n");
3224 return false; // do not idle-cancel
3231 //******************************************************************************
3233 //******************************************************************************
3236 IOPMrootDomain::startSpinDump(uint32_t spindumpKind
)
3238 messageClients(kIOPMMessageLaunchBootSpinDump
, (void *)(uintptr_t)spindumpKind
);
3241 //******************************************************************************
3242 // preventSystemSleepListUpdate
3244 // Called by IOService on PM work loop.
3245 //******************************************************************************
3248 IOPMrootDomain::updatePreventSystemSleepList(
3249 IOService
* service
, bool addNotRemove
)
3251 unsigned int oldCount
, newCount
;
3254 if (this == service
) {
3258 oldCount
= preventSystemSleepList
->getCount();
3260 preventSystemSleepList
->setObject(service
);
3261 DLOG("Added %s to system sleep preventers list (Total %u)\n",
3262 service
->getName(), preventSystemSleepList
->getCount());
3263 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
3265 clock_usec_t microsecs
;
3266 clock_get_uptime(&now
);
3267 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
3268 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
3269 if (assertOnWakeReport
) {
3270 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
3271 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
3274 } else if (preventSystemSleepList
->member(service
)) {
3275 preventSystemSleepList
->removeObject(service
);
3276 DLOG("Removed %s from system sleep preventers list (Total %u)\n",
3277 service
->getName(), preventSystemSleepList
->getCount());
3279 if ((oldCount
!= 0) && (preventSystemSleepList
->getCount() == 0)) {
3280 // Lost all system sleep preventers.
3281 // Send stimulus if system sleep was blocked, and is in dark wake.
3282 evaluatePolicy( kStimulusDarkWakeEvaluate
);
3286 newCount
= preventSystemSleepList
->getCount();
3288 char buf
[256] = "System Sleep Preventers:";
3289 makeSleepPreventersListLog(preventSystemSleepList
, buf
, sizeof(buf
));
3293 messageClient(kIOPMMessageSystemSleepPreventers
, systemCapabilityNotifier
.get(),
3294 &newCount
, sizeof(newCount
));
3298 IOPMrootDomain::copySleepPreventersList(OSArray
**idleSleepList
, OSArray
**systemSleepList
)
3300 OSSharedPtr
<OSCollectionIterator
> iterator
;
3301 OSObject
*object
= NULL
;
3302 OSSharedPtr
<OSArray
> array
;
3304 if (!gIOPMWorkLoop
->inGate()) {
3305 gIOPMWorkLoop
->runAction(
3306 OSMemberFunctionCast(IOWorkLoop::Action
, this,
3307 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersList
),
3308 this, (void *)idleSleepList
, (void *)systemSleepList
);
3312 if (idleSleepList
&& preventIdleSleepList
&& (preventIdleSleepList
->getCount() != 0)) {
3313 iterator
= OSCollectionIterator::withCollection(preventIdleSleepList
.get());
3314 array
= OSArray::withCapacity(5);
3316 if (iterator
&& array
) {
3317 while ((object
= iterator
->getNextObject())) {
3318 IOService
*service
= OSDynamicCast(IOService
, object
);
3320 OSSharedPtr
<const OSSymbol
> name
= service
->copyName();
3322 array
->setObject(name
.get());
3327 *idleSleepList
= array
.detach();
3330 if (systemSleepList
&& preventSystemSleepList
&& (preventSystemSleepList
->getCount() != 0)) {
3331 iterator
= OSCollectionIterator::withCollection(preventSystemSleepList
.get());
3332 array
= OSArray::withCapacity(5);
3334 if (iterator
&& array
) {
3335 while ((object
= iterator
->getNextObject())) {
3336 IOService
*service
= OSDynamicCast(IOService
, object
);
3338 OSSharedPtr
<const OSSymbol
> name
= service
->copyName();
3340 array
->setObject(name
.get());
3345 *systemSleepList
= array
.detach();
3350 IOPMrootDomain::copySleepPreventersListWithID(OSArray
**idleSleepList
, OSArray
**systemSleepList
)
3352 OSSharedPtr
<OSCollectionIterator
> iterator
;
3353 OSObject
*object
= NULL
;
3354 OSSharedPtr
<OSArray
> array
;
3356 if (!gIOPMWorkLoop
->inGate()) {
3357 gIOPMWorkLoop
->runAction(
3358 OSMemberFunctionCast(IOWorkLoop::Action
, this,
3359 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersListWithID
),
3360 this, (void *)idleSleepList
, (void *)systemSleepList
);
3364 if (idleSleepList
&& preventIdleSleepList
&& (preventIdleSleepList
->getCount() != 0)) {
3365 iterator
= OSCollectionIterator::withCollection(preventIdleSleepList
.get());
3366 array
= OSArray::withCapacity(5);
3368 if (iterator
&& array
) {
3369 while ((object
= iterator
->getNextObject())) {
3370 IOService
*service
= OSDynamicCast(IOService
, object
);
3372 OSSharedPtr
<OSDictionary
> dict
= OSDictionary::withCapacity(2);
3373 OSSharedPtr
<const OSSymbol
> name
= service
->copyName();
3374 OSSharedPtr
<OSNumber
> id
= OSNumber::withNumber(service
->getRegistryEntryID(), 64);
3375 if (dict
&& name
&& id
) {
3376 dict
->setObject(kIOPMDriverAssertionRegistryEntryIDKey
, id
.get());
3377 dict
->setObject(kIOPMDriverAssertionOwnerStringKey
, name
.get());
3378 array
->setObject(dict
.get());
3383 *idleSleepList
= array
.detach();
3386 if (systemSleepList
&& preventSystemSleepList
&& (preventSystemSleepList
->getCount() != 0)) {
3387 iterator
= OSCollectionIterator::withCollection(preventSystemSleepList
.get());
3388 array
= OSArray::withCapacity(5);
3390 if (iterator
&& array
) {
3391 while ((object
= iterator
->getNextObject())) {
3392 IOService
*service
= OSDynamicCast(IOService
, object
);
3394 OSSharedPtr
<OSDictionary
> dict
= OSDictionary::withCapacity(2);
3395 OSSharedPtr
<const OSSymbol
> name
= service
->copyName();
3396 OSSharedPtr
<OSNumber
> id
= OSNumber::withNumber(service
->getRegistryEntryID(), 64);
3397 if (dict
&& name
&& id
) {
3398 dict
->setObject(kIOPMDriverAssertionRegistryEntryIDKey
, id
.get());
3399 dict
->setObject(kIOPMDriverAssertionOwnerStringKey
, name
.get());
3400 array
->setObject(dict
.get());
3405 *systemSleepList
= array
.detach();
3409 //******************************************************************************
3412 // Override the superclass implementation to send a different message type.
3413 //******************************************************************************
3416 IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
3418 DLOG("tellChangeDown %s->%s\n",
3419 getPowerStateString((uint32_t) getPowerState()), getPowerStateString((uint32_t) stateNum
));
3421 if (SLEEP_STATE
== stateNum
) {
3422 // Legacy apps were already told in the full->dark transition
3423 if (!ignoreTellChangeDown
) {
3424 tracePoint( kIOPMTracePointSleepApplications
);
3426 tracePoint( kIOPMTracePointSleepPriorityClients
);
3430 if (!ignoreTellChangeDown
) {
3431 userActivityAtSleep
= userActivityCount
;
3432 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
3434 if (SLEEP_STATE
== stateNum
) {
3435 hibernateAborted
= false;
3437 // Direct callout into OSKext so it can disable kext unloads
3438 // during sleep/wake to prevent deadlocks.
3439 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
3441 IOService::updateConsoleUsers(NULL
, kIOMessageSystemWillSleep
);
3443 // Two change downs are sent by IOServicePM. Ignore the 2nd.
3444 // But tellClientsWithResponse() must be called for both.
3445 ignoreTellChangeDown
= true;
3449 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
3452 //******************************************************************************
3455 // Override the superclass implementation to send a different message type.
3456 // This must be idle sleep since we don't ask during any other power change.
3457 //******************************************************************************
3460 IOPMrootDomain::askChangeDown( unsigned long stateNum
)
3462 DLOG("askChangeDown %s->%s\n",
3463 getPowerStateString((uint32_t) getPowerState()), getPowerStateString((uint32_t) stateNum
));
3465 // Don't log for dark wake entry
3466 if (kSystemTransitionSleep
== _systemTransitionType
) {
3467 tracePoint( kIOPMTracePointSleepApplications
);
3470 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
3473 //******************************************************************************
3474 // askChangeDownDone
3476 // An opportunity for root domain to cancel the power transition,
3477 // possibily due to an assertion created by powerd in response to
3478 // kIOMessageCanSystemSleep.
3481 // full -> dark wake transition
3482 // 1. Notify apps and powerd with kIOMessageCanSystemSleep
3483 // 2. askChangeDownDone()
3484 // dark -> sleep transition
3485 // 1. Notify powerd with kIOMessageCanSystemSleep
3486 // 2. askChangeDownDone()
3489 // full -> dark wake transition
3490 // 1. Notify powerd with kIOMessageCanSystemSleep
3491 // 2. askChangeDownDone()
3492 // dark -> sleep transition
3493 // 1. Notify powerd with kIOMessageCanSystemSleep
3494 // 2. askChangeDownDone()
3495 //******************************************************************************
3498 IOPMrootDomain::askChangeDownDone(
3499 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
3501 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
3502 *inOutChangeFlags
, *cancel
,
3503 _systemTransitionType
,
3504 _currentCapability
, _pendingCapability
);
3506 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
)) {
3507 // Dark->Sleep transition.
3508 // Check if there are any deny sleep assertions.
3509 // lastSleepReason already set by handleOurPowerChangeStart()
3511 if (!checkSystemCanSleep(lastSleepReason
)) {
3512 // Cancel dark wake to sleep transition.
3513 // Must re-scan assertions upon entering dark wake.
3516 DLOG("cancel dark->sleep\n");
3518 if (_aotMode
&& (kPMCalendarTypeInvalid
!= _aotWakeTimeCalendar
.selector
)) {
3519 uint64_t now
= mach_continuous_time();
3520 if (((now
+ _aotWakePreWindow
) >= _aotWakeTimeContinuous
)
3521 && (now
< (_aotWakeTimeContinuous
+ _aotWakePostWindow
))) {
3523 IOLog("AOT wake window cancel: %qd, %qd\n", now
, _aotWakeTimeContinuous
);
3529 //******************************************************************************
3530 // systemDidNotSleep
3532 // Work common to both canceled or aborted sleep.
3533 //******************************************************************************
3536 IOPMrootDomain::systemDidNotSleep( void )
3538 // reset console lock state
3539 thread_call_enter(updateConsoleUsersEntry
);
3541 if (idleSleepEnabled
) {
3543 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
3544 startIdleSleepTimer(kIdleSleepRetryInterval
);
3546 startIdleSleepTimer(idleSeconds
);
3548 } else if (!userIsActive
) {
3549 // Manually start the idle sleep timer besides waiting for
3550 // the user to become inactive.
3551 startIdleSleepTimer(kIdleSleepRetryInterval
);
3555 preventTransitionToUserActive(false);
3556 IOService::setAdvisoryTickleEnable( true );
3558 // After idle revert and cancel, send a did-change message to powerd
3559 // to balance the previous will-change message. Kernel clients do not
3560 // need this since sleep cannot be canceled once they are notified.
3562 if (toldPowerdCapWillChange
&& systemCapabilityNotifier
&&
3563 (_pendingCapability
!= _currentCapability
) &&
3564 ((_systemMessageClientMask
& kSystemMessageClientPowerd
) != 0)) {
3565 // Differs from a real capability gain change where notifyRef != 0,
3566 // but it is zero here since no response is expected.
3568 IOPMSystemCapabilityChangeParameters params
;
3570 bzero(¶ms
, sizeof(params
));
3571 params
.fromCapabilities
= _pendingCapability
;
3572 params
.toCapabilities
= _currentCapability
;
3573 params
.changeFlags
= kIOPMSystemCapabilityDidChange
;
3575 DLOG("MESG cap %x->%x did change\n",
3576 params
.fromCapabilities
, params
.toCapabilities
);
3577 messageClient(kIOMessageSystemCapabilityChange
, systemCapabilityNotifier
.get(),
3578 ¶ms
, sizeof(params
));
3582 //******************************************************************************
3585 // Notify registered applications and kernel clients that we are not dropping
3588 // We override the superclass implementation so we can send a different message
3589 // type to the client or application being notified.
3591 // This must be a vetoed idle sleep, since no other power change can be vetoed.
3592 //******************************************************************************
3595 IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
3597 DLOG("tellNoChangeDown %s->%s\n",
3598 getPowerStateString((uint32_t) getPowerState()), getPowerStateString((uint32_t) stateNum
));
3600 // Sleep canceled, clear the sleep trace point.
3601 tracePoint(kIOPMTracePointSystemUp
);
3603 systemDidNotSleep();
3604 return tellClients( kIOMessageSystemWillNotSleep
);
3607 //******************************************************************************
3610 // Notify registered applications and kernel clients that we are raising power.
3612 // We override the superclass implementation so we can send a different message
3613 // type to the client or application being notified.
3614 //******************************************************************************
3617 IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
3619 DLOG("tellChangeUp %s->%s\n",
3620 getPowerStateString((uint32_t) getPowerState()), getPowerStateString((uint32_t) stateNum
));
3622 ignoreTellChangeDown
= false;
3624 if (stateNum
== ON_STATE
) {
3625 // Direct callout into OSKext so it can disable kext unloads
3626 // during sleep/wake to prevent deadlocks.
3627 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
3629 // Notify platform that sleep was cancelled or resumed.
3630 getPlatform()->callPlatformFunction(
3631 sleepMessagePEFunction
.get(), false,
3632 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
3635 if (getPowerState() == ON_STATE
) {
3636 // Sleep was cancelled by idle cancel or revert
3637 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
)) {
3638 // rdar://problem/50363791
3639 // If system is in dark wake and sleep is cancelled, do not
3640 // send SystemWillPowerOn/HasPoweredOn messages to kernel
3641 // priority clients. They haven't yet seen a SystemWillSleep
3642 // message before the cancellation. So make sure the kernel
3643 // client bit is cleared in _systemMessageClientMask before
3644 // invoking the tellClients() below. This bit may have been
3645 // set by handleOurPowerChangeStart() anticipating a successful
3646 // sleep and setting the filter mask ahead of time allows the
3647 // SystemWillSleep message to go through.
3648 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
3651 systemDidNotSleep();
3652 tellClients( kIOMessageSystemWillPowerOn
);
3655 tracePoint( kIOPMTracePointWakeApplications
);
3656 tellClients( kIOMessageSystemHasPoweredOn
);
3660 #define CAP_WILL_CHANGE_TO_OFF(params, flag) \
3661 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
3662 ((params)->fromCapabilities & (flag)) && \
3663 (((params)->toCapabilities & (flag)) == 0))
3665 #define CAP_DID_CHANGE_TO_ON(params, flag) \
3666 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
3667 ((params)->toCapabilities & (flag)) && \
3668 (((params)->fromCapabilities & (flag)) == 0))
3670 #define CAP_DID_CHANGE_TO_OFF(params, flag) \
3671 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
3672 ((params)->fromCapabilities & (flag)) && \
3673 (((params)->toCapabilities & (flag)) == 0))
3675 #define CAP_WILL_CHANGE_TO_ON(params, flag) \
3676 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
3677 ((params)->toCapabilities & (flag)) && \
3678 (((params)->fromCapabilities & (flag)) == 0))
3680 //******************************************************************************
3681 // sysPowerDownHandler
3683 // Perform a vfs sync before system sleep.
3684 //******************************************************************************
3687 IOPMrootDomain::sysPowerDownHandler(
3688 void * target
, void * refCon
,
3689 UInt32 messageType
, IOService
* service
,
3690 void * messageArgs
, vm_size_t argSize
)
3692 static UInt32 lastSystemMessageType
= 0;
3695 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
3697 // rdar://problem/50363791
3698 // Sanity check to make sure the SystemWill/Has message types are
3699 // received in the expected order for all kernel priority clients.
3700 if (messageType
== kIOMessageSystemWillSleep
||
3701 messageType
== kIOMessageSystemWillPowerOn
||
3702 messageType
== kIOMessageSystemHasPoweredOn
) {
3703 switch (messageType
) {
3704 case kIOMessageSystemWillPowerOn
:
3705 assert(lastSystemMessageType
== kIOMessageSystemWillSleep
);
3707 case kIOMessageSystemHasPoweredOn
:
3708 assert(lastSystemMessageType
== kIOMessageSystemWillPowerOn
);
3712 lastSystemMessageType
= messageType
;
3716 return kIOReturnUnsupported
;
3719 if (messageType
== kIOMessageSystemCapabilityChange
) {
3720 IOPMSystemCapabilityChangeParameters
* params
=
3721 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
3723 // Interested applications have been notified of an impending power
3724 // change and have acked (when applicable).
3725 // This is our chance to save whatever state we can before powering
3727 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
3730 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
3731 params
->fromCapabilities
, params
->toCapabilities
,
3732 params
->changeFlags
);
3734 if (CAP_WILL_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityCPU
)) {
3735 // We will ack within 20 seconds
3736 params
->maxWaitForReply
= 20 * 1000 * 1000;
3739 gRootDomain
->evaluateSystemSleepPolicyEarly();
3741 // add in time we could spend freeing pages
3742 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
) {
3743 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
3745 DLOG("sysPowerDownHandler max wait %d s\n",
3746 (int) (params
->maxWaitForReply
/ 1000 / 1000));
3749 // Notify platform that sleep has begun, after the early
3750 // sleep policy evaluation.
3751 getPlatform()->callPlatformFunction(
3752 sleepMessagePEFunction
.get(), false,
3753 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
3756 if (!OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
)) {
3757 // Purposely delay the ack and hope that shutdown occurs quickly.
3758 // Another option is not to schedule the thread and wait for
3760 AbsoluteTime deadline
;
3761 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
3762 thread_call_enter1_delayed(
3763 gRootDomain
->diskSyncCalloutEntry
,
3764 (thread_call_param_t
)(uintptr_t) params
->notifyRef
,
3768 gRootDomain
->diskSyncCalloutEntry
,
3769 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3773 else if (CAP_DID_CHANGE_TO_ON(params
, kIOPMSystemCapabilityCPU
)) {
3774 // We will ack within 110 seconds
3775 params
->maxWaitForReply
= 110 * 1000 * 1000;
3778 gRootDomain
->diskSyncCalloutEntry
,
3779 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3782 ret
= kIOReturnSuccess
;
3788 //******************************************************************************
3789 // handleQueueSleepWakeUUID
3791 // Called from IOPMrootDomain when we're initiating a sleep,
3792 // or indirectly from PM configd when PM decides to clear the UUID.
3793 // PM clears the UUID several minutes after successful wake from sleep,
3794 // so that we might associate App spindumps with the immediately previous
3797 // @param obj has a retain on it. We're responsible for releasing that retain.
3798 //******************************************************************************
3801 IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
3803 OSSharedPtr
<OSString
> str
;
3805 if (kOSBooleanFalse
== obj
) {
3806 handlePublishSleepWakeUUID(false);
3808 str
.reset(OSDynamicCast(OSString
, obj
), OSNoRetain
);
3810 // This branch caches the UUID for an upcoming sleep/wake
3811 queuedSleepWakeUUIDString
= str
;
3812 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
3816 //******************************************************************************
3817 // handlePublishSleepWakeUUID
3819 // Called from IOPMrootDomain when we're initiating a sleep,
3820 // or indirectly from PM configd when PM decides to clear the UUID.
3821 // PM clears the UUID several minutes after successful wake from sleep,
3822 // so that we might associate App spindumps with the immediately previous
3824 //******************************************************************************
3827 IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
3832 * Clear the current UUID
3834 if (gSleepWakeUUIDIsSet
) {
3835 DLOG("SleepWake UUID cleared\n");
3837 gSleepWakeUUIDIsSet
= false;
3839 removeProperty(kIOPMSleepWakeUUIDKey
);
3840 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
3844 * Optionally, publish a new UUID
3846 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
3847 OSSharedPtr
<OSString
> publishThisUUID
;
3849 publishThisUUID
= queuedSleepWakeUUIDString
;
3851 if (publishThisUUID
) {
3852 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
.get());
3855 gSleepWakeUUIDIsSet
= true;
3856 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
3858 queuedSleepWakeUUIDString
.reset();
3862 //******************************************************************************
3863 // IOPMGetSleepWakeUUIDKey
3865 // Return the truth value of gSleepWakeUUIDIsSet and optionally copy the key.
3866 // To get the full key -- a C string -- the buffer must large enough for
3867 // the end-of-string character.
3868 // The key is expected to be an UUID string
3869 //******************************************************************************
3872 IOPMCopySleepWakeUUIDKey(char *buffer
, size_t buf_len
)
3874 if (!gSleepWakeUUIDIsSet
) {
3878 if (buffer
!= NULL
) {
3879 OSSharedPtr
<OSString
> string
=
3880 OSDynamicPtrCast
<OSString
>(gRootDomain
->copyProperty(kIOPMSleepWakeUUIDKey
));
3885 strlcpy(buffer
, string
->getCStringNoCopy(), buf_len
);
3892 //******************************************************************************
3893 // lowLatencyAudioNotify
3895 // Used to send an update about low latency audio activity to interested
3896 // clients. To keep the overhead minimal the OSDictionary used here
3897 // is initialized at boot.
3898 //******************************************************************************
3901 IOPMrootDomain::lowLatencyAudioNotify(uint64_t time
, boolean_t state
)
3903 if (lowLatencyAudioNotifierDict
&& lowLatencyAudioNotifyStateSym
&& lowLatencyAudioNotifyTimestampSym
&&
3904 lowLatencyAudioNotifyStateVal
&& lowLatencyAudioNotifyTimestampVal
) {
3905 lowLatencyAudioNotifyTimestampVal
->setValue(time
);
3906 lowLatencyAudioNotifyStateVal
->setValue(state
);
3907 setPMSetting(gIOPMSettingLowLatencyAudioModeKey
.get(), lowLatencyAudioNotifierDict
.get());
3909 DLOG("LowLatencyAudioNotify error\n");
3914 //******************************************************************************
3915 // IOPMrootDomainRTNotifier
3917 // Used by performance controller to update the timestamp and state associated
3918 // with low latency audio activity in the system.
3919 //******************************************************************************
3922 IOPMrootDomainRTNotifier(uint64_t time
, boolean_t state
)
3924 gRootDomain
->lowLatencyAudioNotify(time
, state
);
3928 //******************************************************************************
3929 // initializeBootSessionUUID
3931 // Initialize the boot session uuid at boot up and sets it into registry.
3932 //******************************************************************************
3935 IOPMrootDomain::initializeBootSessionUUID(void)
3938 uuid_string_t new_uuid_string
;
3940 uuid_generate(new_uuid
);
3941 uuid_unparse_upper(new_uuid
, new_uuid_string
);
3942 memcpy(bootsessionuuid_string
, new_uuid_string
, sizeof(uuid_string_t
));
3944 setProperty(kIOPMBootSessionUUIDKey
, new_uuid_string
);
3947 //******************************************************************************
3948 // Root domain uses the private and tagged changePowerState methods for
3949 // tracking and logging purposes.
3950 //******************************************************************************
3952 #define REQUEST_TAG_TO_REASON(x) ((uint16_t)x)
3955 nextRequestTag( IOPMRequestTag tag
)
3957 static SInt16 msb16
= 1;
3958 uint16_t id
= OSAddAtomic16(1, &msb16
);
3959 return ((uint32_t)id
<< 16) | REQUEST_TAG_TO_REASON(tag
);
3962 // TODO: remove this shim function and exported symbol
3964 IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
3966 return changePowerStateWithTagTo(ordinal
, kCPSReasonNone
);
3969 // TODO: remove this shim function and exported symbol
3971 IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
3973 return changePowerStateWithTagToPriv(ordinal
, kCPSReasonNone
);
3977 IOPMrootDomain::changePowerStateWithOverrideTo(
3978 IOPMPowerStateIndex ordinal
, IOPMRequestTag reason
)
3980 uint32_t tag
= nextRequestTag(reason
);
3981 DLOG("%s(%s, %x)\n", __FUNCTION__
, getPowerStateString((uint32_t) ordinal
), tag
);
3983 if ((ordinal
!= ON_STATE
) && (ordinal
!= AOT_STATE
) && (ordinal
!= SLEEP_STATE
)) {
3984 return kIOReturnUnsupported
;
3987 return super::changePowerStateWithOverrideTo(ordinal
, tag
);
3991 IOPMrootDomain::changePowerStateWithTagTo(
3992 IOPMPowerStateIndex ordinal
, IOPMRequestTag reason
)
3994 uint32_t tag
= nextRequestTag(reason
);
3995 DLOG("%s(%s, %x)\n", __FUNCTION__
, getPowerStateString((uint32_t) ordinal
), tag
);
3997 if ((ordinal
!= ON_STATE
) && (ordinal
!= AOT_STATE
) && (ordinal
!= SLEEP_STATE
)) {
3998 return kIOReturnUnsupported
;
4001 return super::changePowerStateWithTagTo(ordinal
, tag
);
4005 IOPMrootDomain::changePowerStateWithTagToPriv(
4006 IOPMPowerStateIndex ordinal
, IOPMRequestTag reason
)
4008 uint32_t tag
= nextRequestTag(reason
);
4009 DLOG("%s(%s, %x)\n", __FUNCTION__
, getPowerStateString((uint32_t) ordinal
), tag
);
4011 if ((ordinal
!= ON_STATE
) && (ordinal
!= AOT_STATE
) && (ordinal
!= SLEEP_STATE
)) {
4012 return kIOReturnUnsupported
;
4015 return super::changePowerStateWithTagToPriv(ordinal
, tag
);
4018 //******************************************************************************
4021 //******************************************************************************
4024 IOPMrootDomain::activitySinceSleep(void)
4026 return userActivityCount
!= userActivityAtSleep
;
4030 IOPMrootDomain::abortHibernation(void)
4033 // don't allow hibernation to be aborted on ARM due to user activity
4034 // since once ApplePMGR decides we're hibernating, we can't turn back
4035 // see: <rdar://problem/63848862> Tonga ApplePMGR diff quiesce path support
4038 bool ret
= activitySinceSleep();
4040 if (ret
&& !hibernateAborted
&& checkSystemCanSustainFullWake()) {
4041 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
4042 hibernateAborted
= true;
4049 hibernate_should_abort(void)
4052 return gRootDomain
->abortHibernation();
4058 //******************************************************************************
4059 // willNotifyPowerChildren
4061 // Called after all interested drivers have all acknowledged the power change,
4062 // but before any power children is informed. Dispatched though a thread call,
4063 // so it is safe to perform work that might block on a sleeping disk. PM state
4064 // machine (not thread) will block w/o timeout until this function returns.
4065 //******************************************************************************
4068 IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState
)
4070 OSSharedPtr
<OSDictionary
> dict
;
4071 OSSharedPtr
<OSNumber
> secs
;
4073 if (SLEEP_STATE
== newPowerState
) {
4074 notifierThread
= current_thread();
4075 if (!tasksSuspended
) {
4076 AbsoluteTime deadline
;
4077 tasksSuspended
= TRUE
;
4078 updateTasksSuspend();
4080 clock_interval_to_deadline(10, kSecondScale
, &deadline
);
4081 #if defined(XNU_TARGET_OS_OSX)
4082 vm_pageout_wait(AbsoluteTime_to_scalar(&deadline
));
4083 #endif /* defined(XNU_TARGET_OS_OSX) */
4086 _aotReadyToFullWake
= false;
4088 if (_aotLingerTime
) {
4090 IOLog("aot linger no return\n");
4091 clock_absolutetime_interval_to_deadline(_aotLingerTime
, &deadline
);
4092 clock_delay_until(deadline
);
4097 _aotWakeTimeCalendar
.selector
= kPMCalendarTypeInvalid
;
4099 bzero(_aotMetrics
, sizeof(IOPMAOTMetrics
));
4101 } else if (!_aotNow
&& !_debugWakeSeconds
) {
4104 _aotPendingFlags
= 0;
4105 _aotTasksSuspended
= true;
4106 _aotLastWakeTime
= 0;
4107 bzero(_aotMetrics
, sizeof(IOPMAOTMetrics
));
4108 if (kIOPMAOTModeCycle
& _aotMode
) {
4109 clock_interval_to_absolutetime_interval(60, kSecondScale
, &_aotTestInterval
);
4110 _aotTestTime
= mach_continuous_time() + _aotTestInterval
;
4111 setWakeTime(_aotTestTime
);
4113 uint32_t lingerSecs
;
4114 if (!PE_parse_boot_argn("aotlinger", &lingerSecs
, sizeof(lingerSecs
))) {
4117 clock_interval_to_absolutetime_interval(lingerSecs
, kSecondScale
, &_aotLingerTime
);
4118 clock_interval_to_absolutetime_interval(2000, kMillisecondScale
, &_aotWakePreWindow
);
4119 clock_interval_to_absolutetime_interval(1100, kMillisecondScale
, &_aotWakePostWindow
);
4123 IOHibernateSystemSleep();
4124 IOHibernateIOKitSleep();
4126 if (gRootDomain
->activitySinceSleep()) {
4127 dict
= OSDictionary::withCapacity(1);
4128 secs
= OSNumber::withNumber(1, 32);
4131 dict
->setObject(gIOPMSettingDebugWakeRelativeKey
.get(), secs
.get());
4132 gRootDomain
->setProperties(dict
.get());
4133 MSG("Reverting sleep with relative wake\n");
4137 notifierThread
= NULL
;
4141 //******************************************************************************
4142 // willTellSystemCapabilityDidChange
4144 // IOServicePM calls this from OurChangeTellCapabilityDidChange() when root
4145 // domain is raising its power state, immediately after notifying interested
4146 // drivers and power children.
4147 //******************************************************************************
4150 IOPMrootDomain::willTellSystemCapabilityDidChange( void )
4152 if ((_systemTransitionType
== kSystemTransitionWake
) &&
4153 !CAP_GAIN(kIOPMSystemCapabilityGraphics
)) {
4154 // After powering up drivers, dark->full promotion on the current wake
4155 // transition is no longer possible. That is because the next machine
4156 // state will issue the system capability change messages.
4157 // The darkWakePowerClamped flag may already be set if the system has
4158 // at least one driver that was power clamped due to dark wake.
4159 // This function sets the darkWakePowerClamped flag in case there
4160 // is no power-clamped driver in the system.
4162 // Last opportunity to exit dark wake using:
4163 // requestFullWake( kFullWakeReasonLocalUser );
4165 if (!darkWakePowerClamped
) {
4166 if (darkWakeLogClamp
) {
4170 clock_get_uptime(&now
);
4171 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
4172 absolutetime_to_nanoseconds(now
, &nsec
);
4173 DLOG("dark wake promotion disabled at %u ms\n",
4174 ((int)((nsec
) / NSEC_PER_MSEC
)));
4176 darkWakePowerClamped
= true;
4181 //******************************************************************************
4182 // sleepOnClamshellClosed
4184 // contains the logic to determine if the system should sleep when the clamshell
4186 //******************************************************************************
4189 IOPMrootDomain::shouldSleepOnClamshellClosed( void )
4191 if (!clamshellExists
) {
4195 DLOG("clamshell closed %d, disabled %d/%x, desktopMode %d, ac %d\n",
4196 clamshellClosed
, clamshellDisabled
, clamshellSleepDisableMask
, desktopMode
, acAdaptorConnected
);
4198 return !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) && !clamshellSleepDisableMask
;
4202 IOPMrootDomain::shouldSleepOnRTCAlarmWake( void )
4204 // Called once every RTC/Alarm wake. Device should go to sleep if on clamshell
4205 // closed && battery
4206 if (!clamshellExists
) {
4210 DLOG("shouldSleepOnRTCAlarmWake: clamshell closed %d, disabled %d/%x, desktopMode %d, ac %d\n",
4211 clamshellClosed
, clamshellDisabled
, clamshellSleepDisableMask
, desktopMode
, acAdaptorConnected
);
4213 return !acAdaptorConnected
&& !clamshellSleepDisableMask
;
4217 IOPMrootDomain::sendClientClamshellNotification( void )
4219 /* Only broadcast clamshell alert if clamshell exists. */
4220 if (!clamshellExists
) {
4224 setProperty(kAppleClamshellStateKey
,
4225 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
4227 setProperty(kAppleClamshellCausesSleepKey
,
4228 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
4230 /* Argument to message is a bitfiel of
4231 * ( kClamshellStateBit | kClamshellSleepBit )
4233 messageClients(kIOPMMessageClamshellStateChange
,
4234 (void *)(uintptr_t) ((clamshellClosed
? kClamshellStateBit
: 0)
4235 | (shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)));
4238 //******************************************************************************
4239 // getSleepSupported
4242 //******************************************************************************
4245 IOPMrootDomain::getSleepSupported( void )
4247 return platformSleepSupport
;
4250 //******************************************************************************
4251 // setSleepSupported
4254 //******************************************************************************
4257 IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
4259 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
4260 OSBitOrAtomic(flags
, &platformSleepSupport
);
4263 //******************************************************************************
4264 // setClamShellSleepDisable
4266 //******************************************************************************
4269 IOPMrootDomain::setClamShellSleepDisable( bool disable
, uint32_t bitmask
)
4273 // User client calls this in non-gated context
4274 if (gIOPMWorkLoop
->inGate() == false) {
4275 gIOPMWorkLoop
->runAction(
4276 OSMemberFunctionCast(IOWorkLoop::Action
, this,
4277 &IOPMrootDomain::setClamShellSleepDisable
),
4279 (void *) disable
, (void *)(uintptr_t) bitmask
);
4283 oldMask
= clamshellSleepDisableMask
;
4285 clamshellSleepDisableMask
|= bitmask
;
4287 clamshellSleepDisableMask
&= ~bitmask
;
4289 DLOG("setClamShellSleepDisable(%x->%x)\n", oldMask
, clamshellSleepDisableMask
);
4291 if (clamshellExists
&& clamshellClosed
&&
4292 (clamshellSleepDisableMask
!= oldMask
) &&
4293 (clamshellSleepDisableMask
== 0)) {
4294 handlePowerNotification(kLocalEvalClamshellCommand
);
4298 //******************************************************************************
4302 //******************************************************************************
4305 IOPMrootDomain::wakeFromDoze( void )
4307 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
4310 //******************************************************************************
4313 // Record the earliest scheduled RTC alarm to determine whether a RTC wake
4314 // should be a dark wake or a full wake. Both Maintenance and SleepService
4315 // alarms are dark wake, while AutoWake (WakeByCalendarDate) and DebugWake
4316 // (WakeRelativeToSleep) should trigger a full wake. Scheduled power-on
4317 // PMSettings are ignored.
4319 // Caller serialized using settingsCtrlLock.
4320 //******************************************************************************
4323 IOPMrootDomain::recordRTCAlarm(
4324 const OSSymbol
*type
,
4327 uint32_t previousAlarmMask
= _scheduledAlarmMask
;
4329 if (type
== gIOPMSettingDebugWakeRelativeKey
) {
4330 OSNumber
* n
= OSDynamicCast(OSNumber
, object
);
4332 // Debug wake has highest scheduling priority so it overrides any
4333 // pre-existing alarm.
4334 uint32_t debugSecs
= n
->unsigned32BitValue();
4335 _nextScheduledAlarmType
.reset(type
, OSRetain
);
4336 _nextScheduledAlarmUTC
= debugSecs
;
4338 _debugWakeSeconds
= debugSecs
;
4339 OSBitOrAtomic(kIOPMAlarmBitDebugWake
, &_scheduledAlarmMask
);
4340 DLOG("next alarm (%s) in %u secs\n",
4341 type
->getCStringNoCopy(), debugSecs
);
4343 } else if ((type
== gIOPMSettingAutoWakeCalendarKey
.get()) ||
4344 (type
== gIOPMSettingMaintenanceWakeCalendarKey
.get()) ||
4345 (type
== gIOPMSettingSleepServiceWakeCalendarKey
.get())) {
4346 OSData
* data
= OSDynamicCast(OSData
, object
);
4347 if (data
&& (data
->getLength() == sizeof(IOPMCalendarStruct
))) {
4348 const IOPMCalendarStruct
* cs
;
4349 bool replaceNextAlarm
= false;
4352 cs
= (const IOPMCalendarStruct
*) data
->getBytesNoCopy();
4353 secs
= IOPMConvertCalendarToSeconds(cs
);
4354 DLOG("%s " YMDTF
"\n", type
->getCStringNoCopy(), YMDT(cs
));
4356 // Update the next scheduled alarm type
4357 if ((_nextScheduledAlarmType
== NULL
) ||
4358 ((_nextScheduledAlarmType
!= gIOPMSettingDebugWakeRelativeKey
) &&
4359 (secs
< _nextScheduledAlarmUTC
))) {
4360 replaceNextAlarm
= true;
4363 if (type
== gIOPMSettingAutoWakeCalendarKey
.get()) {
4365 _calendarWakeAlarmUTC
= IOPMConvertCalendarToSeconds(cs
);
4366 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_scheduledAlarmMask
);
4368 // TODO: can this else-block be removed?
4369 _calendarWakeAlarmUTC
= 0;
4370 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_scheduledAlarmMask
);
4373 if (type
== gIOPMSettingMaintenanceWakeCalendarKey
.get()) {
4374 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake
, &_scheduledAlarmMask
);
4376 if (type
== gIOPMSettingSleepServiceWakeCalendarKey
.get()) {
4377 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake
, &_scheduledAlarmMask
);
4380 if (replaceNextAlarm
) {
4381 _nextScheduledAlarmType
.reset(type
, OSRetain
);
4382 _nextScheduledAlarmUTC
= secs
;
4383 DLOG("next alarm (%s) " YMDTF
"\n", type
->getCStringNoCopy(), YMDT(cs
));
4388 if (_scheduledAlarmMask
!= previousAlarmMask
) {
4389 DLOG("scheduled alarm mask 0x%x\n", (uint32_t) _scheduledAlarmMask
);
4396 //******************************************************************************
4399 // Adds a new feature to the supported features dictionary
4400 //******************************************************************************
4403 IOPMrootDomain::publishFeature( const char * feature
)
4405 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
4408 //******************************************************************************
4409 // publishFeature (with supported power source specified)
4411 // Adds a new feature to the supported features dictionary
4412 //******************************************************************************
4415 IOPMrootDomain::publishFeature(
4416 const char *feature
,
4417 uint32_t supportedWhere
,
4418 uint32_t *uniqueFeatureID
)
4420 static uint16_t next_feature_id
= 500;
4422 OSSharedPtr
<OSNumber
> new_feature_data
;
4423 OSNumber
*existing_feature
= NULL
;
4424 OSArray
*existing_feature_arr_raw
= NULL
;
4425 OSSharedPtr
<OSArray
> existing_feature_arr
;
4426 OSObject
*osObj
= NULL
;
4427 uint32_t feature_value
= 0;
4429 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
4431 if (!supportedWhere
) {
4432 // Feature isn't supported anywhere!
4436 if (next_feature_id
> 5000) {
4437 // Far, far too many features!
4441 if (featuresDictLock
) {
4442 IOLockLock(featuresDictLock
);
4445 OSSharedPtr
<OSObject
> origFeaturesProp
= copyProperty(kRootDomainSupportedFeatures
);
4446 OSDictionary
*origFeatures
= OSDynamicCast(OSDictionary
, origFeaturesProp
.get());
4447 OSSharedPtr
<OSDictionary
> features
;
4449 // Create new features dict if necessary
4451 features
= OSDictionary::withDictionary(origFeatures
);
4453 features
= OSDictionary::withCapacity(1);
4456 // Create OSNumber to track new feature
4458 next_feature_id
+= 1;
4459 if (uniqueFeatureID
) {
4460 // We don't really mind if the calling kext didn't give us a place
4461 // to stash their unique id. Many kexts don't plan to unload, and thus
4462 // have no need to remove themselves later.
4463 *uniqueFeatureID
= next_feature_id
;
4466 feature_value
= (uint32_t)next_feature_id
;
4467 feature_value
<<= 16;
4468 feature_value
+= supportedWhere
;
4470 new_feature_data
= OSNumber::withNumber(
4471 (unsigned long long)feature_value
, 32);
4473 // Does features object already exist?
4474 if ((osObj
= features
->getObject(feature
))) {
4475 if ((existing_feature
= OSDynamicCast(OSNumber
, osObj
))) {
4476 // We need to create an OSArray to hold the now 2 elements.
4477 existing_feature_arr
= OSArray::withObjects(
4478 (const OSObject
**)&existing_feature
, 1, 2);
4479 } else if ((existing_feature_arr_raw
= OSDynamicCast(OSArray
, osObj
))) {
4480 // Add object to existing array
4481 existing_feature_arr
= OSArray::withArray(
4482 existing_feature_arr_raw
,
4483 existing_feature_arr_raw
->getCount() + 1);
4486 if (existing_feature_arr
) {
4487 existing_feature_arr
->setObject(new_feature_data
.get());
4488 features
->setObject(feature
, existing_feature_arr
.get());
4491 // The easy case: no previously existing features listed. We simply
4492 // set the OSNumber at key 'feature' and we're on our way.
4493 features
->setObject(feature
, new_feature_data
.get());
4496 setProperty(kRootDomainSupportedFeatures
, features
.get());
4498 if (featuresDictLock
) {
4499 IOLockUnlock(featuresDictLock
);
4502 // Notify EnergySaver and all those in user space so they might
4503 // re-populate their feature specific UI
4504 if (pmPowerStateQueue
) {
4505 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
4509 //******************************************************************************
4510 // removePublishedFeature
4512 // Removes previously published feature
4513 //******************************************************************************
4516 IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
4518 IOReturn ret
= kIOReturnError
;
4519 uint32_t feature_value
= 0;
4520 uint16_t feature_id
= 0;
4521 bool madeAChange
= false;
4523 OSSymbol
*dictKey
= NULL
;
4524 OSSharedPtr
<OSCollectionIterator
> dictIterator
;
4525 OSArray
*arrayMember
= NULL
;
4526 OSNumber
*numberMember
= NULL
;
4527 OSObject
*osObj
= NULL
;
4528 OSNumber
*osNum
= NULL
;
4529 OSSharedPtr
<OSArray
> arrayMemberCopy
;
4531 if (kBadPMFeatureID
== removeFeatureID
) {
4532 return kIOReturnNotFound
;
4535 if (featuresDictLock
) {
4536 IOLockLock(featuresDictLock
);
4539 OSSharedPtr
<OSObject
> origFeaturesProp
= copyProperty(kRootDomainSupportedFeatures
);
4540 OSDictionary
*origFeatures
= OSDynamicCast(OSDictionary
, origFeaturesProp
.get());
4541 OSSharedPtr
<OSDictionary
> features
;
4544 // Any modifications to the dictionary are made to the copy to prevent
4545 // races & crashes with userland clients. Dictionary updated
4546 // automically later.
4547 features
= OSDictionary::withDictionary(origFeatures
);
4550 ret
= kIOReturnNotFound
;
4554 // We iterate 'features' dictionary looking for an entry tagged
4555 // with 'removeFeatureID'. If found, we remove it from our tracking
4556 // structures and notify the OS via a general interest message.
4558 dictIterator
= OSCollectionIterator::withCollection(features
.get());
4559 if (!dictIterator
) {
4563 while ((dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject()))) {
4564 osObj
= features
->getObject(dictKey
);
4566 // Each Feature is either tracked by an OSNumber
4567 if (osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
))) {
4568 feature_value
= numberMember
->unsigned32BitValue();
4569 feature_id
= (uint16_t)(feature_value
>> 16);
4571 if (feature_id
== (uint16_t)removeFeatureID
) {
4573 features
->removeObject(dictKey
);
4578 // Or tracked by an OSArray of OSNumbers
4579 } else if (osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
))) {
4580 unsigned int arrayCount
= arrayMember
->getCount();
4582 for (unsigned int i
= 0; i
< arrayCount
; i
++) {
4583 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
4588 feature_value
= osNum
->unsigned32BitValue();
4589 feature_id
= (uint16_t)(feature_value
>> 16);
4591 if (feature_id
== (uint16_t)removeFeatureID
) {
4593 if (1 == arrayCount
) {
4594 // If the array only contains one element, remove
4596 features
->removeObject(dictKey
);
4598 // Otherwise remove the element from a copy of the array.
4599 arrayMemberCopy
= OSArray::withArray(arrayMember
);
4600 if (arrayMemberCopy
) {
4601 arrayMemberCopy
->removeObject(i
);
4602 features
->setObject(dictKey
, arrayMemberCopy
.get());
4614 ret
= kIOReturnSuccess
;
4616 setProperty(kRootDomainSupportedFeatures
, features
.get());
4618 // Notify EnergySaver and all those in user space so they might
4619 // re-populate their feature specific UI
4620 if (pmPowerStateQueue
) {
4621 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
4624 ret
= kIOReturnNotFound
;
4628 if (featuresDictLock
) {
4629 IOLockUnlock(featuresDictLock
);
4634 //******************************************************************************
4635 // publishPMSetting (private)
4637 // Should only be called by PMSettingObject to publish a PM Setting as a
4638 // supported feature.
4639 //******************************************************************************
4642 IOPMrootDomain::publishPMSetting(
4643 const OSSymbol
* feature
, uint32_t where
, uint32_t * featureID
)
4645 if (noPublishPMSettings
&&
4646 (noPublishPMSettings
->getNextIndexOfObject(feature
, 0) != (unsigned int)-1)) {
4647 // Setting found in noPublishPMSettings array
4648 *featureID
= kBadPMFeatureID
;
4653 feature
->getCStringNoCopy(), where
, featureID
);
4656 //******************************************************************************
4657 // setPMSetting (private)
4659 // Internal helper to relay PM settings changes from user space to individual
4660 // drivers. Should be called only by IOPMrootDomain::setProperties.
4661 //******************************************************************************
4664 IOPMrootDomain::setPMSetting(
4665 const OSSymbol
*type
,
4668 PMSettingCallEntry
*entries
= NULL
;
4669 OSSharedPtr
<OSArray
> chosen
;
4670 const OSArray
*array
;
4671 PMSettingObject
*pmso
;
4672 thread_t thisThread
;
4673 int i
, j
, count
, capacity
;
4678 return kIOReturnBadArgument
;
4683 // Update settings dict so changes are visible from copyPMSetting().
4684 fPMSettingsDict
->setObject(type
, object
);
4686 // Prep all PMSetting objects with the given 'type' for callout.
4687 array
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(type
));
4688 if (!array
|| ((capacity
= array
->getCount()) == 0)) {
4692 // Array to retain PMSetting objects targeted for callout.
4693 chosen
= OSArray::withCapacity(capacity
);
4695 goto unlock_exit
; // error
4697 entries
= IONew(PMSettingCallEntry
, capacity
);
4699 goto unlock_exit
; // error
4701 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
4703 thisThread
= current_thread();
4705 for (i
= 0, j
= 0; i
< capacity
; i
++) {
4706 pmso
= (PMSettingObject
*) array
->getObject(i
);
4707 if (pmso
->disabled
) {
4710 entries
[j
].thread
= thisThread
;
4711 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
4712 chosen
->setObject(pmso
);
4722 // Call each pmso in the chosen array.
4723 for (i
= 0; i
< count
; i
++) {
4724 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
4725 ret
= pmso
->dispatchPMSetting(type
, object
);
4726 if (ret
== kIOReturnSuccess
) {
4727 // At least one setting handler was successful
4729 #if DEVELOPMENT || DEBUG
4731 // Log the handler and kext that failed
4732 OSSharedPtr
<const OSSymbol
> kextName
= copyKextIdentifierWithAddress((vm_address_t
) pmso
->func
);
4734 DLOG("PMSetting(%s) error 0x%x from %s\n",
4735 type
->getCStringNoCopy(), ret
, kextName
->getCStringNoCopy());
4742 for (i
= 0; i
< count
; i
++) {
4743 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
4744 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
4745 if (pmso
->waitThread
) {
4746 PMSETTING_WAKEUP(pmso
);
4751 recordRTCAlarm(type
, object
);
4757 IODelete(entries
, PMSettingCallEntry
, capacity
);
4760 return kIOReturnSuccess
;
4763 //******************************************************************************
4764 // copyPMSetting (public)
4766 // Allows kexts to safely read setting values, without being subscribed to
4768 //******************************************************************************
4770 OSSharedPtr
<OSObject
>
4771 IOPMrootDomain::copyPMSetting(
4772 OSSymbol
*whichSetting
)
4774 OSSharedPtr
<OSObject
> obj
;
4776 if (!whichSetting
) {
4781 obj
.reset(fPMSettingsDict
->getObject(whichSetting
), OSRetain
);
4787 //******************************************************************************
4788 // registerPMSettingController (public)
4790 // direct wrapper to registerPMSettingController with uint32_t power source arg
4791 //******************************************************************************
4794 IOPMrootDomain::registerPMSettingController(
4795 const OSSymbol
* settings
[],
4796 IOPMSettingControllerCallback func
,
4801 return registerPMSettingController(
4803 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
4804 func
, target
, refcon
, handle
);
4807 //******************************************************************************
4808 // registerPMSettingController (public)
4810 // Kexts may register for notifications when a particular setting is changed.
4811 // A list of settings is available in IOPM.h.
4813 // * settings - An OSArray containing OSSymbols. Caller should populate this
4814 // array with a list of settings caller wants notifications from.
4815 // * func - A C function callback of the type IOPMSettingControllerCallback
4816 // * target - caller may provide an OSObject *, which PM will pass as an
4817 // target to calls to "func"
4818 // * refcon - caller may provide an void *, which PM will pass as an
4819 // argument to calls to "func"
4820 // * handle - This is a return argument. We will populate this pointer upon
4821 // call success. Hold onto this and pass this argument to
4822 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
4824 // kIOReturnSuccess on success
4825 //******************************************************************************
4828 IOPMrootDomain::registerPMSettingController(
4829 const OSSymbol
* settings
[],
4830 uint32_t supportedPowerSources
,
4831 IOPMSettingControllerCallback func
,
4836 PMSettingObject
*pmso
= NULL
;
4837 OSObject
*pmsh
= NULL
;
4840 if (NULL
== settings
||
4843 return kIOReturnBadArgument
;
4846 pmso
= PMSettingObject::pmSettingObject(
4847 (IOPMrootDomain
*) this, func
, target
,
4848 refcon
, supportedPowerSources
, settings
, &pmsh
);
4852 return kIOReturnInternalError
;
4856 for (i
= 0; settings
[i
]; i
++) {
4857 OSSharedPtr
<OSArray
> newList
;
4858 OSArray
*list
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(settings
[i
]));
4860 // New array of callbacks for this setting
4861 newList
= OSArray::withCapacity(1);
4862 settingsCallbacks
->setObject(settings
[i
], newList
.get());
4863 list
= newList
.get();
4866 // Add caller to the callback list
4867 list
->setObject(pmso
);
4871 // Return handle to the caller, the setting object is private.
4874 return kIOReturnSuccess
;
4877 //******************************************************************************
4878 // deregisterPMSettingObject (private)
4880 // Only called from PMSettingObject.
4881 //******************************************************************************
4884 IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
4886 thread_t thisThread
= current_thread();
4887 PMSettingCallEntry
*callEntry
;
4888 OSSharedPtr
<OSCollectionIterator
> iter
;
4896 pmso
->disabled
= true;
4898 // Wait for all callout threads to finish.
4901 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
4903 if (callEntry
->thread
!= thisThread
) {
4909 assert(NULL
== pmso
->waitThread
);
4910 pmso
->waitThread
= thisThread
;
4911 PMSETTING_WAIT(pmso
);
4912 pmso
->waitThread
= NULL
;
4916 // Search each PM settings array in the kernel.
4917 iter
= OSCollectionIterator::withCollection(settingsCallbacks
.get());
4919 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject()))) {
4920 array
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(sym
));
4921 index
= array
->getNextIndexOfObject(pmso
, 0);
4923 array
->removeObject(index
);
4933 //******************************************************************************
4934 // informCPUStateChange
4936 // Call into PM CPU code so that CPU power savings may dynamically adjust for
4937 // running on battery, with the lid closed, etc.
4939 // informCPUStateChange is a no-op on non x86 systems
4940 // only x86 has explicit support in the IntelCPUPowerManagement kext
4941 //******************************************************************************
4944 IOPMrootDomain::informCPUStateChange(
4948 #if defined(__i386__) || defined(__x86_64__)
4950 pmioctlVariableInfo_t varInfoStruct
;
4952 const char *varNameStr
= NULL
;
4953 int32_t *varIndex
= NULL
;
4955 if (kInformAC
== type
) {
4956 varNameStr
= kIOPMRootDomainBatPowerCString
;
4957 varIndex
= &idxPMCPULimitedPower
;
4958 } else if (kInformLid
== type
) {
4959 varNameStr
= kIOPMRootDomainLidCloseCString
;
4960 varIndex
= &idxPMCPUClamshell
;
4965 // Set the new value!
4966 // pmCPUControl will assign us a new ID if one doesn't exist yet
4967 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
4968 varInfoStruct
.varID
= *varIndex
;
4969 varInfoStruct
.varType
= vBool
;
4970 varInfoStruct
.varInitValue
= value
;
4971 varInfoStruct
.varCurValue
= value
;
4972 strlcpy((char *)varInfoStruct
.varName
,
4973 (const char *)varNameStr
,
4974 sizeof(varInfoStruct
.varName
));
4977 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
4979 // pmCPU only assigns numerical id's when a new varName is specified
4981 && (*varIndex
== kCPUUnknownIndex
)) {
4982 // pmCPUControl has assigned us a new variable ID.
4983 // Let's re-read the structure we just SET to learn that ID.
4984 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
4986 if (0 == pmCPUret
) {
4987 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
4988 *varIndex
= varInfoStruct
.varID
;
4994 #endif /* __i386__ || __x86_64__ */
4998 // MARK: Deep Sleep Policy
5002 //******************************************************************************
5003 // evaluateSystemSleepPolicy
5004 //******************************************************************************
5006 #define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
5010 kIOPMSleepFlagHibernate
= 0x00000001,
5011 kIOPMSleepFlagSleepTimerEnable
= 0x00000002
5014 struct IOPMSystemSleepPolicyEntry
{
5015 uint32_t factorMask
;
5016 uint32_t factorBits
;
5017 uint32_t sleepFlags
;
5018 uint32_t wakeEvents
;
5019 } __attribute__((packed
));
5021 struct IOPMSystemSleepPolicyTable
{
5024 uint16_t entryCount
;
5025 IOPMSystemSleepPolicyEntry entries
[];
5026 } __attribute__((packed
));
5029 kIOPMSleepAttributeHibernateSetup
= 0x00000001,
5030 kIOPMSleepAttributeHibernateSleep
= 0x00000002
5034 getSleepTypeAttributes( uint32_t sleepType
)
5036 static const uint32_t sleepTypeAttributes
[kIOPMSleepTypeLast
] =
5041 /* safesleep */ kIOPMSleepAttributeHibernateSetup
,
5042 /* hibernate */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
5043 /* standby */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
5044 /* poweroff */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
5048 if (sleepType
>= kIOPMSleepTypeLast
) {
5052 return sleepTypeAttributes
[sleepType
];
5056 IOPMrootDomain::evaluateSystemSleepPolicy(
5057 IOPMSystemSleepParameters
* params
, int sleepPhase
, uint32_t * hibMode
)
5059 #define SLEEP_FACTOR(x) {(uint32_t) kIOPMSleepFactor ## x, #x}
5061 static const IONamedValue factorValues
[] = {
5062 SLEEP_FACTOR( SleepTimerWake
),
5063 SLEEP_FACTOR( LidOpen
),
5064 SLEEP_FACTOR( ACPower
),
5065 SLEEP_FACTOR( BatteryLow
),
5066 SLEEP_FACTOR( StandbyNoDelay
),
5067 SLEEP_FACTOR( StandbyForced
),
5068 SLEEP_FACTOR( StandbyDisabled
),
5069 SLEEP_FACTOR( USBExternalDevice
),
5070 SLEEP_FACTOR( BluetoothHIDDevice
),
5071 SLEEP_FACTOR( ExternalMediaMounted
),
5072 SLEEP_FACTOR( ThunderboltDevice
),
5073 SLEEP_FACTOR( RTCAlarmScheduled
),
5074 SLEEP_FACTOR( MagicPacketWakeEnabled
),
5075 SLEEP_FACTOR( HibernateForced
),
5076 SLEEP_FACTOR( AutoPowerOffDisabled
),
5077 SLEEP_FACTOR( AutoPowerOffForced
),
5078 SLEEP_FACTOR( ExternalDisplay
),
5079 SLEEP_FACTOR( NetworkKeepAliveActive
),
5080 SLEEP_FACTOR( LocalUserActivity
),
5081 SLEEP_FACTOR( HibernateFailed
),
5082 SLEEP_FACTOR( ThermalWarning
),
5083 SLEEP_FACTOR( DisplayCaptured
),
5087 const IOPMSystemSleepPolicyTable
* pt
;
5088 OSSharedPtr
<OSObject
> prop
;
5089 OSData
* policyData
;
5090 uint64_t currentFactors
= 0;
5091 char currentFactorsBuf
[512];
5092 uint32_t standbyDelay
= 0;
5093 uint32_t powerOffDelay
= 0;
5094 uint32_t powerOffTimer
= 0;
5095 uint32_t standbyTimer
= 0;
5097 bool standbyEnabled
;
5098 bool powerOffEnabled
;
5101 // Get platform's sleep policy table
5102 if (!gSleepPolicyHandler
) {
5103 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
5109 // Fetch additional settings
5110 standbyEnabled
= (getSleepOption(kIOPMDeepSleepDelayKey
, &standbyDelay
)
5111 && propertyHasValue(kIOPMDeepSleepEnabledKey
, kOSBooleanTrue
));
5112 powerOffEnabled
= (getSleepOption(kIOPMAutoPowerOffDelayKey
, &powerOffDelay
)
5113 && propertyHasValue(kIOPMAutoPowerOffEnabledKey
, kOSBooleanTrue
));
5114 if (!getSleepOption(kIOPMAutoPowerOffTimerKey
, &powerOffTimer
)) {
5115 powerOffTimer
= powerOffDelay
;
5117 if (!getSleepOption(kIOPMDeepSleepTimerKey
, &standbyTimer
)) {
5118 standbyTimer
= standbyDelay
;
5121 DLOG("phase %d, standby %d delay %u timer %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
5122 sleepPhase
, standbyEnabled
, standbyDelay
, standbyTimer
,
5123 powerOffEnabled
, powerOffDelay
, powerOffTimer
, *hibMode
);
5125 currentFactorsBuf
[0] = 0;
5126 // pmset level overrides
5127 if ((*hibMode
& kIOHibernateModeOn
) == 0) {
5128 if (!gSleepPolicyHandler
) {
5129 standbyEnabled
= false;
5130 powerOffEnabled
= false;
5132 } else if (!(*hibMode
& kIOHibernateModeSleep
)) {
5133 // Force hibernate (i.e. mode 25)
5134 // If standby is enabled, force standy.
5135 // If poweroff is enabled, force poweroff.
5136 if (standbyEnabled
) {
5137 currentFactors
|= kIOPMSleepFactorStandbyForced
;
5138 } else if (powerOffEnabled
) {
5139 currentFactors
|= kIOPMSleepFactorAutoPowerOffForced
;
5141 currentFactors
|= kIOPMSleepFactorHibernateForced
;
5145 // Current factors based on environment and assertions
5146 if (sleepTimerMaintenance
) {
5147 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
5149 if (standbyEnabled
&& sleepToStandby
&& !gSleepPolicyHandler
) {
5150 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
5152 if (!clamshellClosed
) {
5153 currentFactors
|= kIOPMSleepFactorLidOpen
;
5155 if (acAdaptorConnected
) {
5156 currentFactors
|= kIOPMSleepFactorACPower
;
5158 if (lowBatteryCondition
) {
5160 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
5161 if ((hibernateMode
& kIOHibernateModeOn
) == 0) {
5162 DLOG("HibernateMode is 0. Not sending LowBattery factor to IOPPF\n");
5164 currentFactors
|= kIOPMSleepFactorBatteryLow
;
5167 if (!standbyDelay
|| !standbyTimer
) {
5168 currentFactors
|= kIOPMSleepFactorStandbyNoDelay
;
5170 if (standbyNixed
|| !standbyEnabled
) {
5171 currentFactors
|= kIOPMSleepFactorStandbyDisabled
;
5174 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
5175 currentFactors
&= ~kIOPMSleepFactorSleepTimerWake
;
5177 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
5178 kIOPMDriverAssertionLevelOff
) {
5179 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
5181 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
5182 kIOPMDriverAssertionLevelOff
) {
5183 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
5185 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
5186 kIOPMDriverAssertionLevelOff
) {
5187 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
5189 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) !=
5190 kIOPMDriverAssertionLevelOff
) {
5191 currentFactors
|= kIOPMSleepFactorThunderboltDevice
;
5193 if (_scheduledAlarmMask
!= 0) {
5194 currentFactors
|= kIOPMSleepFactorRTCAlarmScheduled
;
5196 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit
) !=
5197 kIOPMDriverAssertionLevelOff
) {
5198 currentFactors
|= kIOPMSleepFactorMagicPacketWakeEnabled
;
5200 #define TCPKEEPALIVE 1
5202 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit
) !=
5203 kIOPMDriverAssertionLevelOff
) {
5204 currentFactors
|= kIOPMSleepFactorNetworkKeepAliveActive
;
5207 if (!powerOffEnabled
) {
5208 currentFactors
|= kIOPMSleepFactorAutoPowerOffDisabled
;
5211 currentFactors
|= kIOPMSleepFactorExternalDisplay
;
5213 if (userWasActive
) {
5214 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
5216 if (darkWakeHibernateError
&& !CAP_HIGHEST(kIOPMSystemCapabilityGraphics
)) {
5217 currentFactors
|= kIOPMSleepFactorHibernateFailed
;
5219 if (thermalWarningState
) {
5220 currentFactors
|= kIOPMSleepFactorThermalWarning
;
5223 for (int factorBit
= 0; factorBit
< (8 * sizeof(uint32_t)); factorBit
++) {
5224 uint32_t factor
= 1 << factorBit
;
5225 if (factor
& currentFactors
) {
5226 strlcat(currentFactorsBuf
, ", ", sizeof(currentFactorsBuf
));
5227 strlcat(currentFactorsBuf
, IOFindNameForValue(factor
, factorValues
), sizeof(currentFactorsBuf
));
5230 DLOG("sleep factors 0x%llx%s\n", currentFactors
, currentFactorsBuf
);
5232 if (gSleepPolicyHandler
) {
5233 uint32_t savedHibernateMode
;
5236 if (!gSleepPolicyVars
) {
5237 gSleepPolicyVars
= IONew(IOPMSystemSleepPolicyVariables
, 1);
5238 if (!gSleepPolicyVars
) {
5241 bzero(gSleepPolicyVars
, sizeof(*gSleepPolicyVars
));
5243 gSleepPolicyVars
->signature
= kIOPMSystemSleepPolicySignature
;
5244 gSleepPolicyVars
->version
= kIOPMSystemSleepPolicyVersion
;
5245 gSleepPolicyVars
->currentCapability
= _currentCapability
;
5246 gSleepPolicyVars
->highestCapability
= _highestCapability
;
5247 gSleepPolicyVars
->sleepFactors
= currentFactors
;
5248 gSleepPolicyVars
->sleepReason
= lastSleepReason
;
5249 gSleepPolicyVars
->sleepPhase
= sleepPhase
;
5250 gSleepPolicyVars
->standbyDelay
= standbyDelay
;
5251 gSleepPolicyVars
->standbyTimer
= standbyTimer
;
5252 gSleepPolicyVars
->poweroffDelay
= powerOffDelay
;
5253 gSleepPolicyVars
->scheduledAlarms
= _scheduledAlarmMask
| _userScheduledAlarmMask
;
5254 gSleepPolicyVars
->poweroffTimer
= powerOffTimer
;
5256 if (kIOPMSleepPhase0
== sleepPhase
) {
5257 // preserve hibernateMode
5258 savedHibernateMode
= gSleepPolicyVars
->hibernateMode
;
5259 gSleepPolicyVars
->hibernateMode
= *hibMode
;
5260 } else if (kIOPMSleepPhase1
== sleepPhase
) {
5261 // use original hibernateMode for phase2
5262 gSleepPolicyVars
->hibernateMode
= *hibMode
;
5265 result
= gSleepPolicyHandler(gSleepPolicyTarget
, gSleepPolicyVars
, params
);
5267 if (kIOPMSleepPhase0
== sleepPhase
) {
5268 // restore hibernateMode
5269 gSleepPolicyVars
->hibernateMode
= savedHibernateMode
;
5272 if ((result
!= kIOReturnSuccess
) ||
5273 (kIOPMSleepTypeInvalid
== params
->sleepType
) ||
5274 (params
->sleepType
>= kIOPMSleepTypeLast
) ||
5275 (kIOPMSystemSleepParametersVersion
!= params
->version
)) {
5276 MSG("sleep policy handler error\n");
5280 if ((getSleepTypeAttributes(params
->sleepType
) &
5281 kIOPMSleepAttributeHibernateSetup
) &&
5282 ((*hibMode
& kIOHibernateModeOn
) == 0)) {
5283 *hibMode
|= (kIOHibernateModeOn
| kIOHibernateModeSleep
);
5286 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
5287 params
->version
, params
->sleepType
, params
->sleepFlags
,
5288 params
->ecWakeEvents
, params
->ecWakeTimer
, params
->ecPoweroffTimer
);
5293 // Policy table is meaningless without standby enabled
5294 if (!standbyEnabled
) {
5298 // Validate the sleep policy table
5299 policyData
= OSDynamicCast(OSData
, prop
.get());
5300 if (!policyData
|| (policyData
->getLength() <= sizeof(IOPMSystemSleepPolicyTable
))) {
5304 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
5305 if ((pt
->signature
!= kIOPMSystemSleepPolicySignature
) ||
5306 (pt
->version
!= 1) || (0 == pt
->entryCount
)) {
5310 if (((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
5311 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
))) {
5315 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++) {
5316 const IOPMSystemSleepPolicyEntry
* entry
= &pt
->entries
[i
];
5317 mismatch
= (((uint32_t)currentFactors
^ entry
->factorBits
) & entry
->factorMask
);
5319 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
5320 entry
->factorMask
, entry
->factorBits
,
5321 entry
->sleepFlags
, entry
->wakeEvents
, mismatch
);
5326 DLOG("^ found match\n");
5329 params
->version
= kIOPMSystemSleepParametersVersion
;
5330 params
->reserved1
= 1;
5331 if (entry
->sleepFlags
& kIOPMSleepFlagHibernate
) {
5332 params
->sleepType
= kIOPMSleepTypeStandby
;
5334 params
->sleepType
= kIOPMSleepTypeNormalSleep
;
5337 params
->ecWakeEvents
= entry
->wakeEvents
;
5338 if (entry
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
) {
5339 if (kIOPMSleepPhase2
== sleepPhase
) {
5340 clock_sec_t now_secs
= gIOLastSleepTime
.tv_sec
;
5342 if (!_standbyTimerResetSeconds
||
5343 (now_secs
<= _standbyTimerResetSeconds
)) {
5344 // Reset standby timer adjustment
5345 _standbyTimerResetSeconds
= now_secs
;
5346 DLOG("standby delay %u, reset %u\n",
5347 standbyDelay
, (uint32_t) _standbyTimerResetSeconds
);
5348 } else if (standbyDelay
) {
5349 // Shorten the standby delay timer
5350 clock_sec_t elapsed
= now_secs
- _standbyTimerResetSeconds
;
5351 if (standbyDelay
> elapsed
) {
5352 standbyDelay
-= elapsed
;
5354 standbyDelay
= 1; // must be > 0
5356 DLOG("standby delay %u, elapsed %u\n",
5357 standbyDelay
, (uint32_t) elapsed
);
5360 params
->ecWakeTimer
= standbyDelay
;
5361 } else if (kIOPMSleepPhase2
== sleepPhase
) {
5362 // A sleep that does not enable the sleep timer will reset
5363 // the standby delay adjustment.
5364 _standbyTimerResetSeconds
= 0;
5373 static IOPMSystemSleepParameters gEarlySystemSleepParams
;
5376 IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
5378 // Evaluate early (priority interest phase), before drivers sleep.
5380 DLOG("%s\n", __FUNCTION__
);
5381 removeProperty(kIOPMSystemSleepParametersKey
);
5383 // Full wake resets the standby timer delay adjustment
5384 if (_highestCapability
& kIOPMSystemCapabilityGraphics
) {
5385 _standbyTimerResetSeconds
= 0;
5388 hibernateDisabled
= false;
5390 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
5392 // Save for late evaluation if sleep is aborted
5393 bzero(&gEarlySystemSleepParams
, sizeof(gEarlySystemSleepParams
));
5395 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams
, kIOPMSleepPhase1
,
5397 if (!hibernateRetry
&&
5398 ((getSleepTypeAttributes(gEarlySystemSleepParams
.sleepType
) &
5399 kIOPMSleepAttributeHibernateSetup
) == 0)) {
5400 // skip hibernate setup
5401 hibernateDisabled
= true;
5405 // Publish IOPMSystemSleepType
5406 uint32_t sleepType
= gEarlySystemSleepParams
.sleepType
;
5407 if (sleepType
== kIOPMSleepTypeInvalid
) {
5409 sleepType
= kIOPMSleepTypeNormalSleep
;
5410 if (hibernateMode
& kIOHibernateModeOn
) {
5411 sleepType
= (hibernateMode
& kIOHibernateModeSleep
) ?
5412 kIOPMSleepTypeSafeSleep
: kIOPMSleepTypeHibernate
;
5414 } else if ((sleepType
== kIOPMSleepTypeStandby
) &&
5415 (gEarlySystemSleepParams
.ecPoweroffTimer
)) {
5416 // report the lowest possible sleep state
5417 sleepType
= kIOPMSleepTypePowerOff
;
5420 setProperty(kIOPMSystemSleepTypeKey
, sleepType
, 32);
5424 IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
5426 IOPMSystemSleepParameters params
;
5427 OSSharedPtr
<OSData
> paramsData
;
5429 // Evaluate sleep policy after sleeping drivers but before platform sleep.
5431 DLOG("%s\n", __FUNCTION__
);
5433 bzero(¶ms
, sizeof(params
));
5435 if (evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase2
, &hibernateMode
)) {
5436 if ((kIOPMSleepTypeStandby
== params
.sleepType
)
5437 && gIOHibernateStandbyDisabled
&& gSleepPolicyVars
5438 && (!((kIOPMSleepFactorStandbyForced
| kIOPMSleepFactorAutoPowerOffForced
| kIOPMSleepFactorHibernateForced
)
5439 & gSleepPolicyVars
->sleepFactors
))) {
5440 standbyNixed
= true;
5444 || ((hibernateDisabled
|| hibernateAborted
) &&
5445 (getSleepTypeAttributes(params
.sleepType
) &
5446 kIOPMSleepAttributeHibernateSetup
))) {
5447 // Final evaluation picked a state requiring hibernation,
5448 // but hibernate isn't going to proceed. Arm a short sleep using
5449 // the early non-hibernate sleep parameters.
5450 bcopy(&gEarlySystemSleepParams
, ¶ms
, sizeof(params
));
5451 params
.sleepType
= kIOPMSleepTypeAbortedSleep
;
5452 params
.ecWakeTimer
= 1;
5456 // Set hibernateRetry flag to force hibernate setup on the
5458 hibernateRetry
= true;
5460 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d, standbyNixed %d\n",
5461 params
.ecWakeTimer
, hibernateDisabled
, hibernateAborted
, standbyNixed
);
5463 hibernateRetry
= false;
5466 if (kIOPMSleepTypeAbortedSleep
!= params
.sleepType
) {
5467 resetTimers
= false;
5470 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
5472 setProperty(kIOPMSystemSleepParametersKey
, paramsData
.get());
5475 if (getSleepTypeAttributes(params
.sleepType
) &
5476 kIOPMSleepAttributeHibernateSleep
) {
5477 // Disable sleep to force hibernation
5478 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
5484 IOPMrootDomain::getHibernateSettings(
5485 uint32_t * hibernateModePtr
,
5486 uint32_t * hibernateFreeRatio
,
5487 uint32_t * hibernateFreeTime
)
5489 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
5490 // has updated the hibernateDisabled flag.
5492 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateModePtr
);
5493 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
5494 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
5495 if (hibernateDisabled
) {
5496 *hibernateModePtr
= 0;
5497 } else if (gSleepPolicyHandler
) {
5498 *hibernateModePtr
= hibernateMode
;
5500 DLOG("hibernateMode 0x%x\n", *hibernateModePtr
);
5505 IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
5507 OSSharedPtr
<OSObject
> optionsProp
;
5508 OSDictionary
* optionsDict
;
5509 OSSharedPtr
<OSObject
> obj
;
5513 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
5514 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
.get());
5517 obj
.reset(optionsDict
->getObject(key
), OSRetain
);
5520 obj
= copyProperty(key
);
5523 if ((num
= OSDynamicCast(OSNumber
, obj
.get()))) {
5524 *option
= num
->unsigned32BitValue();
5526 } else if (OSDynamicCast(OSBoolean
, obj
.get())) {
5527 *option
= (obj
== kOSBooleanTrue
) ? 1 : 0;
5534 #endif /* HIBERNATION */
5537 IOPMrootDomain::getSystemSleepType( uint32_t * sleepType
, uint32_t * standbyTimer
)
5540 IOPMSystemSleepParameters params
;
5541 uint32_t hibMode
= 0;
5544 if (gIOPMWorkLoop
->inGate() == false) {
5545 IOReturn ret
= gIOPMWorkLoop
->runAction(
5546 OSMemberFunctionCast(IOWorkLoop::Action
, this,
5547 &IOPMrootDomain::getSystemSleepType
),
5549 (void *) sleepType
, (void *) standbyTimer
);
5553 getSleepOption(kIOHibernateModeKey
, &hibMode
);
5554 bzero(¶ms
, sizeof(params
));
5556 ok
= evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase0
, &hibMode
);
5558 *sleepType
= params
.sleepType
;
5559 if (!getSleepOption(kIOPMDeepSleepTimerKey
, standbyTimer
) &&
5560 !getSleepOption(kIOPMDeepSleepDelayKey
, standbyTimer
)) {
5561 DLOG("Standby delay is not set\n");
5564 return kIOReturnSuccess
;
5568 return kIOReturnUnsupported
;
5572 // MARK: Shutdown and Restart
5574 //******************************************************************************
5575 // handlePlatformHaltRestart
5577 //******************************************************************************
5579 // Phases while performing shutdown/restart
5582 kNotifyPriorityClients
= 0x10,
5583 kNotifyPowerPlaneDrivers
= 0x20,
5584 kNotifyHaltRestartAction
= 0x30,
5589 struct HaltRestartApplierContext
{
5590 IOPMrootDomain
* RootDomain
;
5591 unsigned long PowerState
;
5592 IOPMPowerFlags PowerFlags
;
5595 const char * LogString
;
5596 shutdownPhase_t phase
;
5598 IOServiceInterestHandler handler
;
5602 shutdownPhase2String(shutdownPhase_t phase
)
5606 return "Notifications completed";
5607 case kNotifyPriorityClients
:
5608 return "Notifying priority clients";
5609 case kNotifyPowerPlaneDrivers
:
5610 return "Notifying power plane drivers";
5611 case kNotifyHaltRestartAction
:
5612 return "Notifying HaltRestart action handlers";
5614 return "Quiescing PM";
5621 platformHaltRestartApplier( OSObject
* object
, void * context
)
5623 IOPowerStateChangeNotification notify
;
5624 HaltRestartApplierContext
* ctx
;
5625 AbsoluteTime startTime
, elapsedTime
;
5628 ctx
= (HaltRestartApplierContext
*) context
;
5630 _IOServiceInterestNotifier
* notifier
;
5631 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
5632 memset(¬ify
, 0, sizeof(notify
));
5633 notify
.powerRef
= (void *)(uintptr_t)ctx
->Counter
;
5634 notify
.returnValue
= 0;
5635 notify
.stateNumber
= ctx
->PowerState
;
5636 notify
.stateFlags
= ctx
->PowerFlags
;
5639 ctx
->handler
= notifier
->handler
;
5642 clock_get_uptime(&startTime
);
5643 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
5644 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
5646 if ((deltaTime
> kPMHaltTimeoutMS
) && notifier
) {
5647 LOG("%s handler %p took %u ms\n",
5648 ctx
->LogString
, OBFUSCATE(notifier
->handler
), deltaTime
);
5649 halt_log_enter("PowerOff/Restart message to priority client", (const void *) notifier
->handler
, elapsedTime
);
5652 ctx
->handler
= NULL
;
5657 quiescePowerTreeCallback( void * target
, void * param
)
5659 IOLockLock(gPMHaltLock
);
5661 thread_wakeup(param
);
5662 IOLockUnlock(gPMHaltLock
);
5666 IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
5668 AbsoluteTime startTime
, elapsedTime
;
5671 memset(&gHaltRestartCtx
, 0, sizeof(gHaltRestartCtx
));
5672 gHaltRestartCtx
.RootDomain
= this;
5674 clock_get_uptime(&startTime
);
5677 case kPEUPSDelayHaltCPU
:
5678 gHaltRestartCtx
.PowerState
= OFF_STATE
;
5679 gHaltRestartCtx
.MessageType
= kIOMessageSystemWillPowerOff
;
5680 gHaltRestartCtx
.LogString
= "PowerOff";
5684 gHaltRestartCtx
.PowerState
= RESTART_STATE
;
5685 gHaltRestartCtx
.MessageType
= kIOMessageSystemWillRestart
;
5686 gHaltRestartCtx
.LogString
= "Restart";
5690 gHaltRestartCtx
.PowerState
= ON_STATE
;
5691 gHaltRestartCtx
.MessageType
= kIOMessageSystemPagingOff
;
5692 gHaltRestartCtx
.LogString
= "PagingOff";
5693 IOService::updateConsoleUsers(NULL
, kIOMessageSystemPagingOff
);
5695 IOHibernateSystemRestart();
5703 gHaltRestartCtx
.phase
= kNotifyPriorityClients
;
5704 // Notify legacy clients
5705 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &gHaltRestartCtx
);
5707 // For normal shutdown, turn off File Server Mode.
5708 if (kPEHaltCPU
== pe_type
) {
5709 OSSharedPtr
<const OSSymbol
> setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
5710 OSSharedPtr
<OSNumber
> num
= OSNumber::withNumber((unsigned long long) 0, 32);
5711 if (setting
&& num
) {
5712 setPMSetting(setting
.get(), num
.get());
5716 if (kPEPagingOff
!= pe_type
) {
5717 gHaltRestartCtx
.phase
= kNotifyPowerPlaneDrivers
;
5718 // Notify in power tree order
5719 notifySystemShutdown(this, gHaltRestartCtx
.MessageType
);
5722 gHaltRestartCtx
.phase
= kNotifyHaltRestartAction
;
5723 #if defined(XNU_TARGET_OS_OSX)
5724 IOCPURunPlatformHaltRestartActions(pe_type
);
5725 #else /* !defined(XNU_TARGET_OS_OSX) */
5726 if (kPEPagingOff
!= pe_type
) {
5727 IOCPURunPlatformHaltRestartActions(pe_type
);
5729 #endif /* !defined(XNU_TARGET_OS_OSX) */
5731 // Wait for PM to quiesce
5732 if ((kPEPagingOff
!= pe_type
) && gPMHaltLock
) {
5733 gHaltRestartCtx
.phase
= kQuiescePM
;
5734 AbsoluteTime quiesceTime
= mach_absolute_time();
5736 IOLockLock(gPMHaltLock
);
5737 gPMQuiesced
= false;
5738 if (quiescePowerTree(this, &quiescePowerTreeCallback
, &gPMQuiesced
) ==
5740 while (!gPMQuiesced
) {
5741 IOLockSleep(gPMHaltLock
, &gPMQuiesced
, THREAD_UNINT
);
5744 IOLockUnlock(gPMHaltLock
);
5745 deltaTime
= computeDeltaTimeMS(&quiesceTime
, &elapsedTime
);
5746 DLOG("PM quiesce took %u ms\n", deltaTime
);
5747 halt_log_enter("Quiesce", NULL
, elapsedTime
);
5749 gHaltRestartCtx
.phase
= kNotifyDone
;
5751 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
5752 LOG("%s all drivers took %u ms\n", gHaltRestartCtx
.LogString
, deltaTime
);
5754 halt_log_enter(gHaltRestartCtx
.LogString
, NULL
, elapsedTime
);
5756 deltaTime
= computeDeltaTimeMS(&gHaltStartTime
, &elapsedTime
);
5757 LOG("%s total %u ms\n", gHaltRestartCtx
.LogString
, deltaTime
);
5759 if (gHaltLog
&& gHaltTimeMaxLog
&& (deltaTime
>= gHaltTimeMaxLog
)) {
5760 printf("%s total %d ms:%s\n", gHaltRestartCtx
.LogString
, deltaTime
, gHaltLog
);
5763 checkShutdownTimeout();
5767 IOPMrootDomain::checkShutdownTimeout()
5769 AbsoluteTime elapsedTime
;
5770 uint32_t deltaTime
= computeDeltaTimeMS(&gHaltStartTime
, &elapsedTime
);
5772 if (gHaltTimeMaxPanic
&& (deltaTime
>= gHaltTimeMaxPanic
)) {
5779 IOPMrootDomain::panicWithShutdownLog(uint32_t timeoutInMs
)
5782 if ((gHaltRestartCtx
.phase
== kNotifyPriorityClients
) && gHaltRestartCtx
.handler
) {
5783 halt_log_enter("Blocked on priority client", (void *)gHaltRestartCtx
.handler
, mach_absolute_time() - gHaltStartTime
);
5785 panic("%s timed out in phase '%s'. Total %d ms:%s",
5786 gHaltRestartCtx
.LogString
, shutdownPhase2String(gHaltRestartCtx
.phase
), timeoutInMs
, gHaltLog
);
5788 panic("%s timed out in phase \'%s\'. Total %d ms",
5789 gHaltRestartCtx
.LogString
, shutdownPhase2String(gHaltRestartCtx
.phase
), timeoutInMs
);
5793 //******************************************************************************
5796 //******************************************************************************
5799 IOPMrootDomain::shutdownSystem( void )
5801 return kIOReturnUnsupported
;
5804 //******************************************************************************
5807 //******************************************************************************
5810 IOPMrootDomain::restartSystem( void )
5812 return kIOReturnUnsupported
;
5816 // MARK: System Capability
5818 //******************************************************************************
5819 // tagPowerPlaneService
5821 // Running on PM work loop thread.
5822 //******************************************************************************
5825 IOPMrootDomain::tagPowerPlaneService(
5826 IOService
* service
,
5827 IOPMActions
* actions
,
5828 IOPMPowerStateIndex maxPowerState
)
5832 memset(actions
, 0, sizeof(*actions
));
5833 actions
->target
= this;
5835 if (service
== this) {
5836 actions
->actionPowerChangeStart
=
5837 OSMemberFunctionCast(
5838 IOPMActionPowerChangeStart
, this,
5839 &IOPMrootDomain::handleOurPowerChangeStart
);
5841 actions
->actionPowerChangeDone
=
5842 OSMemberFunctionCast(
5843 IOPMActionPowerChangeDone
, this,
5844 &IOPMrootDomain::handleOurPowerChangeDone
);
5846 actions
->actionPowerChangeOverride
=
5847 OSMemberFunctionCast(
5848 IOPMActionPowerChangeOverride
, this,
5849 &IOPMrootDomain::overrideOurPowerChange
);
5853 #if DISPLAY_WRANGLER_PRESENT
5854 if (NULL
!= service
->metaCast("IODisplayWrangler")) {
5855 // XXX should this really retain?
5856 wrangler
.reset(service
, OSRetain
);
5857 wrangler
->registerInterest(gIOGeneralInterest
,
5858 &displayWranglerNotification
, this, NULL
);
5860 // found the display wrangler, check for any display assertions already created
5861 if (pmAssertions
->getActivatedAssertions() & kIOPMDriverAssertionPreventDisplaySleepBit
) {
5862 DLOG("wrangler setIgnoreIdleTimer\(1) due to pre-existing assertion\n");
5863 wrangler
->setIgnoreIdleTimer( true );
5865 flags
|= kPMActionsFlagIsDisplayWrangler
;
5867 #endif /* DISPLAY_WRANGLER_PRESENT */
5869 if (service
->propertyExists("IOPMStrictTreeOrder")) {
5870 flags
|= kPMActionsFlagIsGraphicsDriver
;
5872 if (service
->propertyExists("IOPMUnattendedWakePowerState")) {
5873 flags
|= kPMActionsFlagIsAudioDriver
;
5876 OSSharedPtr
<OSObject
> prop
= service
->copyProperty(kIOPMDarkWakeMaxPowerStateKey
);
5878 OSNumber
* num
= OSDynamicCast(OSNumber
, prop
.get());
5880 actions
->darkWakePowerState
= num
->unsigned32BitValue();
5881 if (actions
->darkWakePowerState
< maxPowerState
) {
5882 flags
|= kPMActionsFlagHasDarkWakePowerState
;
5887 // Find the power connection object that is a child of the PCI host
5888 // bridge, and has a graphics/audio device attached below. Mark the
5889 // power branch for delayed child notifications.
5892 IORegistryEntry
* child
= service
;
5893 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
5895 while (child
!= this) {
5896 if (child
->propertyHasValue("IOPCITunnelled", kOSBooleanTrue
)) {
5897 // Skip delaying notifications and clamping power on external graphics and audio devices.
5898 DLOG("Avoiding delayChildNotification on object 0x%llx. flags: 0x%x\n", service
->getRegistryEntryID(), flags
);
5902 if ((parent
== pciHostBridgeDriver
) ||
5904 if (OSDynamicCast(IOPowerConnection
, child
)) {
5905 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
5906 conn
->delayChildNotification
= true;
5907 DLOG("delayChildNotification for 0x%llx\n", conn
->getRegistryEntryID());
5912 parent
= child
->getParentEntry(gIOPowerPlane
);
5917 DLOG("%s tag flags %x\n", service
->getName(), flags
);
5918 actions
->flags
|= flags
;
5919 actions
->actionPowerChangeOverride
=
5920 OSMemberFunctionCast(
5921 IOPMActionPowerChangeOverride
, this,
5922 &IOPMrootDomain::overridePowerChangeForService
);
5924 if (flags
& kPMActionsFlagIsDisplayWrangler
) {
5925 actions
->actionActivityTickle
=
5926 OSMemberFunctionCast(
5927 IOPMActionActivityTickle
, this,
5928 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
5930 actions
->actionUpdatePowerClient
=
5931 OSMemberFunctionCast(
5932 IOPMActionUpdatePowerClient
, this,
5933 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler
);
5938 // Locate the first PCI host bridge for PMTrace.
5939 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge")) {
5940 IOService
* provider
= service
->getProvider();
5941 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
5942 provider
->inPlane(gIODTPlane
)) {
5943 pciHostBridgeDevice
.reset(provider
, OSNoRetain
);
5944 pciHostBridgeDriver
.reset(service
, OSNoRetain
);
5945 DLOG("PMTrace found PCI host bridge %s->%s\n",
5946 provider
->getName(), service
->getName());
5950 // Tag top-level PCI devices. The order of PMinit() call does not
5951 // change across boots and is used as the PCI bit number.
5952 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice")) {
5953 // Would prefer to check built-in property, but tagPowerPlaneService()
5954 // is called before pciDevice->registerService().
5955 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
5956 if ((parent
== pciHostBridgeDevice
) && service
->propertyExists("acpi-device")) {
5957 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
5959 // Save the assigned bit for fast lookup.
5960 actions
->flags
|= (bit
& kPMActionsPCIBitNumberMask
);
5962 actions
->actionPowerChangeStart
=
5963 OSMemberFunctionCast(
5964 IOPMActionPowerChangeStart
, this,
5965 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
5967 actions
->actionPowerChangeDone
=
5968 OSMemberFunctionCast(
5969 IOPMActionPowerChangeDone
, this,
5970 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
5976 //******************************************************************************
5977 // PM actions for root domain
5978 //******************************************************************************
5981 IOPMrootDomain::overrideOurPowerChange(
5982 IOService
* service
,
5983 IOPMActions
* actions
,
5984 const IOPMRequest
* request
,
5985 IOPMPowerStateIndex
* inOutPowerState
,
5986 IOPMPowerChangeFlags
* inOutChangeFlags
)
5988 uint32_t changeFlags
= *inOutChangeFlags
;
5989 uint32_t desiredPowerState
= (uint32_t) *inOutPowerState
;
5990 uint32_t currentPowerState
= (uint32_t) getPowerState();
5992 if (request
->getTag() == 0) {
5993 // Set a tag for any request that originates from IOServicePM
5994 (const_cast<IOPMRequest
*>(request
))->fTag
= nextRequestTag(kCPSReasonPMInternals
);
5997 DLOG("PowerChangeOverride (%s->%s, %x, 0x%x) tag 0x%x\n",
5998 getPowerStateString(currentPowerState
),
5999 getPowerStateString(desiredPowerState
),
6000 _currentCapability
, changeFlags
,
6003 if ((AOT_STATE
== desiredPowerState
) && (ON_STATE
== currentPowerState
)) {
6004 // Assertion may have been taken in AOT leading to changePowerStateTo(AOT)
6005 *inOutChangeFlags
|= kIOPMNotDone
;
6009 if (changeFlags
& kIOPMParentInitiated
) {
6010 // Root parent is permanently pegged at max power,
6011 // a parent initiated power change is unexpected.
6012 *inOutChangeFlags
|= kIOPMNotDone
;
6016 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
6017 if (lowBatteryCondition
&& (desiredPowerState
< currentPowerState
)) {
6018 // Reject sleep requests when lowBatteryCondition is TRUE to
6019 // avoid racing with the impending system shutdown.
6020 *inOutChangeFlags
|= kIOPMNotDone
;
6025 if (desiredPowerState
< currentPowerState
) {
6026 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
)) {
6027 // Root domain is dropping power state from ON->SLEEP.
6028 // If system is in full wake, first enter dark wake by
6029 // converting the power drop to a capability change.
6030 // Once in dark wake, transition to sleep state ASAP.
6032 darkWakeToSleepASAP
= true;
6034 // Drop graphics and audio capability
6035 _desiredCapability
&= ~(
6036 kIOPMSystemCapabilityGraphics
|
6037 kIOPMSystemCapabilityAudio
);
6039 // Convert to capability change (ON->ON)
6040 *inOutPowerState
= getRUN_STATE();
6041 *inOutChangeFlags
|= kIOPMSynchronize
;
6043 // Revert device desire from SLEEP to ON
6044 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonPowerOverride
);
6046 // System is already in dark wake, ok to drop power state.
6047 // Broadcast root power down to entire tree.
6048 *inOutChangeFlags
|= kIOPMRootChangeDown
;
6050 } else if (desiredPowerState
> currentPowerState
) {
6051 if ((_currentCapability
& kIOPMSystemCapabilityCPU
) == 0) {
6052 // Broadcast power up when waking from sleep, but not for the
6053 // initial power change at boot by checking for cpu capability.
6054 *inOutChangeFlags
|= kIOPMRootChangeUp
;
6060 IOPMrootDomain::handleOurPowerChangeStart(
6061 IOService
* service
,
6062 IOPMActions
* actions
,
6063 const IOPMRequest
* request
,
6064 IOPMPowerStateIndex newPowerState
,
6065 IOPMPowerChangeFlags
* inOutChangeFlags
)
6067 IOPMRequestTag requestTag
= request
->getTag();
6068 IOPMRequestTag sleepReason
;
6070 uint32_t changeFlags
= *inOutChangeFlags
;
6071 uint32_t currentPowerState
= (uint32_t) getPowerState();
6072 bool publishSleepReason
= false;
6074 // Check if request has a valid sleep reason
6075 sleepReason
= REQUEST_TAG_TO_REASON(requestTag
);
6076 if (sleepReason
< kIOPMSleepReasonClamshell
) {
6077 sleepReason
= kIOPMSleepReasonIdle
;
6080 _systemTransitionType
= kSystemTransitionNone
;
6081 _systemMessageClientMask
= 0;
6082 capabilityLoss
= false;
6083 toldPowerdCapWillChange
= false;
6085 // Emergency notifications may arrive after the initial sleep request
6086 // has been queued. Override the sleep reason so powerd and others can
6087 // treat this as an emergency sleep.
6088 if (lowBatteryCondition
) {
6089 sleepReason
= kIOPMSleepReasonLowPower
;
6090 } else if (thermalEmergencyState
) {
6091 sleepReason
= kIOPMSleepReasonThermalEmergency
;
6094 // 1. Explicit capability change.
6095 if (changeFlags
& kIOPMSynchronize
) {
6096 if (newPowerState
== ON_STATE
) {
6097 if (changeFlags
& kIOPMSyncNoChildNotify
) {
6098 _systemTransitionType
= kSystemTransitionNewCapClient
;
6100 _systemTransitionType
= kSystemTransitionCapability
;
6104 // 2. Going to sleep (cancellation still possible).
6105 else if (newPowerState
< currentPowerState
) {
6106 _systemTransitionType
= kSystemTransitionSleep
;
6108 // 3. Woke from (idle or demand) sleep.
6109 else if (!systemBooting
&&
6110 (changeFlags
& kIOPMSelfInitiated
) &&
6111 (newPowerState
> currentPowerState
)) {
6112 _systemTransitionType
= kSystemTransitionWake
;
6113 _desiredCapability
= kIOPMSystemCapabilityCPU
| kIOPMSystemCapabilityNetwork
;
6115 // Early exit from dark wake to full (e.g. LID open)
6116 if (kFullWakeReasonNone
!= fullWakeReason
) {
6117 _desiredCapability
|= (
6118 kIOPMSystemCapabilityGraphics
|
6119 kIOPMSystemCapabilityAudio
);
6121 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
6122 if (fullWakeReason
== kFullWakeReasonLocalUser
) {
6123 darkWakeExit
= true;
6124 darkWakeToSleepASAP
= false;
6125 setProperty(kIOPMRootDomainWakeTypeKey
, isRTCAlarmWake
?
6126 kIOPMRootDomainWakeTypeAlarm
: kIOPMRootDomainWakeTypeUser
);
6131 IOHibernateSetWakeCapabilities(_desiredCapability
);
6135 // Update pending wake capability at the beginning of every
6136 // state transition (including synchronize). This will become
6137 // the current capability at the end of the transition.
6139 if (kSystemTransitionSleep
== _systemTransitionType
) {
6140 _pendingCapability
= 0;
6141 capabilityLoss
= true;
6142 } else if (kSystemTransitionNewCapClient
!= _systemTransitionType
) {
6143 _pendingCapability
= _desiredCapability
|
6144 kIOPMSystemCapabilityCPU
|
6145 kIOPMSystemCapabilityNetwork
;
6147 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
) {
6148 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
6151 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
6152 (_pendingCapability
== _currentCapability
)) {
6153 // Cancel the PM state change.
6154 _systemTransitionType
= kSystemTransitionNone
;
6155 *inOutChangeFlags
|= kIOPMNotDone
;
6157 if (__builtin_popcount(_pendingCapability
) <
6158 __builtin_popcount(_currentCapability
)) {
6159 capabilityLoss
= true;
6163 // 1. Capability change.
6164 if (kSystemTransitionCapability
== _systemTransitionType
) {
6165 // Dark to Full transition.
6166 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
)) {
6167 tracePoint( kIOPMTracePointDarkWakeExit
);
6169 #if defined(XNU_TARGET_OS_OSX)
6170 // rdar://problem/65627936
6171 // When a dark->full wake promotion is scheduled before an ON->SLEEP
6172 // power state drop, invalidate any request to drop power state already
6173 // in the queue, including the override variant, unless full wake cannot
6174 // be sustained. Any power state drop queued after this SustainFullWake
6175 // request will not be affected.
6176 if (checkSystemCanSustainFullWake()) {
6177 changePowerStateWithOverrideTo(getRUN_STATE(), kCPSReasonSustainFullWake
);
6181 willEnterFullWake();
6184 // Full to Dark transition.
6185 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
)) {
6186 // Clear previous stats
6187 IOLockLock(pmStatsLock
);
6188 if (pmStatsAppResponses
) {
6189 pmStatsAppResponses
= OSArray::withCapacity(5);
6191 IOLockUnlock(pmStatsLock
);
6193 tracePoint( kIOPMTracePointDarkWakeEntry
);
6194 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
6195 _systemMessageClientMask
= kSystemMessageClientPowerd
|
6196 kSystemMessageClientLegacyApp
;
6199 // Prevent user active transitions before notifying clients
6200 // that system will sleep.
6201 preventTransitionToUserActive(true);
6203 IOService::setAdvisoryTickleEnable( false );
6205 // Publish the sleep reason for full to dark wake
6206 publishSleepReason
= true;
6207 lastSleepReason
= fullToDarkReason
= sleepReason
;
6209 // Publish a UUID for the Sleep --> Wake cycle
6210 handlePublishSleepWakeUUID(true);
6211 if (sleepDelaysReport
) {
6212 clock_get_uptime(&ts_sleepStart
);
6213 DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart
);
6216 darkWakeExit
= false;
6220 else if (kSystemTransitionSleep
== _systemTransitionType
) {
6221 // Beginning of a system sleep transition.
6222 // Cancellation is still possible.
6223 tracePoint( kIOPMTracePointSleepStarted
);
6225 _systemMessageClientMask
= kSystemMessageClientAll
;
6226 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0) {
6227 _systemMessageClientMask
&= ~kSystemMessageClientLegacyApp
;
6229 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0) {
6230 // Kernel priority clients are only notified on the initial
6231 // transition to full wake, so don't notify them unless system
6232 // has gained graphics capability since the last system wake.
6233 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
6235 // System was in full wake, but the downwards power transition is driven
6236 // by a request that originates from IOServicePM, so it isn't tagged with
6237 // a valid system sleep reason.
6238 if (REQUEST_TAG_TO_REASON(requestTag
) == kCPSReasonPMInternals
) {
6239 // Publish the same reason for full to dark
6240 sleepReason
= fullToDarkReason
;
6244 gIOHibernateState
= 0;
6247 // Record the reason for dark wake back to sleep
6248 // System may not have ever achieved full wake
6250 publishSleepReason
= true;
6251 lastSleepReason
= sleepReason
;
6252 if (sleepDelaysReport
) {
6253 clock_get_uptime(&ts_sleepStart
);
6254 DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart
);
6258 else if (kSystemTransitionWake
== _systemTransitionType
) {
6259 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
6260 // Clear stats about sleep
6262 if (AOT_STATE
== newPowerState
) {
6263 _pendingCapability
= 0;
6266 if (AOT_STATE
== currentPowerState
) {
6267 // Wake events are no longer accepted after waking to AOT_STATE.
6268 // Re-enable wake event acceptance to append wake events claimed
6269 // during the AOT to ON_STATE transition.
6270 acceptSystemWakeEvents(kAcceptSystemWakeEvents_Reenable
);
6273 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
) {
6274 willEnterFullWake();
6278 // The only location where the sleep reason is published. At this point
6279 // sleep can still be cancelled, but sleep reason should be published
6280 // early for logging purposes.
6282 if (publishSleepReason
) {
6283 static const char * IOPMSleepReasons
[] =
6285 kIOPMClamshellSleepKey
,
6286 kIOPMPowerButtonSleepKey
,
6287 kIOPMSoftwareSleepKey
,
6288 kIOPMOSSwitchHibernationKey
,
6290 kIOPMLowPowerSleepKey
,
6291 kIOPMThermalEmergencySleepKey
,
6292 kIOPMMaintenanceSleepKey
,
6293 kIOPMSleepServiceExitKey
,
6294 kIOPMDarkWakeThermalEmergencyKey
,
6295 kIOPMNotificationWakeExitKey
6298 // Record sleep cause in IORegistry
6299 uint32_t reasonIndex
= sleepReason
- kIOPMSleepReasonClamshell
;
6300 if (reasonIndex
< sizeof(IOPMSleepReasons
) / sizeof(IOPMSleepReasons
[0])) {
6301 DLOG("sleep reason %s\n", IOPMSleepReasons
[reasonIndex
]);
6302 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[reasonIndex
]);
6306 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
6307 (kSystemTransitionNewCapClient
!= _systemTransitionType
)) {
6308 _systemStateGeneration
++;
6309 systemDarkWake
= false;
6311 DLOG("=== START (%s->%s, %x->%x, 0x%x) gen %u, msg %x, tag %x\n",
6312 getPowerStateString(currentPowerState
),
6313 getPowerStateString((uint32_t) newPowerState
),
6314 _currentCapability
, _pendingCapability
,
6315 *inOutChangeFlags
, _systemStateGeneration
, _systemMessageClientMask
,
6319 if ((AOT_STATE
== newPowerState
) && (SLEEP_STATE
!= currentPowerState
)) {
6320 panic("illegal AOT entry from %s", getPowerStateString(currentPowerState
));
6322 if (_aotNow
&& (ON_STATE
== newPowerState
)) {
6324 aotShouldExit(false, true);
6331 IOPMrootDomain::handleOurPowerChangeDone(
6332 IOService
* service
,
6333 IOPMActions
* actions
,
6334 const IOPMRequest
* request
,
6335 IOPMPowerStateIndex oldPowerState
,
6336 IOPMPowerChangeFlags changeFlags
)
6338 if (kSystemTransitionNewCapClient
== _systemTransitionType
) {
6339 _systemTransitionType
= kSystemTransitionNone
;
6343 if (_systemTransitionType
!= kSystemTransitionNone
) {
6344 uint32_t currentPowerState
= (uint32_t) getPowerState();
6346 if (changeFlags
& kIOPMNotDone
) {
6347 // Power down was cancelled or vetoed.
6348 _pendingCapability
= _currentCapability
;
6349 lastSleepReason
= 0;
6351 // When sleep is cancelled or reverted, don't report
6352 // the target (lower) power state as the previous state.
6353 oldPowerState
= currentPowerState
;
6355 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
) &&
6356 CAP_CURRENT(kIOPMSystemCapabilityCPU
)) {
6357 #if defined(XNU_TARGET_OS_OSX)
6358 pmPowerStateQueue
->submitPowerEvent(
6359 kPowerEventPolicyStimulus
,
6360 (void *) kStimulusDarkWakeReentry
,
6361 _systemStateGeneration
);
6362 #else /* !defined(XNU_TARGET_OS_OSX) */
6363 // On embedded, there are no factors that can prolong a
6364 // "darkWake" when a power down is vetoed. We need to
6365 // promote to "fullWake" at least once so that factors
6366 // that prevent idle sleep can assert themselves if required
6367 pmPowerStateQueue
->submitPowerEvent(
6368 kPowerEventPolicyStimulus
,
6369 (void *) kStimulusDarkWakeActivityTickle
);
6370 #endif /* !defined(XNU_TARGET_OS_OSX) */
6373 // Revert device desire to max.
6374 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonPowerDownCancel
);
6376 // Send message on dark wake to full wake promotion.
6377 // tellChangeUp() handles the normal SLEEP->ON case.
6379 if (kSystemTransitionCapability
== _systemTransitionType
) {
6380 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
)) {
6381 lastSleepReason
= 0; // stop logging wrangler tickles
6382 tellClients(kIOMessageSystemHasPoweredOn
);
6384 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
)) {
6385 // Going dark, reset full wake state
6386 // userIsActive will be cleared by wrangler powering down
6387 fullWakeReason
= kFullWakeReasonNone
;
6389 if (ts_sleepStart
) {
6390 clock_get_uptime(&wake2DarkwakeDelay
);
6391 SUB_ABSOLUTETIME(&wake2DarkwakeDelay
, &ts_sleepStart
);
6392 DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay
);
6398 // Reset state after exiting from dark wake.
6400 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
6401 CAP_LOSS(kIOPMSystemCapabilityCPU
)) {
6402 darkWakeMaintenance
= false;
6403 darkWakeToSleepASAP
= false;
6404 pciCantSleepValid
= false;
6405 darkWakeSleepService
= false;
6407 if (CAP_LOSS(kIOPMSystemCapabilityCPU
)) {
6408 // Remove the influence of display power assertion
6409 // before next system wake.
6411 wrangler
->changePowerStateForRootDomain(
6412 kWranglerPowerStateMin
);
6414 removeProperty(gIOPMUserTriggeredFullWakeKey
.get());
6418 // Entered dark mode.
6420 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
6421 (_pendingCapability
& kIOPMSystemCapabilityCPU
)) {
6422 // Queue an evaluation of whether to remain in dark wake,
6423 // and for how long. This serves the purpose of draining
6424 // any assertions from the queue.
6426 pmPowerStateQueue
->submitPowerEvent(
6427 kPowerEventPolicyStimulus
,
6428 (void *) kStimulusDarkWakeEntry
,
6429 _systemStateGeneration
);
6433 DLOG("=== FINISH (%s->%s, %x->%x, 0x%x) gen %u, msg %x, tag %x\n",
6434 getPowerStateString((uint32_t) oldPowerState
), getPowerStateString(currentPowerState
),
6435 _currentCapability
, _pendingCapability
,
6436 changeFlags
, _systemStateGeneration
, _systemMessageClientMask
,
6439 if ((currentPowerState
== ON_STATE
) && pmAssertions
) {
6440 pmAssertions
->reportCPUBitAccounting();
6443 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
) {
6445 #if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
6446 if (clamshellExists
&& fullWakeThreadCall
) {
6447 AbsoluteTime deadline
;
6448 clock_interval_to_deadline(DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
, kSecondScale
, &deadline
);
6449 thread_call_enter_delayed(fullWakeThreadCall
, deadline
);
6452 } else if (CAP_GAIN(kIOPMSystemCapabilityCPU
)) {
6456 // Update current system capability.
6457 if (_currentCapability
!= _pendingCapability
) {
6458 _currentCapability
= _pendingCapability
;
6461 // Update highest system capability.
6463 _highestCapability
|= _currentCapability
;
6465 if (darkWakePostTickle
&&
6466 (kSystemTransitionWake
== _systemTransitionType
) &&
6467 (gDarkWakeFlags
& kDarkWakeFlagPromotionMask
) ==
6468 kDarkWakeFlagPromotionLate
) {
6469 darkWakePostTickle
= false;
6471 } else if (darkWakeExit
) {
6472 requestFullWake( kFullWakeReasonLocalUser
);
6475 // Reset tracepoint at completion of capability change,
6476 // completion of wake transition, and aborted sleep transition.
6478 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
6479 (_systemTransitionType
== kSystemTransitionWake
) ||
6480 ((_systemTransitionType
== kSystemTransitionSleep
) &&
6481 (changeFlags
& kIOPMNotDone
))) {
6482 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
6483 tracePoint( kIOPMTracePointSystemUp
);
6486 _systemTransitionType
= kSystemTransitionNone
;
6487 _systemMessageClientMask
= 0;
6488 toldPowerdCapWillChange
= false;
6490 darkWakeLogClamp
= false;
6492 if (lowBatteryCondition
) {
6493 privateSleepSystem(kIOPMSleepReasonLowPower
);
6494 } else if (thermalEmergencyState
) {
6495 privateSleepSystem(kIOPMSleepReasonThermalEmergency
);
6496 } else if ((fullWakeReason
== kFullWakeReasonDisplayOn
) && !displayPowerOnRequested
) {
6497 // Request for full wake is removed while system is waking up to full wake
6498 DLOG("DisplayOn fullwake request is removed\n");
6499 handleSetDisplayPowerOn(false);
6502 if ((gClamshellFlags
& kClamshell_WAR_47715679
) && isRTCAlarmWake
) {
6503 pmPowerStateQueue
->submitPowerEvent(
6504 kPowerEventReceivedPowerNotification
, (void *)(uintptr_t) kLocalEvalClamshellCommand
);
6509 //******************************************************************************
6510 // PM actions for graphics and audio.
6511 //******************************************************************************
6514 IOPMrootDomain::overridePowerChangeForService(
6515 IOService
* service
,
6516 IOPMActions
* actions
,
6517 const IOPMRequest
* request
,
6518 IOPMPowerStateIndex
* inOutPowerState
,
6519 IOPMPowerChangeFlags
* inOutChangeFlags
)
6521 uint32_t powerState
= (uint32_t) *inOutPowerState
;
6522 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
6523 const uint32_t actionFlags
= actions
->flags
;
6525 if (kSystemTransitionNone
== _systemTransitionType
) {
6526 // Not in midst of a system transition.
6527 // Do not set kPMActionsStatePowerClamped.
6528 } else if ((actions
->state
& kPMActionsStatePowerClamped
) == 0) {
6529 bool enableClamp
= false;
6531 // For most drivers, enable the clamp during ON->Dark transition
6532 // which has the kIOPMSynchronize flag set in changeFlags.
6533 if ((actionFlags
& kPMActionsFlagIsDisplayWrangler
) &&
6534 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
6535 (changeFlags
& kIOPMSynchronize
)) {
6537 } else if ((actionFlags
& kPMActionsFlagIsAudioDriver
) &&
6538 ((gDarkWakeFlags
& kDarkWakeFlagAudioNotSuppressed
) == 0) &&
6539 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0) &&
6540 (changeFlags
& kIOPMSynchronize
)) {
6542 } else if ((actionFlags
& kPMActionsFlagHasDarkWakePowerState
) &&
6543 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
6544 (changeFlags
& kIOPMSynchronize
)) {
6546 } else if ((actionFlags
& kPMActionsFlagIsGraphicsDriver
) &&
6547 (_systemTransitionType
== kSystemTransitionSleep
)) {
6548 // For graphics drivers, clamp power when entering
6549 // system sleep. Not when dropping to dark wake.
6554 actions
->state
|= kPMActionsStatePowerClamped
;
6555 DLOG("power clamp enabled %s %qx, pendingCap 0x%x, ps %d, cflags 0x%x\n",
6556 service
->getName(), service
->getRegistryEntryID(),
6557 _pendingCapability
, powerState
, changeFlags
);
6559 } else if ((actions
->state
& kPMActionsStatePowerClamped
) != 0) {
6560 bool disableClamp
= false;
6562 if ((actionFlags
& (
6563 kPMActionsFlagIsDisplayWrangler
|
6564 kPMActionsFlagIsGraphicsDriver
)) &&
6565 (_pendingCapability
& kIOPMSystemCapabilityGraphics
)) {
6566 disableClamp
= true;
6567 } else if ((actionFlags
& kPMActionsFlagIsAudioDriver
) &&
6568 (_pendingCapability
& kIOPMSystemCapabilityAudio
)) {
6569 disableClamp
= true;
6570 } else if ((actionFlags
& kPMActionsFlagHasDarkWakePowerState
) &&
6571 (_pendingCapability
& kIOPMSystemCapabilityGraphics
)) {
6572 disableClamp
= true;
6576 actions
->state
&= ~kPMActionsStatePowerClamped
;
6577 DLOG("power clamp removed %s %qx, pendingCap 0x%x, ps %d, cflags 0x%x\n",
6578 service
->getName(), service
->getRegistryEntryID(),
6579 _pendingCapability
, powerState
, changeFlags
);
6583 if (actions
->state
& kPMActionsStatePowerClamped
) {
6584 uint32_t maxPowerState
= 0;
6586 // Determine the max power state allowed when clamp is enabled
6587 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
)) {
6588 // Parent intiated power state changes
6589 if ((service
->getPowerState() > maxPowerState
) &&
6590 (actionFlags
& kPMActionsFlagIsDisplayWrangler
)) {
6593 // Remove lingering effects of any tickle before entering
6594 // dark wake. It will take a new tickle to return to full
6595 // wake, so the existing tickle state is useless.
6597 if (changeFlags
& kIOPMDomainDidChange
) {
6598 *inOutChangeFlags
|= kIOPMExpireIdleTimer
;
6600 } else if (actionFlags
& kPMActionsFlagIsGraphicsDriver
) {
6602 } else if (actionFlags
& kPMActionsFlagHasDarkWakePowerState
) {
6603 maxPowerState
= actions
->darkWakePowerState
;
6606 // Deny all self-initiated changes when power is limited.
6607 // Wrangler tickle should never defeat the limiter.
6608 maxPowerState
= service
->getPowerState();
6611 if (powerState
> maxPowerState
) {
6612 DLOG("power clamped %s %qx, ps %u->%u, cflags 0x%x)\n",
6613 service
->getName(), service
->getRegistryEntryID(),
6614 powerState
, maxPowerState
, changeFlags
);
6615 *inOutPowerState
= maxPowerState
;
6617 if (darkWakePostTickle
&&
6618 (actionFlags
& kPMActionsFlagIsDisplayWrangler
) &&
6619 (changeFlags
& kIOPMDomainWillChange
) &&
6620 ((gDarkWakeFlags
& kDarkWakeFlagPromotionMask
) ==
6621 kDarkWakeFlagPromotionEarly
)) {
6622 darkWakePostTickle
= false;
6627 if (!darkWakePowerClamped
&& (changeFlags
& kIOPMDomainDidChange
)) {
6628 if (darkWakeLogClamp
) {
6632 clock_get_uptime(&now
);
6633 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
6634 absolutetime_to_nanoseconds(now
, &nsec
);
6635 DLOG("dark wake power clamped after %u ms\n",
6636 ((int)((nsec
) / NSEC_PER_MSEC
)));
6638 darkWakePowerClamped
= true;
6644 IOPMrootDomain::handleActivityTickleForDisplayWrangler(
6645 IOService
* service
,
6646 IOPMActions
* actions
)
6648 #if DISPLAY_WRANGLER_PRESENT
6649 // Warning: Not running in PM work loop context - don't modify state !!!
6650 // Trap tickle directed to IODisplayWrangler while running with graphics
6651 // capability suppressed.
6653 assert(service
== wrangler
);
6655 clock_get_uptime(&userActivityTime
);
6656 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
6657 || (lastSleepReason
== kIOPMSleepReasonMaintenance
)
6658 || (lastSleepReason
== kIOPMSleepReasonSoftware
));
6660 userActivityCount
++;
6661 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
6662 userActivityCount
, lastSleepReason
);
6665 if (!darkWakeExit
&& ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0)) {
6666 DLOG("display wrangler tickled\n");
6667 if (kIOLogPMRootDomain
& gIOKitDebug
) {
6668 OSReportWithBacktrace("Dark wake display tickle");
6670 if (pmPowerStateQueue
) {
6671 pmPowerStateQueue
->submitPowerEvent(
6672 kPowerEventPolicyStimulus
,
6673 (void *) kStimulusDarkWakeActivityTickle
,
6674 true /* set wake type */ );
6677 #endif /* DISPLAY_WRANGLER_PRESENT */
6681 IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
6682 IOService
* service
,
6683 IOPMActions
* actions
,
6684 const OSSymbol
* powerClient
,
6685 IOPMPowerStateIndex oldPowerState
,
6686 IOPMPowerStateIndex newPowerState
)
6688 #if DISPLAY_WRANGLER_PRESENT
6689 assert(service
== wrangler
);
6691 // This function implements half of the user active detection
6692 // by monitoring changes to the display wrangler's device desire.
6694 // User becomes active when either:
6695 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
6696 // in max power state. This desire change in absence of a power state
6697 // change is detected within. This handles the case when user becomes
6698 // active while the display is already lit by setDisplayPowerOn().
6700 // 2. Power state change to max, and DeviceDesire is also at max.
6701 // Handled by displayWranglerNotification().
6703 // User becomes inactive when DeviceDesire drops to sleep state or below.
6705 DLOG("wrangler %s (ps %u, %u->%u)\n",
6706 powerClient
->getCStringNoCopy(),
6707 (uint32_t) service
->getPowerState(),
6708 (uint32_t) oldPowerState
, (uint32_t) newPowerState
);
6710 if (powerClient
== gIOPMPowerClientDevice
) {
6711 if ((newPowerState
> oldPowerState
) &&
6712 (newPowerState
== kWranglerPowerStateMax
) &&
6713 (service
->getPowerState() == kWranglerPowerStateMax
)) {
6714 evaluatePolicy( kStimulusEnterUserActiveState
);
6715 } else if ((newPowerState
< oldPowerState
) &&
6716 (newPowerState
<= kWranglerPowerStateSleep
)) {
6717 evaluatePolicy( kStimulusLeaveUserActiveState
);
6721 if (newPowerState
<= kWranglerPowerStateSleep
) {
6722 evaluatePolicy( kStimulusDisplayWranglerSleep
);
6723 } else if (newPowerState
== kWranglerPowerStateMax
) {
6724 evaluatePolicy( kStimulusDisplayWranglerWake
);
6726 #endif /* DISPLAY_WRANGLER_PRESENT */
6729 //******************************************************************************
6730 // User active state management
6731 //******************************************************************************
6734 IOPMrootDomain::preventTransitionToUserActive( bool prevent
)
6736 #if DISPLAY_WRANGLER_PRESENT
6737 _preventUserActive
= prevent
;
6738 if (wrangler
&& !_preventUserActive
) {
6739 // Allowing transition to user active, but the wrangler may have
6740 // already powered ON in case of sleep cancel/revert. Poll the
6741 // same conditions checked for in displayWranglerNotification()
6742 // to bring the user active state up to date.
6744 if ((wrangler
->getPowerState() == kWranglerPowerStateMax
) &&
6745 (wrangler
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
6746 kWranglerPowerStateMax
)) {
6747 evaluatePolicy( kStimulusEnterUserActiveState
);
6750 #endif /* DISPLAY_WRANGLER_PRESENT */
6753 //******************************************************************************
6754 // Approve usage of delayed child notification by PM.
6755 //******************************************************************************
6758 IOPMrootDomain::shouldDelayChildNotification(
6759 IOService
* service
)
6761 if ((kFullWakeReasonNone
== fullWakeReason
) &&
6762 (kSystemTransitionWake
== _systemTransitionType
)) {
6763 DLOG("%s: delay child notify\n", service
->getName());
6769 //******************************************************************************
6770 // PM actions for PCI device.
6771 //******************************************************************************
6774 IOPMrootDomain::handlePowerChangeStartForPCIDevice(
6775 IOService
* service
,
6776 IOPMActions
* actions
,
6777 const IOPMRequest
* request
,
6778 IOPMPowerStateIndex powerState
,
6779 IOPMPowerChangeFlags
* inOutChangeFlags
)
6781 pmTracer
->tracePCIPowerChange(
6782 PMTraceWorker::kPowerChangeStart
,
6783 service
, *inOutChangeFlags
,
6784 (actions
->flags
& kPMActionsPCIBitNumberMask
));
6788 IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
6789 IOService
* service
,
6790 IOPMActions
* actions
,
6791 const IOPMRequest
* request
,
6792 IOPMPowerStateIndex powerState
,
6793 IOPMPowerChangeFlags changeFlags
)
6795 pmTracer
->tracePCIPowerChange(
6796 PMTraceWorker::kPowerChangeCompleted
,
6797 service
, changeFlags
,
6798 (actions
->flags
& kPMActionsPCIBitNumberMask
));
6801 //******************************************************************************
6804 // Override IOService::registerInterest() for root domain clients.
6805 //******************************************************************************
6807 class IOPMServiceInterestNotifier
: public _IOServiceInterestNotifier
6809 friend class IOPMrootDomain
;
6810 OSDeclareDefaultStructors(IOPMServiceInterestNotifier
);
6813 uint32_t ackTimeoutCnt
;
6814 uint32_t msgType
; // Message pending ack
6816 uint32_t maxMsgDelayMS
;
6817 uint32_t maxAckDelayMS
;
6818 uint64_t msgAbsTime
;
6821 OSSharedPtr
<const OSSymbol
> identifier
;
6822 OSSharedPtr
<const OSSymbol
> clientName
;
6825 OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier
, _IOServiceInterestNotifier
)
6827 OSSharedPtr
<IONotifier
>
6828 IOPMrootDomain::registerInterest(
6829 const OSSymbol
* typeOfInterest
,
6830 IOServiceInterestHandler handler
,
6831 void * target
, void * ref
)
6833 IOPMServiceInterestNotifier
* notifier
;
6834 bool isSystemCapabilityClient
;
6835 bool isKernelCapabilityClient
;
6836 IOReturn rc
= kIOReturnError
;
6838 isSystemCapabilityClient
= typeOfInterest
&&
6839 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
6841 isKernelCapabilityClient
= typeOfInterest
&&
6842 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
6844 if (isSystemCapabilityClient
) {
6845 typeOfInterest
= gIOAppPowerStateInterest
;
6848 notifier
= new IOPMServiceInterestNotifier
;
6853 if (notifier
->init()) {
6854 rc
= super::registerInterestForNotifier(notifier
, typeOfInterest
, handler
, target
, ref
);
6856 if (rc
!= kIOReturnSuccess
) {
6860 notifier
->ackTimeoutCnt
= 0;
6862 if (pmPowerStateQueue
) {
6863 if (isSystemCapabilityClient
) {
6865 if (pmPowerStateQueue
->submitPowerEvent(
6866 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false) {
6867 notifier
->release();
6871 if (isKernelCapabilityClient
) {
6873 if (pmPowerStateQueue
->submitPowerEvent(
6874 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false) {
6875 notifier
->release();
6880 OSSharedPtr
<OSData
> data
;
6881 uint8_t *uuid
= NULL
;
6882 OSSharedPtr
<OSKext
> kext
= OSKext::lookupKextWithAddress((vm_address_t
)handler
);
6884 data
= kext
->copyUUID();
6886 if (data
&& (data
->getLength() == sizeof(uuid_t
))) {
6887 uuid
= (uint8_t *)(data
->getBytesNoCopy());
6889 notifier
->uuid0
= ((uint64_t)(uuid
[0]) << 56) | ((uint64_t)(uuid
[1]) << 48) | ((uint64_t)(uuid
[2]) << 40) |
6890 ((uint64_t)(uuid
[3]) << 32) | ((uint64_t)(uuid
[4]) << 24) | ((uint64_t)(uuid
[5]) << 16) |
6891 ((uint64_t)(uuid
[6]) << 8) | (uuid
[7]);
6892 notifier
->uuid1
= ((uint64_t)(uuid
[8]) << 56) | ((uint64_t)(uuid
[9]) << 48) | ((uint64_t)(uuid
[10]) << 40) |
6893 ((uint64_t)(uuid
[11]) << 32) | ((uint64_t)(uuid
[12]) << 24) | ((uint64_t)(uuid
[13]) << 16) |
6894 ((uint64_t)(uuid
[14]) << 8) | (uuid
[15]);
6896 notifier
->identifier
= copyKextIdentifierWithAddress((vm_address_t
) handler
);
6898 return OSSharedPtr
<IOPMServiceInterestNotifier
>(notifier
, OSNoRetain
);
6901 //******************************************************************************
6902 // systemMessageFilter
6904 //******************************************************************************
6907 IOPMrootDomain::systemMessageFilter(
6908 void * object
, void * arg1
, void * arg2
, void * arg3
)
6910 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
6911 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
6912 bool isCapClient
= false;
6914 IOPMServiceInterestNotifier
*notifier
;
6916 notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, (OSObject
*)object
);
6919 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
6920 (!isCapMsg
|| !_joinedCapabilityClients
||
6921 !_joinedCapabilityClients
->containsObject((OSObject
*) object
))) {
6925 // Capability change message for app and kernel clients.
6929 if ((context
->notifyType
== kNotifyPriority
) ||
6930 (context
->notifyType
== kNotifyCapabilityChangePriority
)) {
6934 // powerd's systemCapabilityNotifier
6935 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
6936 (object
== (void *) systemCapabilityNotifier
.get())) {
6942 IOPMSystemCapabilityChangeParameters
* capArgs
=
6943 (IOPMSystemCapabilityChangeParameters
*) arg2
;
6945 if (kSystemTransitionNewCapClient
== _systemTransitionType
) {
6946 capArgs
->fromCapabilities
= 0;
6947 capArgs
->toCapabilities
= _currentCapability
;
6948 capArgs
->changeFlags
= 0;
6950 capArgs
->fromCapabilities
= _currentCapability
;
6951 capArgs
->toCapabilities
= _pendingCapability
;
6953 if (context
->isPreChange
) {
6954 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
6956 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
6959 if ((object
== (void *) systemCapabilityNotifier
.get()) &&
6960 context
->isPreChange
) {
6961 toldPowerdCapWillChange
= true;
6965 // Capability change messages only go to the PM configd plugin.
6966 // Wait for response post-change if capabilitiy is increasing.
6967 // Wait for response pre-change if capability is decreasing.
6969 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
6970 ((capabilityLoss
&& context
->isPreChange
) ||
6971 (!capabilityLoss
&& !context
->isPreChange
))) {
6972 // app has not replied yet, wait for it
6973 *((OSObject
**) arg3
) = kOSBooleanFalse
;
6980 // Capability client will always see kIOMessageCanSystemSleep,
6981 // even for demand sleep. It will also have a chance to veto
6982 // sleep one last time after all clients have responded to
6983 // kIOMessageSystemWillSleep
6985 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
6986 (kIOMessageSystemWillNotSleep
== context
->messageType
)) {
6987 if (object
== (OSObject
*) systemCapabilityNotifier
.get()) {
6992 // Not idle sleep, don't ask apps.
6993 if (context
->changeFlags
& kIOPMSkipAskPowerDown
) {
6998 if (kIOPMMessageLastCallBeforeSleep
== context
->messageType
) {
6999 if ((object
== (OSObject
*) systemCapabilityNotifier
.get()) &&
7000 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) &&
7001 (fullToDarkReason
== kIOPMSleepReasonIdle
)) {
7007 // Reject capability change messages for legacy clients.
7008 // Reject legacy system sleep messages for capability client.
7010 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
.get())) {
7014 // Filter system sleep messages.
7016 if ((context
->notifyType
== kNotifyApps
) &&
7017 (_systemMessageClientMask
& kSystemMessageClientLegacyApp
)) {
7022 if (notifier
->ackTimeoutCnt
>= 3) {
7023 *((OSObject
**) arg3
) = kOSBooleanFalse
;
7025 *((OSObject
**) arg3
) = kOSBooleanTrue
;
7029 } else if ((context
->notifyType
== kNotifyPriority
) &&
7030 (_systemMessageClientMask
& kSystemMessageClientKernel
)) {
7035 if (allow
&& isCapMsg
&& _joinedCapabilityClients
) {
7036 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
7037 if (_joinedCapabilityClients
->getCount() == 0) {
7038 DLOG("destroyed capability client set %p\n",
7039 OBFUSCATE(_joinedCapabilityClients
.get()));
7040 _joinedCapabilityClients
.reset();
7044 notifier
->msgType
= context
->messageType
;
7050 //******************************************************************************
7051 // setMaintenanceWakeCalendar
7053 //******************************************************************************
7056 IOPMrootDomain::setMaintenanceWakeCalendar(
7057 const IOPMCalendarStruct
* calendar
)
7059 OSSharedPtr
<OSData
> data
;
7063 return kIOReturnBadArgument
;
7066 data
= OSData::withBytes((void *) calendar
, sizeof(*calendar
));
7068 return kIOReturnNoMemory
;
7071 if (kPMCalendarTypeMaintenance
== calendar
->selector
) {
7072 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
.get(), data
.get());
7073 } else if (kPMCalendarTypeSleepService
== calendar
->selector
) {
7074 ret
= setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey
.get(), data
.get());
7081 // MARK: Display Wrangler
7083 //******************************************************************************
7084 // displayWranglerNotification
7086 // Handle the notification when the IODisplayWrangler changes power state.
7087 //******************************************************************************
7090 IOPMrootDomain::displayWranglerNotification(
7091 void * target
, void * refCon
,
7092 UInt32 messageType
, IOService
* service
,
7093 void * messageArgument
, vm_size_t argSize
)
7095 #if DISPLAY_WRANGLER_PRESENT
7096 IOPMPowerStateIndex displayPowerState
;
7097 IOPowerStateChangeNotification
* params
=
7098 (IOPowerStateChangeNotification
*) messageArgument
;
7100 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
7101 (messageType
!= kIOMessageDeviceHasPoweredOn
)) {
7102 return kIOReturnUnsupported
;
7107 return kIOReturnUnsupported
;
7110 displayPowerState
= params
->stateNumber
;
7111 DLOG("wrangler %s ps %d\n",
7112 getIOMessageString(messageType
), (uint32_t) displayPowerState
);
7114 switch (messageType
) {
7115 case kIOMessageDeviceWillPowerOff
:
7116 // Display wrangler has dropped power due to display idle
7117 // or force system sleep.
7119 // 4 Display ON kWranglerPowerStateMax
7120 // 3 Display Dim kWranglerPowerStateDim
7121 // 2 Display Sleep kWranglerPowerStateSleep
7122 // 1 Not visible to user
7123 // 0 Not visible to user kWranglerPowerStateMin
7125 if (displayPowerState
<= kWranglerPowerStateSleep
) {
7126 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
7130 case kIOMessageDeviceHasPoweredOn
:
7131 // Display wrangler has powered on due to user activity
7132 // or wake from sleep.
7134 if (kWranglerPowerStateMax
== displayPowerState
) {
7135 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
7137 // See comment in handleUpdatePowerClientForDisplayWrangler
7138 if (service
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
7139 kWranglerPowerStateMax
) {
7140 gRootDomain
->evaluatePolicy( kStimulusEnterUserActiveState
);
7145 #endif /* DISPLAY_WRANGLER_PRESENT */
7146 return kIOReturnUnsupported
;
7149 //******************************************************************************
7152 //******************************************************************************
7155 IOPMrootDomain::updateUserActivity( void )
7157 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
7158 clock_get_uptime(&userActivityTime
);
7159 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonSoftware
)
7160 || (lastSleepReason
== kIOPMSleepReasonIdle
)
7161 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
7163 userActivityCount
++;
7164 DLOG("user activity reported %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
7169 IOPMrootDomain::reportUserInput( void )
7172 wrangler
->activityTickle(0, 0);
7174 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
7175 // Update user activity
7176 updateUserActivity();
7178 if (!darkWakeExit
&& ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0)) {
7179 // update user active abs time
7180 clock_get_uptime(&gUserActiveAbsTime
);
7181 pmPowerStateQueue
->submitPowerEvent(
7182 kPowerEventPolicyStimulus
,
7183 (void *) kStimulusDarkWakeActivityTickle
,
7184 true /* set wake type */ );
7190 IOPMrootDomain::requestUserActive(IOService
*device
, const char *reason
)
7192 #if DISPLAY_WRANGLER_PRESENT
7194 wrangler
->activityTickle(0, 0);
7198 DLOG("requestUserActive: device is null\n");
7201 OSSharedPtr
<const OSSymbol
> deviceName
= device
->copyName();
7202 uint64_t registryID
= device
->getRegistryEntryID();
7204 if (!deviceName
|| !registryID
) {
7205 DLOG("requestUserActive: no device name or registry entry\n");
7208 const char *name
= deviceName
->getCStringNoCopy();
7210 snprintf(payload
, sizeof(payload
), "%s:%s", name
, reason
);
7211 DLOG("requestUserActive from %s (0x%llx) for %s\n", name
, registryID
, reason
);
7212 messageClient(kIOPMMessageRequestUserActive
, systemCapabilityNotifier
.get(), (void *)payload
, sizeof(payload
));
7216 //******************************************************************************
7217 // latchDisplayWranglerTickle
7218 //******************************************************************************
7221 IOPMrootDomain::latchDisplayWranglerTickle( bool latch
)
7223 #if DISPLAY_WRANGLER_PRESENT
7225 if (!(_currentCapability
& kIOPMSystemCapabilityGraphics
) &&
7226 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
7227 !checkSystemCanSustainFullWake()) {
7228 // Currently in dark wake, and not transitioning to full wake.
7229 // Full wake is unsustainable, so latch the tickle to prevent
7230 // the display from lighting up momentarily.
7231 wranglerTickled
= true;
7233 wranglerTickled
= false;
7235 } else if (wranglerTickled
&& checkSystemCanSustainFullWake()) {
7236 wranglerTickled
= false;
7238 pmPowerStateQueue
->submitPowerEvent(
7239 kPowerEventPolicyStimulus
,
7240 (void *) kStimulusDarkWakeActivityTickle
);
7243 return wranglerTickled
;
7244 #else /* ! DISPLAY_WRANGLER_PRESENT */
7246 #endif /* ! DISPLAY_WRANGLER_PRESENT */
7249 //******************************************************************************
7250 // setDisplayPowerOn
7252 // For root domain user client
7253 //******************************************************************************
7256 IOPMrootDomain::setDisplayPowerOn( uint32_t options
)
7258 pmPowerStateQueue
->submitPowerEvent( kPowerEventSetDisplayPowerOn
,
7259 (void *) NULL
, options
);
7263 // MARK: System PM Policy
7265 //******************************************************************************
7266 // checkSystemSleepAllowed
7268 //******************************************************************************
7271 IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options
,
7272 uint32_t sleepReason
)
7276 // Conditions that prevent idle and demand system sleep.
7279 if (userDisabledAllSleep
) {
7280 err
= kPMUserDisabledAllSleep
; // 1. user-space sleep kill switch
7284 if (systemBooting
|| systemShutdown
|| gWillShutdown
) {
7285 err
= kPMSystemRestartBootingInProgress
; // 2. restart or shutdown in progress
7293 // Conditions above pegs the system at full wake.
7294 // Conditions below prevent system sleep but does not prevent
7295 // dark wake, and must be called from gated context.
7298 err
= kPMConfigPreventSystemSleep
; // 3. config does not support sleep
7302 if (lowBatteryCondition
|| thermalWarningState
|| thermalEmergencyState
) {
7303 break; // always sleep on low battery or when in thermal warning/emergency state
7306 if (sleepReason
== kIOPMSleepReasonDarkWakeThermalEmergency
) {
7307 break; // always sleep on dark wake thermal emergencies
7310 if (preventSystemSleepList
->getCount() != 0) {
7311 err
= kPMChildPreventSystemSleep
; // 4. child prevent system sleep clamp
7315 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
7316 kIOPMDriverAssertionLevelOn
) {
7317 err
= kPMCPUAssertion
; // 5. CPU assertion
7321 if (pciCantSleepValid
) {
7322 if (pciCantSleepFlag
) {
7323 err
= kPMPCIUnsupported
; // 6. PCI card does not support PM (cached)
7326 } else if (sleepSupportedPEFunction
&&
7327 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
)) {
7329 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
7330 ret
= getPlatform()->callPlatformFunction(
7331 sleepSupportedPEFunction
.get(), false,
7332 NULL
, NULL
, NULL
, NULL
);
7333 pciCantSleepValid
= true;
7334 pciCantSleepFlag
= false;
7335 if ((platformSleepSupport
& kPCICantSleep
) ||
7336 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
))) {
7337 err
= 6; // 6. PCI card does not support PM
7338 pciCantSleepFlag
= true;
7345 DLOG("System sleep prevented by %s\n", getSystemSleepPreventerString(err
));
7352 IOPMrootDomain::checkSystemSleepEnabled( void )
7354 return checkSystemSleepAllowed(0, 0);
7358 IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason
)
7361 return checkSystemSleepAllowed(1, sleepReason
);
7364 //******************************************************************************
7365 // checkSystemCanSustainFullWake
7366 //******************************************************************************
7369 IOPMrootDomain::checkSystemCanSustainFullWake( void )
7371 if (lowBatteryCondition
|| thermalWarningState
|| thermalEmergencyState
) {
7372 // Low battery wake, or received a low battery notification
7373 // while system is awake. This condition will persist until
7374 // the following wake.
7378 if (clamshellExists
&& clamshellClosed
&& !clamshellSleepDisableMask
) {
7379 // Graphics state is unknown and external display might not be probed.
7380 // Do not incorporate state that requires graphics to be in max power
7381 // such as desktopMode or clamshellDisabled.
7383 if (!acAdaptorConnected
) {
7384 DLOG("full wake check: no AC\n");
7391 //******************************************************************************
7393 //******************************************************************************
7398 IOPMrootDomain::mustHibernate( void )
7400 return lowBatteryCondition
|| thermalWarningState
;
7403 #endif /* HIBERNATION */
7405 //******************************************************************************
7407 //******************************************************************************
7409 // Tables for accumulated days in year by month, latter used for leap years
7411 static const unsigned int daysbymonth
[] =
7412 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
7414 static const unsigned int lydaysbymonth
[] =
7415 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 };
7418 IOPMConvertSecondsToCalendar(clock_sec_t secs
, IOPMCalendarStruct
* dt
)
7420 const unsigned int * dbm
= daysbymonth
;
7421 clock_sec_t n
, x
, y
, z
;
7423 // Calculate seconds, minutes and hours
7425 n
= secs
% (24 * 3600);
7426 dt
->second
= n
% 60;
7428 dt
->minute
= n
% 60;
7429 dt
->hour
= (typeof(dt
->hour
))(n
/ 60);
7431 // Calculate day of week
7433 n
= secs
/ (24 * 3600);
7434 // dt->dayWeek = (n + 4) % 7;
7437 // Rebase from days since Unix epoch (1/1/1970) store in 'n',
7438 // to days since 1/1/1968 to start on 4 year cycle, beginning
7443 // Every 4 year cycle will be exactly (366 + 365 * 3) = 1461 days.
7444 // Valid before 2100, since 2100 is not a leap year.
7446 x
= n
/ 1461; // number of 4 year cycles
7447 y
= n
% 1461; // days into current 4 year cycle
7450 // Add in years in the current 4 year cycle
7453 y
-= 366; // days after the leap year
7454 n
= y
% 365; // days into the current year
7455 z
+= (1 + y
/ 365); // years after the past 4-yr cycle
7458 dbm
= lydaysbymonth
;
7464 dt
->year
= (typeof(dt
->year
))z
;
7466 // Adjust remaining days value to start at 1
7472 for (x
= 1; (n
> dbm
[x
]) && (x
< 12); x
++) {
7475 dt
->month
= (typeof(dt
->month
))x
;
7477 // Calculate day of month
7479 dt
->day
= (typeof(dt
->day
))(n
- dbm
[x
- 1]);
7485 IOPMConvertCalendarToSeconds(const IOPMCalendarStruct
* dt
)
7487 const unsigned int * dbm
= daysbymonth
;
7490 if (dt
->year
< 1970 || dt
->month
> 12) {
7494 // Seconds elapsed in the current day
7496 secs
= dt
->second
+ 60 * dt
->minute
+ 3600 * dt
->hour
;
7498 // Number of days from 1/1/70 to beginning of current year
7499 // Account for extra day every 4 years starting at 1973
7501 y
= dt
->year
- 1970;
7502 days
= (y
* 365) + ((y
+ 1) / 4);
7504 // Change table if current year is a leap year
7506 if ((dt
->year
% 4) == 0) {
7507 dbm
= lydaysbymonth
;
7510 // Add in days elapsed in the current year
7512 days
+= (dt
->day
- 1) + dbm
[dt
->month
- 1];
7514 // Add accumulated days to accumulated seconds
7516 secs
+= 24 * 3600 * days
;
7522 IOPMrootDomain::getRUN_STATE(void)
7524 return _aotNow
? AOT_STATE
: ON_STATE
;
7528 IOPMrootDomain::isAOTMode()
7534 IOPMrootDomain::setWakeTime(uint64_t wakeContinuousTime
)
7536 clock_sec_t nowsecs
, wakesecs
;
7537 clock_usec_t nowmicrosecs
, wakemicrosecs
;
7538 uint64_t nowAbs
, wakeAbs
;
7540 clock_gettimeofday_and_absolute_time(&nowsecs
, &nowmicrosecs
, &nowAbs
);
7541 wakeAbs
= continuoustime_to_absolutetime(wakeContinuousTime
);
7542 if (wakeAbs
< nowAbs
) {
7543 printf(LOG_PREFIX
"wakeAbs %qd < nowAbs %qd\n", wakeAbs
, nowAbs
);
7547 absolutetime_to_microtime(wakeAbs
, &wakesecs
, &wakemicrosecs
);
7549 wakesecs
+= nowsecs
;
7550 wakemicrosecs
+= nowmicrosecs
;
7551 if (wakemicrosecs
>= USEC_PER_SEC
) {
7553 wakemicrosecs
-= USEC_PER_SEC
;
7555 if (wakemicrosecs
>= (USEC_PER_SEC
/ 10)) {
7559 IOPMConvertSecondsToCalendar(wakesecs
, &_aotWakeTimeCalendar
);
7561 if (_aotWakeTimeContinuous
!= wakeContinuousTime
) {
7562 _aotWakeTimeContinuous
= wakeContinuousTime
;
7563 IOLog(LOG_PREFIX
"setWakeTime: " YMDTF
"\n", YMDT(&_aotWakeTimeCalendar
));
7565 _aotWakeTimeCalendar
.selector
= kPMCalendarTypeMaintenance
;
7566 _aotWakeTimeUTC
= wakesecs
;
7568 return kIOReturnSuccess
;
7571 // assumes WAKEEVENT_LOCK
7573 IOPMrootDomain::aotShouldExit(bool checkTimeSet
, bool software
)
7576 const char * reason
= "";
7580 _aotMetrics
->softwareRequestCount
++;
7581 reason
= "software request";
7582 } else if (kIOPMWakeEventAOTExitFlags
& _aotPendingFlags
) {
7584 reason
= gWakeReasonString
;
7585 } else if (checkTimeSet
&& (kPMCalendarTypeInvalid
== _aotWakeTimeCalendar
.selector
)) {
7587 _aotMetrics
->noTimeSetCount
++;
7588 reason
= "flipbook expired";
7589 } else if ((kIOPMAOTModeRespectTimers
& _aotMode
) && _calendarWakeAlarmUTC
) {
7592 clock_get_calendar_microtime(&sec
, &usec
);
7593 if (_calendarWakeAlarmUTC
<= sec
) {
7595 _aotMetrics
->rtcAlarmsCount
++;
7596 reason
= "user alarm";
7599 exitNow
= (_aotNow
&& _aotExit
);
7602 IOLog(LOG_PREFIX
"AOT exit for %s, sc %d po %d, cp %d, rj %d, ex %d, nt %d, rt %d\n",
7604 _aotMetrics
->sleepCount
,
7605 _aotMetrics
->possibleCount
,
7606 _aotMetrics
->confirmedPossibleCount
,
7607 _aotMetrics
->rejectedPossibleCount
,
7608 _aotMetrics
->expiredPossibleCount
,
7609 _aotMetrics
->noTimeSetCount
,
7610 _aotMetrics
->rtcAlarmsCount
);
7616 IOPMrootDomain::aotExit(bool cps
)
7618 uint32_t savedMessageMask
;
7621 _aotTasksSuspended
= false;
7622 _aotReadyToFullWake
= false;
7623 if (_aotTimerScheduled
) {
7624 _aotTimerES
->cancelTimeout();
7625 _aotTimerScheduled
= false;
7627 updateTasksSuspend();
7629 _aotMetrics
->totalTime
+= mach_absolute_time() - _aotLastWakeTime
;
7630 _aotLastWakeTime
= 0;
7631 if (_aotMetrics
->sleepCount
&& (_aotMetrics
->sleepCount
<= kIOPMAOTMetricsKernelWakeCountMax
)) {
7633 strlcpy(&_aotMetrics
->kernelWakeReason
[_aotMetrics
->sleepCount
- 1][0],
7635 sizeof(_aotMetrics
->kernelWakeReason
[_aotMetrics
->sleepCount
]));
7639 _aotWakeTimeCalendar
.selector
= kPMCalendarTypeInvalid
;
7641 // Preserve the message mask since a system wake transition
7642 // may have already started and initialized the mask.
7643 savedMessageMask
= _systemMessageClientMask
;
7644 _systemMessageClientMask
= kSystemMessageClientLegacyApp
;
7645 tellClients(kIOMessageSystemWillPowerOn
);
7646 _systemMessageClientMask
= savedMessageMask
| kSystemMessageClientLegacyApp
;
7649 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonAOTExit
);
7654 IOPMrootDomain::aotEvaluate(IOTimerEventSource
* timer
)
7658 IOLog("aotEvaluate(%d) 0x%x\n", (timer
!= NULL
), _aotPendingFlags
);
7661 exitNow
= aotShouldExit(false, false);
7662 if (timer
!= NULL
) {
7663 _aotTimerScheduled
= false;
7670 if (_aotLingerTime
) {
7672 IOLog("aot linger before sleep\n");
7673 clock_absolutetime_interval_to_deadline(_aotLingerTime
, &deadline
);
7674 clock_delay_until(deadline
);
7677 privateSleepSystem(kIOPMSleepReasonSoftware
);
7681 //******************************************************************************
7684 // Conditions that affect our wake/sleep decision has changed.
7685 // If conditions dictate that the system must remain awake, clamp power
7686 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
7687 // is TRUE, then remove the power clamp and allow the power state to drop
7689 //******************************************************************************
7692 IOPMrootDomain::adjustPowerState( bool sleepASAP
)
7694 DEBUG_LOG("adjustPowerState %s, asap %d, idleSleepEnabled %d\n",
7695 getPowerStateString((uint32_t) getPowerState()), sleepASAP
, idleSleepEnabled
);
7702 if (AOT_STATE
!= getPowerState()) {
7706 exitNow
= aotShouldExit(true, false);
7708 && !_aotTimerScheduled
7709 && (kIOPMWakeEventAOTPossibleExit
== (kIOPMWakeEventAOTPossibleFlags
& _aotPendingFlags
))) {
7710 _aotTimerScheduled
= true;
7711 if (_aotLingerTime
) {
7712 _aotTimerES
->setTimeout(_aotLingerTime
);
7714 _aotTimerES
->setTimeout(800, kMillisecondScale
);
7721 _aotReadyToFullWake
= true;
7722 if (!_aotTimerScheduled
) {
7723 privateSleepSystem(kIOPMSleepReasonSoftware
);
7729 if ((!idleSleepEnabled
) || !checkSystemSleepEnabled()) {
7730 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonAdjustPowerState
);
7731 } else if (sleepASAP
) {
7732 changePowerStateWithTagToPriv(SLEEP_STATE
, kCPSReasonAdjustPowerState
);
7737 IOPMrootDomain::handleSetDisplayPowerOn(bool powerOn
)
7740 if (!checkSystemCanSustainFullWake()) {
7741 DLOG("System cannot sustain full wake\n");
7745 // Force wrangler to max power state. If system is in dark wake
7746 // this alone won't raise the wrangler's power state.
7748 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMax
);
7751 // System in dark wake, always requesting full wake should
7752 // not have any bad side-effects, even if the request fails.
7754 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
)) {
7755 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeNotification
);
7756 requestFullWake( kFullWakeReasonDisplayOn
);
7759 // Relenquish desire to power up display.
7760 // Must first transition to state 1 since wrangler doesn't
7761 // power off the displays at state 0. At state 0 the root
7762 // domain is removed from the wrangler's power client list.
7764 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
+ 1);
7765 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
);
7770 //******************************************************************************
7771 // dispatchPowerEvent
7773 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
7774 //******************************************************************************
7777 IOPMrootDomain::dispatchPowerEvent(
7778 uint32_t event
, void * arg0
, uint64_t arg1
)
7783 case kPowerEventFeatureChanged
:
7784 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7785 messageClients(kIOPMMessageFeatureChange
, this);
7788 case kPowerEventReceivedPowerNotification
:
7789 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7790 handlePowerNotification((UInt32
)(uintptr_t) arg0
);
7793 case kPowerEventSystemBootCompleted
:
7794 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7795 if (systemBooting
) {
7796 systemBooting
= false;
7798 // read noidle setting from Device Tree
7799 OSSharedPtr
<IORegistryEntry
> defaults
= IORegistryEntry::fromPath("IODeviceTree:/defaults");
7800 if (defaults
!= NULL
) {
7801 OSSharedPtr
<OSObject
> noIdleProp
= defaults
->copyProperty("no-idle");
7802 OSData
*data
= OSDynamicCast(OSData
, noIdleProp
.get());
7803 if ((data
!= NULL
) && (data
->getLength() == 4)) {
7804 gNoIdleFlag
= *(uint32_t*)data
->getBytesNoCopy();
7805 DLOG("Setting gNoIdleFlag to %u from device tree\n", gNoIdleFlag
);
7808 if (lowBatteryCondition
|| thermalEmergencyState
) {
7809 if (lowBatteryCondition
) {
7810 privateSleepSystem(kIOPMSleepReasonLowPower
);
7812 privateSleepSystem(kIOPMSleepReasonThermalEmergency
);
7814 // The rest is unnecessary since the system is expected
7815 // to sleep immediately. The following wake will update
7820 sleepWakeDebugMemAlloc();
7821 saveFailureData2File();
7823 // If lid is closed, re-send lid closed notification
7824 // now that booting is complete.
7825 if (clamshellClosed
) {
7826 handlePowerNotification(kLocalEvalClamshellCommand
);
7828 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
7832 case kPowerEventSystemShutdown
:
7833 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7834 if (kOSBooleanTrue
== (OSBoolean
*) arg0
) {
7835 /* We set systemShutdown = true during shutdown
7836 * to prevent sleep at unexpected times while loginwindow is trying
7837 * to shutdown apps and while the OS is trying to transition to
7838 * complete power of.
7840 * Set to true during shutdown, as soon as loginwindow shows
7841 * the "shutdown countdown dialog", through individual app
7842 * termination, and through black screen kernel shutdown.
7844 systemShutdown
= true;
7847 * A shutdown was initiated, but then the shutdown
7848 * was cancelled, clearing systemShutdown to false here.
7850 systemShutdown
= false;
7854 case kPowerEventUserDisabledSleep
:
7855 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7856 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
7859 case kPowerEventRegisterSystemCapabilityClient
:
7860 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7862 // reset() handles the arg0 == nullptr case for us
7863 systemCapabilityNotifier
.reset((IONotifier
*) arg0
, OSRetain
);
7864 /* intentional fall-through */
7865 [[clang::fallthrough]];
7867 case kPowerEventRegisterKernelCapabilityClient
:
7868 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7869 if (!_joinedCapabilityClients
) {
7870 _joinedCapabilityClients
= OSSet::withCapacity(8);
7873 OSSharedPtr
<IONotifier
> notify((IONotifier
*) arg0
, OSNoRetain
);
7874 if (_joinedCapabilityClients
) {
7875 _joinedCapabilityClients
->setObject(notify
.get());
7876 synchronizePowerTree( kIOPMSyncNoChildNotify
);
7881 case kPowerEventPolicyStimulus
:
7882 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7884 int stimulus
= (int)(uintptr_t) arg0
;
7885 evaluatePolicy(stimulus
, (uint32_t) arg1
);
7889 case kPowerEventAssertionCreate
:
7890 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7892 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
7897 case kPowerEventAssertionRelease
:
7898 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7900 pmAssertions
->handleReleaseAssertion(arg1
);
7904 case kPowerEventAssertionSetLevel
:
7905 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7907 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
7911 case kPowerEventQueueSleepWakeUUID
:
7912 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7913 handleQueueSleepWakeUUID((OSObject
*)arg0
);
7915 case kPowerEventPublishSleepWakeUUID
:
7916 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7917 handlePublishSleepWakeUUID((bool)arg0
);
7920 case kPowerEventSetDisplayPowerOn
:
7921 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7923 displayPowerOnRequested
= true;
7925 displayPowerOnRequested
= false;
7927 handleSetDisplayPowerOn(displayPowerOnRequested
);
7930 case kPowerEventPublishWakeType
:
7931 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7933 // Don't replace wake type property if already set
7934 if ((arg0
== gIOPMWakeTypeUserKey
) ||
7935 !propertyExists(kIOPMRootDomainWakeTypeKey
)) {
7936 const char * wakeType
= NULL
;
7938 if (arg0
== gIOPMWakeTypeUserKey
) {
7939 requestUserActive(this, "WakeTypeUser");
7940 wakeType
= kIOPMRootDomainWakeTypeUser
;
7941 } else if (arg0
== gIOPMSettingDebugWakeRelativeKey
) {
7942 requestUserActive(this, "WakeTypeAlarm");
7943 wakeType
= kIOPMRootDomainWakeTypeAlarm
;
7944 } else if (arg0
== gIOPMSettingSleepServiceWakeCalendarKey
) {
7945 darkWakeSleepService
= true;
7946 wakeType
= kIOPMRootDomainWakeTypeSleepService
;
7947 } else if (arg0
== gIOPMSettingMaintenanceWakeCalendarKey
) {
7948 wakeType
= kIOPMRootDomainWakeTypeMaintenance
;
7952 setProperty(kIOPMRootDomainWakeTypeKey
, wakeType
);
7957 case kPowerEventAOTEvaluate
:
7958 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7959 if (_aotReadyToFullWake
) {
7966 //******************************************************************************
7967 // systemPowerEventOccurred
7969 // The power controller is notifying us of a hardware-related power management
7970 // event that we must handle.
7972 // systemPowerEventOccurred covers the same functionality that
7973 // receivePowerNotification does; it simply provides a richer API for conveying
7974 // more information.
7975 //******************************************************************************
7978 IOPMrootDomain::systemPowerEventOccurred(
7979 const OSSymbol
*event
,
7982 IOReturn attempt
= kIOReturnSuccess
;
7983 OSSharedPtr
<OSNumber
> newNumber
;
7986 return kIOReturnBadArgument
;
7989 newNumber
= OSNumber::withNumber(intValue
, 8 * sizeof(intValue
));
7991 return kIOReturnInternalError
;
7994 attempt
= systemPowerEventOccurred(event
, static_cast<OSObject
*>(newNumber
.get()));
8000 IOPMrootDomain::setThermalState(OSObject
*value
)
8004 if (gIOPMWorkLoop
->inGate() == false) {
8005 gIOPMWorkLoop
->runAction(
8006 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setThermalState
),
8012 if (value
&& (num
= OSDynamicCast(OSNumber
, value
))) {
8013 thermalWarningState
= ((num
->unsigned32BitValue() == kIOPMThermalLevelWarning
) ||
8014 (num
->unsigned32BitValue() == kIOPMThermalLevelTrap
)) ? 1 : 0;
8019 IOPMrootDomain::systemPowerEventOccurred(
8020 const OSSymbol
*event
,
8023 OSSharedPtr
<OSDictionary
> thermalsDict
;
8024 bool shouldUpdate
= true;
8026 if (!event
|| !value
) {
8027 return kIOReturnBadArgument
;
8031 // We reuse featuresDict Lock because it already exists and guards
8032 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
8033 // of stepping on that lock.
8034 if (featuresDictLock
) {
8035 IOLockLock(featuresDictLock
);
8038 OSSharedPtr
<OSObject
> origThermalsProp
= copyProperty(kIOPMRootDomainPowerStatusKey
);
8039 OSDictionary
* origThermalsDict
= OSDynamicCast(OSDictionary
, origThermalsProp
.get());
8041 if (origThermalsDict
) {
8042 thermalsDict
= OSDictionary::withDictionary(origThermalsDict
);
8044 thermalsDict
= OSDictionary::withCapacity(1);
8047 if (!thermalsDict
) {
8048 shouldUpdate
= false;
8052 thermalsDict
->setObject(event
, value
);
8054 setProperty(kIOPMRootDomainPowerStatusKey
, thermalsDict
.get());
8058 if (featuresDictLock
) {
8059 IOLockUnlock(featuresDictLock
);
8064 event
->isEqualTo(kIOPMThermalLevelWarningKey
)) {
8065 setThermalState(value
);
8067 messageClients(kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
8070 return kIOReturnSuccess
;
8073 //******************************************************************************
8074 // receivePowerNotification
8076 // The power controller is notifying us of a hardware-related power management
8077 // event that we must handle. This may be a result of an 'environment' interrupt
8078 // from the power mgt micro.
8079 //******************************************************************************
8082 IOPMrootDomain::receivePowerNotification( UInt32 msg
)
8084 if (msg
& kIOPMPowerButton
) {
8085 uint32_t currentPhase
= pmTracer
->getTracePhase();
8086 if (currentPhase
!= kIOPMTracePointSystemUp
&& currentPhase
> kIOPMTracePointSystemSleep
) {
8087 DEBUG_LOG("power button pressed during wake. phase = %u\n", currentPhase
);
8088 swd_flags
|= SWD_PWR_BTN_STACKSHOT
;
8089 thread_call_enter(powerButtonDown
);
8091 DEBUG_LOG("power button pressed when system is up\n");
8093 } else if (msg
& kIOPMPowerButtonUp
) {
8094 if (swd_flags
& SWD_PWR_BTN_STACKSHOT
) {
8095 swd_flags
&= ~SWD_PWR_BTN_STACKSHOT
;
8096 thread_call_enter(powerButtonUp
);
8099 pmPowerStateQueue
->submitPowerEvent(
8100 kPowerEventReceivedPowerNotification
, (void *)(uintptr_t) msg
);
8102 return kIOReturnSuccess
;
8106 IOPMrootDomain::handlePowerNotification( UInt32 msg
)
8108 bool eval_clamshell
= false;
8109 bool eval_clamshell_alarm
= false;
8114 * Local (IOPMrootDomain only) eval clamshell command
8116 if (msg
& kLocalEvalClamshellCommand
) {
8117 if ((gClamshellFlags
& kClamshell_WAR_47715679
) && isRTCAlarmWake
) {
8118 eval_clamshell_alarm
= true;
8120 // reset isRTCAlarmWake. This evaluation should happen only once
8121 // on RTC/Alarm wake. Any clamshell events after wake should follow
8122 // the regular evaluation
8123 isRTCAlarmWake
= false;
8125 eval_clamshell
= true;
8132 if (msg
& kIOPMOverTemp
) {
8133 DLOG("Thermal overtemp message received!\n");
8134 thermalEmergencyState
= true;
8135 privateSleepSystem(kIOPMSleepReasonThermalEmergency
);
8139 * Forward DW thermal notification to client, if system is not going to sleep
8141 if ((msg
& kIOPMDWOverTemp
) && (_systemTransitionType
!= kSystemTransitionSleep
)) {
8142 DLOG("DarkWake thermal limits message received!\n");
8143 messageClients(kIOPMMessageDarkWakeThermalEmergency
);
8149 if (msg
& kIOPMSleepNow
) {
8150 privateSleepSystem(kIOPMSleepReasonSoftware
);
8156 if (msg
& kIOPMPowerEmergency
) {
8157 DLOG("Low battery notification received\n");
8158 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
8159 // Wait for the next low battery notification if the system state is
8161 if ((_systemTransitionType
== kSystemTransitionNone
) &&
8162 CAP_CURRENT(kIOPMSystemCapabilityCPU
) &&
8163 !systemBooting
&& !systemShutdown
&& !gWillShutdown
) {
8164 // Setting lowBatteryCondition will prevent system sleep
8165 lowBatteryCondition
= true;
8167 // Notify userspace to initiate system shutdown
8168 messageClients(kIOPMMessageRequestSystemShutdown
);
8171 lowBatteryCondition
= true;
8172 privateSleepSystem(kIOPMSleepReasonLowPower
);
8179 if (msg
& kIOPMClamshellOpened
) {
8180 DLOG("Clamshell opened\n");
8181 // Received clamshel open message from clamshell controlling driver
8182 // Update our internal state and tell general interest clients
8183 clamshellClosed
= false;
8184 clamshellExists
= true;
8186 // Don't issue a hid tickle when lid is open and polled on wake
8187 if (msg
& kIOPMSetValue
) {
8188 setProperty(kIOPMRootDomainWakeTypeKey
, "Lid Open");
8193 informCPUStateChange(kInformLid
, 0);
8195 // Tell general interest clients
8196 sendClientClamshellNotification();
8198 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
8199 || (lastSleepReason
== kIOPMSleepReasonIdle
)
8200 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
8202 userActivityCount
++;
8204 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
8209 * Send the clamshell interest notification since the lid is closing.
8211 if (msg
& kIOPMClamshellClosed
) {
8212 if ((clamshellIgnoreClose
|| (gClamshellFlags
& kClamshell_WAR_38378787
)) &&
8213 clamshellClosed
&& clamshellExists
) {
8214 DLOG("Ignoring redundant Clamshell close event\n");
8216 DLOG("Clamshell closed\n");
8217 // Received clamshel open message from clamshell controlling driver
8218 // Update our internal state and tell general interest clients
8219 clamshellClosed
= true;
8220 clamshellExists
= true;
8222 // Ignore all following clamshell close events until the clamshell
8223 // is opened or the system sleeps. When a clamshell close triggers
8224 // a system wake, the lid driver may send us two clamshell close
8225 // events, one for the clamshell close event itself, and a second
8226 // close event when the driver polls the lid state on wake.
8227 clamshellIgnoreClose
= true;
8230 informCPUStateChange(kInformLid
, 1);
8232 // Tell general interest clients
8233 sendClientClamshellNotification();
8235 // And set eval_clamshell = so we can attempt
8236 eval_clamshell
= true;
8241 * Set Desktop mode (sent from graphics)
8243 * -> reevaluate lid state
8245 if (msg
& kIOPMSetDesktopMode
) {
8246 desktopMode
= (0 != (msg
& kIOPMSetValue
));
8247 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
8248 DLOG("Desktop mode %d\n", desktopMode
);
8250 sendClientClamshellNotification();
8252 // Re-evaluate the lid state
8253 eval_clamshell
= true;
8257 * AC Adaptor connected
8259 * -> reevaluate lid state
8261 if (msg
& kIOPMSetACAdaptorConnected
) {
8262 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
8263 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
8266 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
8268 // Tell BSD if AC is connected
8269 // 0 == external power source; 1 == on battery
8270 post_sys_powersource(acAdaptorConnected
? 0:1);
8272 sendClientClamshellNotification();
8274 // Re-evaluate the lid state
8275 eval_clamshell
= true;
8277 // Lack of AC may have latched a display wrangler tickle.
8278 // This mirrors the hardware's USB wake event latch, where a latched
8279 // USB wake event followed by an AC attach will trigger a full wake.
8280 latchDisplayWranglerTickle( false );
8283 // AC presence will reset the standy timer delay adjustment.
8284 _standbyTimerResetSeconds
= 0;
8286 if (!userIsActive
) {
8287 // Reset userActivityTime when power supply is changed(rdr 13789330)
8288 clock_get_uptime(&userActivityTime
);
8293 * Enable Clamshell (external display disappear)
8295 * -> reevaluate lid state
8297 if (msg
& kIOPMEnableClamshell
) {
8298 DLOG("Clamshell enabled\n");
8300 // Re-evaluate the lid state
8301 // System should sleep on external display disappearance
8302 // in lid closed operation.
8303 if (true == clamshellDisabled
) {
8304 eval_clamshell
= true;
8306 #if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
8307 // Also clear kClamshellSleepDisableInternal when graphics enables
8308 // the clamshell during a full wake. When graphics is behaving as
8309 // expected, this will allow clamshell close to be honored earlier
8310 // rather than waiting for the delayed evaluation.
8311 if ((clamshellSleepDisableMask
& kClamshellSleepDisableInternal
) &&
8312 (CAP_PENDING(kIOPMSystemCapabilityGraphics
) ||
8313 CAP_CURRENT(kIOPMSystemCapabilityGraphics
))) {
8314 setClamShellSleepDisable(false, kClamshellSleepDisableInternal
);
8316 // Cancel the TC to avoid an extra kLocalEvalClamshellCommand
8317 // when timer expires which is harmless but useless.
8318 thread_call_cancel(fullWakeThreadCall
);
8323 clamshellDisabled
= false;
8324 sendClientClamshellNotification();
8328 * Disable Clamshell (external display appeared)
8329 * We don't bother re-evaluating clamshell state. If the system is awake,
8330 * the lid is probably open.
8332 if (msg
& kIOPMDisableClamshell
) {
8333 DLOG("Clamshell disabled\n");
8334 clamshellDisabled
= true;
8335 sendClientClamshellNotification();
8339 * Evaluate clamshell and SLEEP if appropriate
8341 if (eval_clamshell_alarm
&& clamshellClosed
) {
8342 if (shouldSleepOnRTCAlarmWake()) {
8343 privateSleepSystem(kIOPMSleepReasonClamshell
);
8345 } else if (eval_clamshell
&& clamshellClosed
) {
8346 if (shouldSleepOnClamshellClosed()) {
8347 privateSleepSystem(kIOPMSleepReasonClamshell
);
8349 evaluatePolicy( kStimulusDarkWakeEvaluate
);
8353 if (msg
& kIOPMProModeEngaged
) {
8355 DLOG("ProModeEngaged\n");
8356 messageClient(kIOPMMessageProModeStateChange
, systemCapabilityNotifier
.get(), &newState
, sizeof(newState
));
8359 if (msg
& kIOPMProModeDisengaged
) {
8361 DLOG("ProModeDisengaged\n");
8362 messageClient(kIOPMMessageProModeStateChange
, systemCapabilityNotifier
.get(), &newState
, sizeof(newState
));
8366 //******************************************************************************
8369 // Evaluate root-domain policy in response to external changes.
8370 //******************************************************************************
8373 IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
8377 int idleSleepEnabled
: 1;
8378 int idleSleepDisabled
: 1;
8379 int displaySleep
: 1;
8380 int sleepDelayChanged
: 1;
8381 int evaluateDarkWake
: 1;
8382 int adjustPowerState
: 1;
8383 int userBecameInactive
: 1;
8384 int displaySleepEntry
: 1;
8394 case kStimulusDisplayWranglerSleep
:
8395 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8396 if (!wranglerPowerOff
) {
8397 // wrangler is in sleep state or lower
8398 flags
.bit
.displaySleep
= true;
8400 if (!wranglerAsleep
) {
8401 // transition from wrangler wake to wrangler sleep
8402 flags
.bit
.displaySleepEntry
= true;
8403 wranglerAsleep
= true;
8407 case kStimulusDisplayWranglerWake
:
8408 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8409 displayIdleForDemandSleep
= false;
8410 wranglerPowerOff
= false;
8411 wranglerAsleep
= false;
8414 case kStimulusEnterUserActiveState
:
8415 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8416 if (_preventUserActive
) {
8417 DLOG("user active dropped\n");
8420 if (!userIsActive
) {
8421 userIsActive
= true;
8422 userWasActive
= true;
8423 clock_get_uptime(&gUserActiveAbsTime
);
8425 // Stay awake after dropping demand for display power on
8426 if (kFullWakeReasonDisplayOn
== fullWakeReason
) {
8427 fullWakeReason
= fFullWakeReasonDisplayOnAndLocalUser
;
8428 DLOG("User activity while in notification wake\n");
8429 changePowerStateWithOverrideTo( getRUN_STATE(), 0);
8432 kdebugTrace(kPMLogUserActiveState
, 0, 1, 0);
8433 setProperty(gIOPMUserIsActiveKey
.get(), kOSBooleanTrue
);
8434 messageClients(kIOPMMessageUserIsActiveChanged
);
8436 flags
.bit
.idleSleepDisabled
= true;
8439 case kStimulusLeaveUserActiveState
:
8440 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8442 clock_get_uptime(&gUserInactiveAbsTime
);
8443 userIsActive
= false;
8444 clock_get_uptime(&userBecameInactiveTime
);
8445 flags
.bit
.userBecameInactive
= true;
8447 kdebugTrace(kPMLogUserActiveState
, 0, 0, 0);
8448 setProperty(gIOPMUserIsActiveKey
.get(), kOSBooleanFalse
);
8449 messageClients(kIOPMMessageUserIsActiveChanged
);
8453 case kStimulusAggressivenessChanged
:
8455 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8456 unsigned long aggressiveValue
;
8457 uint32_t minutesToIdleSleep
= 0;
8458 uint32_t minutesToDisplayDim
= 0;
8459 uint32_t minutesDelta
= 0;
8461 // Fetch latest display and system sleep slider values.
8462 aggressiveValue
= 0;
8463 getAggressiveness(kPMMinutesToSleep
, &aggressiveValue
);
8464 minutesToIdleSleep
= (uint32_t) aggressiveValue
;
8466 aggressiveValue
= 0;
8467 getAggressiveness(kPMMinutesToDim
, &aggressiveValue
);
8468 minutesToDisplayDim
= (uint32_t) aggressiveValue
;
8469 DLOG("aggressiveness changed: system %u->%u, display %u\n",
8470 sleepSlider
, minutesToIdleSleep
, minutesToDisplayDim
);
8472 DLOG("idle time -> %d secs (ena %d)\n",
8473 idleSeconds
, (minutesToIdleSleep
!= 0));
8475 // How long to wait before sleeping the system once
8476 // the displays turns off is indicated by 'extraSleepDelay'.
8478 if (minutesToIdleSleep
> minutesToDisplayDim
) {
8479 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
8480 } else if (minutesToIdleSleep
== minutesToDisplayDim
) {
8484 if ((!idleSleepEnabled
) && (minutesToIdleSleep
!= 0)) {
8485 idleSleepEnabled
= flags
.bit
.idleSleepEnabled
= true;
8488 if ((idleSleepEnabled
) && (minutesToIdleSleep
== 0)) {
8489 flags
.bit
.idleSleepDisabled
= true;
8490 idleSleepEnabled
= false;
8492 #if !defined(XNU_TARGET_OS_OSX)
8493 if (0x7fffffff == minutesToIdleSleep
) {
8494 minutesToIdleSleep
= idleSeconds
;
8496 #endif /* !defined(XNU_TARGET_OS_OSX) */
8498 if (((minutesDelta
!= extraSleepDelay
) ||
8499 (userActivityTime
!= userActivityTime_prev
)) &&
8500 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
) {
8501 flags
.bit
.sleepDelayChanged
= true;
8504 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
8505 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
)) {
8506 // Reconsider decision to remain in dark wake
8507 flags
.bit
.evaluateDarkWake
= true;
8510 sleepSlider
= minutesToIdleSleep
;
8511 extraSleepDelay
= minutesDelta
;
8512 userActivityTime_prev
= userActivityTime
;
8515 case kStimulusDemandSystemSleep
:
8516 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8517 displayIdleForDemandSleep
= true;
8518 if (wrangler
&& wranglerIdleSettings
) {
8519 // Request wrangler idle only when demand sleep is triggered
8521 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
)) {
8522 wrangler
->setProperties(wranglerIdleSettings
.get());
8523 DLOG("Requested wrangler idle\n");
8526 // arg = sleepReason
8527 changePowerStateWithOverrideTo( SLEEP_STATE
, arg
);
8530 case kStimulusAllowSystemSleepChanged
:
8531 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8532 flags
.bit
.adjustPowerState
= true;
8535 case kStimulusDarkWakeActivityTickle
:
8536 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8537 // arg == true implies real and not self generated wrangler tickle.
8538 // Update wake type on PM work loop instead of the tickle thread to
8539 // eliminate the possibility of an early tickle clobbering the wake
8540 // type set by the platform driver.
8542 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeHIDActivity
);
8545 if (!darkWakeExit
) {
8546 if (latchDisplayWranglerTickle(true)) {
8547 DLOG("latched tickle\n");
8551 darkWakeExit
= true;
8552 DLOG("Requesting full wake due to dark wake activity tickle\n");
8553 requestFullWake( kFullWakeReasonLocalUser
);
8557 case kStimulusDarkWakeEntry
:
8558 case kStimulusDarkWakeReentry
:
8559 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8560 // Any system transitions since the last dark wake transition
8561 // will invalid the stimulus.
8563 if (arg
== _systemStateGeneration
) {
8564 DLOG("dark wake entry\n");
8565 systemDarkWake
= true;
8567 // Keep wranglerPowerOff an invariant when wrangler is absent
8569 wranglerPowerOff
= true;
8572 if (kStimulusDarkWakeEntry
== stimulus
) {
8573 clock_get_uptime(&userBecameInactiveTime
);
8574 flags
.bit
.evaluateDarkWake
= true;
8575 if (activitySinceSleep()) {
8576 DLOG("User activity recorded while going to darkwake\n");
8581 // Always accelerate disk spindown while in dark wake,
8582 // even if system does not support/allow sleep.
8584 cancelIdleSleepTimer();
8585 setQuickSpinDownTimeout();
8589 case kStimulusDarkWakeEvaluate
:
8590 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8591 if (systemDarkWake
) {
8592 flags
.bit
.evaluateDarkWake
= true;
8596 case kStimulusNoIdleSleepPreventers
:
8597 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8598 flags
.bit
.adjustPowerState
= true;
8600 } /* switch(stimulus) */
8602 if (flags
.bit
.evaluateDarkWake
&& (kFullWakeReasonNone
== fullWakeReason
)) {
8603 DLOG("DarkWake: sleepASAP %d, clamshell closed %d, disabled %d/%x, desktopMode %d, ac %d\n",
8604 darkWakeToSleepASAP
, clamshellClosed
, clamshellDisabled
, clamshellSleepDisableMask
, desktopMode
, acAdaptorConnected
);
8605 if (darkWakeToSleepASAP
||
8606 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
))) {
8607 uint32_t newSleepReason
;
8609 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics
)) {
8610 // System was previously in full wake. Sleep reason from
8611 // full to dark already recorded in fullToDarkReason.
8613 if (lowBatteryCondition
) {
8614 newSleepReason
= kIOPMSleepReasonLowPower
;
8615 } else if (thermalEmergencyState
) {
8616 newSleepReason
= kIOPMSleepReasonThermalEmergency
;
8618 newSleepReason
= fullToDarkReason
;
8621 // In dark wake from system sleep.
8623 if (darkWakeSleepService
) {
8624 newSleepReason
= kIOPMSleepReasonSleepServiceExit
;
8626 newSleepReason
= kIOPMSleepReasonMaintenance
;
8630 if (checkSystemCanSleep(newSleepReason
)) {
8631 privateSleepSystem(newSleepReason
);
8633 } else { // non-maintenance (network) dark wake
8634 if (checkSystemCanSleep(kIOPMSleepReasonIdle
)) {
8635 // Release power clamp, and wait for children idle.
8636 adjustPowerState(true);
8638 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonDarkWakeCannotSleep
);
8643 if (systemDarkWake
) {
8644 // The rest are irrelevant while system is in dark wake.
8648 if ((flags
.bit
.displaySleepEntry
) &&
8649 (kFullWakeReasonDisplayOn
== fullWakeReason
)) {
8650 // kIOPMSleepReasonNotificationWakeExit
8651 DLOG("Display sleep while in notification wake\n");
8652 changePowerStateWithOverrideTo(SLEEP_STATE
, kIOPMSleepReasonNotificationWakeExit
);
8655 if (flags
.bit
.userBecameInactive
|| flags
.bit
.sleepDelayChanged
) {
8656 bool cancelQuickSpindown
= false;
8658 if (flags
.bit
.sleepDelayChanged
) {
8659 // Cancel existing idle sleep timer and quick disk spindown.
8660 // New settings will be applied by the idleSleepEnabled flag
8661 // handler below if idle sleep is enabled.
8663 DLOG("extra sleep timer changed\n");
8664 cancelIdleSleepTimer();
8665 cancelQuickSpindown
= true;
8667 DLOG("user inactive\n");
8670 if (!userIsActive
&& idleSleepEnabled
) {
8671 startIdleSleepTimer(getTimeToIdleSleep());
8674 if (cancelQuickSpindown
) {
8675 restoreUserSpinDownTimeout();
8679 if (flags
.bit
.idleSleepEnabled
) {
8680 DLOG("idle sleep timer enabled\n");
8682 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
8683 startIdleSleepTimer(getTimeToIdleSleep());
8685 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonIdleSleepEnabled
);
8686 startIdleSleepTimer( idleSeconds
);
8689 // Start idle timer if prefs now allow system sleep
8690 // and user is already inactive. Disk spindown is
8691 // accelerated upon timer expiration.
8693 if (!userIsActive
) {
8694 startIdleSleepTimer(getTimeToIdleSleep());
8699 if (flags
.bit
.idleSleepDisabled
) {
8700 DLOG("idle sleep timer disabled\n");
8701 cancelIdleSleepTimer();
8702 restoreUserSpinDownTimeout();
8706 if (flags
.bit
.adjustPowerState
) {
8707 bool sleepASAP
= false;
8709 if (!systemBooting
&& (0 == idleSleepPreventersCount())) {
8711 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonEvaluatePolicy
);
8712 if (idleSleepEnabled
) {
8713 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
8714 if (!extraSleepDelay
&& !idleSleepTimerPending
) {
8718 // stay awake for at least idleSeconds
8719 startIdleSleepTimer(idleSeconds
);
8722 } else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
) {
8727 adjustPowerState(sleepASAP
);
8731 //******************************************************************************
8734 IOPMrootDomain::idleSleepPreventersCount()
8737 unsigned int count __block
;
8739 preventIdleSleepList
->iterateObjects(^bool (OSObject
* obj
)
8741 count
+= (NULL
== obj
->metaCast("AppleARMBacklight"));
8747 return preventIdleSleepList
->getCount();
8751 //******************************************************************************
8754 // Request transition from dark wake to full wake
8755 //******************************************************************************
8758 IOPMrootDomain::requestFullWake( FullWakeReason reason
)
8760 uint32_t options
= 0;
8761 IOService
* pciRoot
= NULL
;
8762 bool promotion
= false;
8764 // System must be in dark wake and a valid reason for entering full wake
8765 if ((kFullWakeReasonNone
== reason
) ||
8766 (kFullWakeReasonNone
!= fullWakeReason
) ||
8767 (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))) {
8771 // Will clear reason upon exit from full wake
8772 fullWakeReason
= reason
;
8774 _desiredCapability
|= (kIOPMSystemCapabilityGraphics
|
8775 kIOPMSystemCapabilityAudio
);
8777 if ((kSystemTransitionWake
== _systemTransitionType
) &&
8778 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
8779 !darkWakePowerClamped
) {
8780 // Promote to full wake while waking up to dark wake due to tickle.
8781 // PM will hold off notifying the graphics subsystem about system wake
8782 // as late as possible, so if a HID tickle does arrive, graphics can
8783 // power up from this same wake transition. Otherwise, the latency to
8784 // power up graphics on the following transition can be huge on certain
8785 // systems. However, once any power clamping has taken effect, it is
8786 // too late to promote the current dark wake transition to a full wake.
8787 _pendingCapability
|= (kIOPMSystemCapabilityGraphics
|
8788 kIOPMSystemCapabilityAudio
);
8790 // Tell the PCI parent of audio and graphics drivers to stop
8791 // delaying the child notifications. Same for root domain.
8792 pciRoot
= pciHostBridgeDriver
.get();
8793 willEnterFullWake();
8797 // Unsafe to cancel once graphics was powered.
8798 // If system woke from dark wake, the return to sleep can
8799 // be cancelled. "awake -> dark -> sleep" transition
8800 // can be cancelled also, during the "dark -> sleep" phase
8801 // *prior* to driver power down.
8802 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) ||
8803 _pendingCapability
== 0) {
8804 options
|= kIOPMSyncCancelPowerDown
;
8807 synchronizePowerTree(options
, pciRoot
);
8809 if (kFullWakeReasonLocalUser
== fullWakeReason
) {
8810 // IOGraphics doesn't light the display even though graphics is
8811 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
8812 // So, do an explicit activity tickle
8814 wrangler
->activityTickle(0, 0);
8818 // Log a timestamp for the initial full wake request.
8819 // System may not always honor this full wake request.
8820 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
)) {
8824 clock_get_uptime(&now
);
8825 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
8826 absolutetime_to_nanoseconds(now
, &nsec
);
8827 MSG("full wake %s (reason %u) %u ms\n",
8828 promotion
? "promotion" : "request",
8829 fullWakeReason
, ((int)((nsec
) / NSEC_PER_MSEC
)));
8833 //******************************************************************************
8834 // willEnterFullWake
8836 // System will enter full wake from sleep, from dark wake, or from dark
8837 // wake promotion. This function aggregate things that are in common to
8838 // all three full wake transitions.
8840 // Assumptions: fullWakeReason was updated
8841 //******************************************************************************
8844 IOPMrootDomain::willEnterFullWake( void )
8846 hibernateRetry
= false;
8847 sleepToStandby
= false;
8848 standbyNixed
= false;
8849 resetTimers
= false;
8850 sleepTimerMaintenance
= false;
8852 assert(!CAP_CURRENT(kIOPMSystemCapabilityGraphics
));
8854 _systemMessageClientMask
= kSystemMessageClientPowerd
|
8855 kSystemMessageClientLegacyApp
;
8857 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0) {
8858 // First time to attain full wake capability since the last wake
8859 _systemMessageClientMask
|= kSystemMessageClientKernel
;
8861 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
8862 setProperty(gIOPMUserTriggeredFullWakeKey
.get(),
8863 (kFullWakeReasonLocalUser
== fullWakeReason
) ?
8864 kOSBooleanTrue
: kOSBooleanFalse
);
8867 IOHibernateSetWakeCapabilities(_pendingCapability
);
8870 IOService::setAdvisoryTickleEnable( true );
8871 tellClients(kIOMessageSystemWillPowerOn
);
8872 preventTransitionToUserActive(false);
8875 //******************************************************************************
8876 // fullWakeDelayedWork
8878 // System has already entered full wake. Invoked by a delayed thread call.
8879 //******************************************************************************
8882 IOPMrootDomain::fullWakeDelayedWork( void )
8884 #if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
8885 if (!gIOPMWorkLoop
->inGate()) {
8886 gIOPMWorkLoop
->runAction(
8887 OSMemberFunctionCast(IOWorkLoop::Action
, this,
8888 &IOPMrootDomain::fullWakeDelayedWork
), this);
8892 DLOG("fullWakeDelayedWork cap cur %x pend %x high %x, clamshell disable %x/%x\n",
8893 _currentCapability
, _pendingCapability
, _highestCapability
,
8894 clamshellDisabled
, clamshellSleepDisableMask
);
8896 if (clamshellExists
&&
8897 CAP_CURRENT(kIOPMSystemCapabilityGraphics
) &&
8898 !CAP_CHANGE(kIOPMSystemCapabilityGraphics
)) {
8899 if (clamshellSleepDisableMask
& kClamshellSleepDisableInternal
) {
8900 setClamShellSleepDisable(false, kClamshellSleepDisableInternal
);
8902 // Not the initial full wake after waking from sleep.
8903 // Evaluate the clamshell for rdar://problem/9157444.
8904 receivePowerNotification(kLocalEvalClamshellCommand
);
8910 //******************************************************************************
8911 // evaluateAssertions
8913 //******************************************************************************
8915 // Bitmask of all kernel assertions that prevent system idle sleep.
8916 // kIOPMDriverAssertionReservedBit7 is reserved for IOMediaBSDClient.
8917 #define NO_IDLE_SLEEP_ASSERTIONS_MASK \
8918 (kIOPMDriverAssertionReservedBit7 | \
8919 kIOPMDriverAssertionPreventSystemIdleSleepBit)
8922 IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions
, IOPMDriverAssertionType oldAssertions
)
8924 IOPMDriverAssertionType changedBits
= newAssertions
^ oldAssertions
;
8926 messageClients(kIOPMMessageDriverAssertionsChanged
);
8928 if (changedBits
& kIOPMDriverAssertionPreventDisplaySleepBit
) {
8930 bool value
= (newAssertions
& kIOPMDriverAssertionPreventDisplaySleepBit
) ? true : false;
8932 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value
);
8933 wrangler
->setIgnoreIdleTimer( value
);
8937 if (changedBits
& kIOPMDriverAssertionCPUBit
) {
8939 IOLog("CPU assertions %d\n", (0 != (kIOPMDriverAssertionCPUBit
& newAssertions
)));
8941 evaluatePolicy(_aotNow
? kStimulusNoIdleSleepPreventers
: kStimulusDarkWakeEvaluate
);
8942 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
8944 clock_usec_t microsecs
;
8945 clock_get_uptime(&now
);
8946 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
8947 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
8948 if (assertOnWakeReport
) {
8949 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
8950 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
8955 if (changedBits
& NO_IDLE_SLEEP_ASSERTIONS_MASK
) {
8956 if ((newAssertions
& NO_IDLE_SLEEP_ASSERTIONS_MASK
) != 0) {
8957 if ((oldAssertions
& NO_IDLE_SLEEP_ASSERTIONS_MASK
) == 0) {
8958 DLOG("PreventIdleSleep driver assertion raised\n");
8959 bool ok
= updatePreventIdleSleepList(this, true);
8960 if (ok
&& (changedBits
& kIOPMDriverAssertionPreventSystemIdleSleepBit
)) {
8961 // Cancel idle sleep if there is one in progress
8962 cancelIdlePowerDown(this);
8966 DLOG("PreventIdleSleep driver assertion dropped\n");
8967 updatePreventIdleSleepList(this, false);
8975 //******************************************************************************
8978 //******************************************************************************
8981 IOPMrootDomain::pmStatsRecordEvent(
8983 AbsoluteTime timestamp
)
8985 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
8986 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
8989 OSSharedPtr
<OSData
> publishPMStats
;
8991 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
8993 absolutetime_to_nanoseconds(timestamp
, &nsec
);
8995 switch (eventIndex
) {
8996 case kIOPMStatsHibernateImageWrite
:
8998 gPMStats
.hibWrite
.start
= nsec
;
8999 } else if (stopping
) {
9000 gPMStats
.hibWrite
.stop
= nsec
;
9004 delta
= gPMStats
.hibWrite
.stop
- gPMStats
.hibWrite
.start
;
9005 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/ NSEC_PER_MSEC
);
9008 case kIOPMStatsHibernateImageRead
:
9010 gPMStats
.hibRead
.start
= nsec
;
9011 } else if (stopping
) {
9012 gPMStats
.hibRead
.stop
= nsec
;
9016 delta
= gPMStats
.hibRead
.stop
- gPMStats
.hibRead
.start
;
9017 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/ NSEC_PER_MSEC
);
9019 publishPMStats
= OSData::withBytes(&gPMStats
, sizeof(gPMStats
));
9020 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
.get());
9021 bzero(&gPMStats
, sizeof(gPMStats
));
9028 * Appends a record of the application response to
9029 * IOPMrootDomain::pmStatsAppResponses
9032 IOPMrootDomain::pmStatsRecordApplicationResponse(
9033 const OSSymbol
*response
,
9039 IOPMPowerStateIndex powerState
,
9042 OSSharedPtr
<OSDictionary
> responseDescription
;
9043 OSSharedPtr
<OSNumber
> delayNum
;
9044 OSSharedPtr
<OSNumber
> powerCaps
;
9045 OSSharedPtr
<OSNumber
> pidNum
;
9046 OSSharedPtr
<OSNumber
> msgNum
;
9047 OSSharedPtr
<const OSSymbol
> appname
;
9048 OSSharedPtr
<const OSSymbol
> sleep
;
9049 OSSharedPtr
<const OSSymbol
> wake
;
9050 IOPMServiceInterestNotifier
*notify
= NULL
;
9052 if (object
&& (notify
= OSDynamicCast(IOPMServiceInterestNotifier
, object
))) {
9053 if (response
->isEqualTo(gIOPMStatsResponseTimedOut
.get())) {
9054 notify
->ackTimeoutCnt
++;
9056 notify
->ackTimeoutCnt
= 0;
9060 if (response
->isEqualTo(gIOPMStatsResponsePrompt
.get()) ||
9061 (_systemTransitionType
== kSystemTransitionNone
) || (_systemTransitionType
== kSystemTransitionNewCapClient
)) {
9066 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
.get())) {
9067 kdebugTrace(kPMLogDrvPSChangeDelay
, id
, messageType
, delay_ms
);
9068 } else if (notify
) {
9069 // User space app or kernel capability client
9071 kdebugTrace(kPMLogAppResponseDelay
, id
, notify
->msgType
, delay_ms
);
9073 kdebugTrace(kPMLogDrvResponseDelay
, notify
->uuid0
, messageType
, delay_ms
);
9075 notify
->msgType
= 0;
9078 responseDescription
= OSDictionary::withCapacity(5);
9079 if (responseDescription
) {
9081 responseDescription
->setObject(_statsResponseTypeKey
.get(), response
);
9084 msgNum
= OSNumber::withNumber(messageType
, 32);
9086 responseDescription
->setObject(_statsMessageTypeKey
.get(), msgNum
.get());
9089 if (!name
&& notify
&& notify
->identifier
) {
9090 name
= notify
->identifier
->getCStringNoCopy();
9093 if (name
&& (strlen(name
) > 0)) {
9094 appname
= OSSymbol::withCString(name
);
9096 responseDescription
->setObject(_statsNameKey
.get(), appname
.get());
9100 if (!id
&& notify
) {
9104 pidNum
= OSNumber::withNumber(id
, 64);
9106 responseDescription
->setObject(_statsPIDKey
.get(), pidNum
.get());
9110 delayNum
= OSNumber::withNumber(delay_ms
, 32);
9112 responseDescription
->setObject(_statsTimeMSKey
.get(), delayNum
.get());
9115 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
.get())) {
9116 powerCaps
= OSNumber::withNumber(powerState
, 32);
9118 #if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
9119 static const char * driverCallTypes
[] = {
9120 [kDriverCallInformPreChange
] = "powerStateWillChangeTo",
9121 [kDriverCallInformPostChange
] = "powerStateDidChangeTo",
9122 [kDriverCallSetPowerState
] = "setPowerState"
9125 if (messageType
< (sizeof(driverCallTypes
) / sizeof(driverCallTypes
[0]))) {
9126 DLOG("%s[0x%qx]::%s(%u) %stook %d ms\n",
9127 name
, id
, driverCallTypes
[messageType
], (uint32_t) powerState
,
9128 async
? "async " : "", delay_ms
);
9132 powerCaps
= OSNumber::withNumber(_pendingCapability
, 32);
9135 responseDescription
->setObject(_statsPowerCapsKey
.get(), powerCaps
.get());
9138 sleep
= OSSymbol::withCString("Sleep");
9139 wake
= OSSymbol::withCString("Wake");
9140 if (_systemTransitionType
== kSystemTransitionSleep
) {
9141 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
.get());
9142 } else if (_systemTransitionType
== kSystemTransitionWake
) {
9143 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
.get());
9144 } else if (_systemTransitionType
== kSystemTransitionCapability
) {
9145 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
)) {
9146 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
.get());
9147 } else if (CAP_GAIN(kIOPMSystemCapabilityGraphics
)) {
9148 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
.get());
9152 IOLockLock(pmStatsLock
);
9153 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount() < 50) {
9154 pmStatsAppResponses
->setObject(responseDescription
.get());
9156 IOLockUnlock(pmStatsLock
);
9163 // MARK: PMTraceWorker
9165 //******************************************************************************
9166 // TracePoint support
9168 //******************************************************************************
9170 #define kIOPMRegisterNVRAMTracePointHandlerKey \
9171 "IOPMRegisterNVRAMTracePointHandler"
9174 IOPMrootDomain::callPlatformFunction(
9175 const OSSymbol
* functionName
,
9176 bool waitForFunction
,
9177 void * param1
, void * param2
,
9178 void * param3
, void * param4
)
9180 if (pmTracer
&& functionName
&&
9181 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
9182 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
) {
9183 uint32_t tracePointPhases
, tracePointPCI
;
9184 uint64_t statusCode
;
9186 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
9187 pmTracer
->tracePointTarget
= (void *) param2
;
9188 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
9189 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
9190 if ((tracePointPhases
& 0xff) == kIOPMTracePointSystemSleep
) {
9191 OSSharedPtr
<IORegistryEntry
> node
= IORegistryEntry::fromPath( "/chosen", gIODTPlane
);
9193 OSSharedPtr
<OSObject
> bootRomFailureProp
;
9194 bootRomFailureProp
= node
->copyProperty(kIOEFIBootRomFailureKey
);
9195 OSData
*data
= OSDynamicCast(OSData
, bootRomFailureProp
.get());
9196 uint32_t bootFailureCode
;
9197 if (data
&& data
->getLength() == sizeof(bootFailureCode
)) {
9198 // Failure code from EFI/BootRom is a four byte structure
9199 memcpy(&bootFailureCode
, data
->getBytesNoCopy(), sizeof(bootFailureCode
));
9200 tracePointPCI
= OSSwapBigToHostInt32(bootFailureCode
);
9204 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
9205 if ((tracePointPhases
& 0xff) != kIOPMTracePointSystemUp
) {
9206 MSG("Sleep failure code 0x%08x 0x%08x\n",
9207 tracePointPCI
, tracePointPhases
);
9209 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
9210 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
9212 return kIOReturnSuccess
;
9215 else if (functionName
&&
9216 functionName
->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey
)) {
9217 if (gSleepPolicyHandler
) {
9218 return kIOReturnExclusiveAccess
;
9221 return kIOReturnBadArgument
;
9223 gSleepPolicyHandler
= (IOPMSystemSleepPolicyHandler
) param1
;
9224 gSleepPolicyTarget
= (void *) param2
;
9225 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue
);
9226 return kIOReturnSuccess
;
9230 return super::callPlatformFunction(
9231 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
9235 IOPMrootDomain::kdebugTrace(uint32_t event
, uint64_t id
,
9236 uintptr_t param1
, uintptr_t param2
, uintptr_t param3
)
9238 uint32_t code
= IODBG_POWER(event
);
9239 uint64_t regId
= id
;
9241 regId
= getRegistryEntryID();
9243 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE
, code
, (uintptr_t) regId
, param1
, param2
, param3
, 0);
9247 IOPMrootDomain::tracePoint( uint8_t point
)
9249 if (systemBooting
) {
9253 if (kIOPMTracePointWakeCapabilityClients
== point
) {
9254 acceptSystemWakeEvents(kAcceptSystemWakeEvents_Disable
);
9257 kdebugTrace(kPMLogSleepWakeTracePoint
, 0, point
, 0);
9258 pmTracer
->tracePoint(point
);
9262 kext_log_putc(char c
)
9264 if (gKextNameEnd
|| gKextNamePos
>= (sizeof(gKextNameBuf
) - 1)) {
9267 if (c
== '(' || c
== '[' || c
== ' ') {
9269 gKextNameEnd
= true;
9272 gKextNameBuf
[gKextNamePos
++] = c
;
9276 kext_log(const char *fmt
, ...)
9280 va_start(listp
, fmt
);
9281 _doprnt(fmt
, &listp
, &kext_log_putc
, 16);
9287 static OSPtr
<const OSSymbol
>
9288 copyKextIdentifierWithAddress(vm_address_t address
)
9290 OSSharedPtr
<const OSSymbol
> identifer
;
9292 IOLockLock(gHaltLogLock
);
9294 gKextNameEnd
= false;
9296 gKextNameBuf
[0] = 0;
9298 OSKext::printKextsInBacktrace(&address
, 1, kext_log
, OSKext::kPrintKextsLock
| OSKext::kPrintKextsTerse
);
9299 gKextNameBuf
[sizeof(gKextNameBuf
) - 1] = 0;
9300 identifer
= OSSymbol::withCString((gKextNameBuf
[0] != 0) ? gKextNameBuf
: kOSKextKernelIdentifier
);
9302 IOLockUnlock(gHaltLogLock
);
9307 // Caller serialized using PM workloop
9309 IOPMrootDomain::getNotificationClientName(OSObject
*object
)
9311 IOPMServiceInterestNotifier
*notifier
= (typeof(notifier
))object
;
9312 const char *clientName
= "UNKNOWN";
9314 if (!notifier
->clientName
) {
9315 // Check for user client
9316 if (systemCapabilityNotifier
&& (((IOPMServiceInterestNotifier
*) systemCapabilityNotifier
.get())->handler
== notifier
->handler
)) {
9317 OSNumber
*clientID
= NULL
;
9318 messageClient(kIOMessageCopyClientID
, object
, &clientID
);
9320 OSSharedPtr
<OSString
> string(IOCopyLogNameForPID(clientID
->unsigned32BitValue()), OSNoRetain
);
9322 notifier
->clientName
= OSSymbol::withString(string
.get());
9324 clientID
->release();
9326 } else if (notifier
->identifier
) {
9327 notifier
->clientName
.reset(notifier
->identifier
.get(), OSRetain
);
9331 if (notifier
->clientName
) {
9332 clientName
= notifier
->clientName
->getCStringNoCopy();
9339 IOPMrootDomain::traceNotification(OSObject
*object
, bool start
, uint64_t timestamp
, uint32_t msgIndex
)
9341 IOPMServiceInterestNotifier
*notifier
;
9343 if (systemBooting
) {
9346 notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, object
);
9352 pmTracer
->traceDetail(notifier
->uuid0
>> 32);
9353 kdebugTrace(kPMLogSleepWakeMessage
, pmTracer
->getTracePhase(),
9354 (uintptr_t) notifier
->msgType
, (uintptr_t) notifier
->uuid0
, (uintptr_t) notifier
->uuid1
);
9356 // Update notifier state used for response/ack logging
9357 notifier
->msgIndex
= msgIndex
;
9358 notifier
->msgAbsTime
= timestamp
;
9360 if (msgIndex
!= UINT_MAX
) {
9361 DLOG("%s[%u] to %s\n", getIOMessageString(notifier
->msgType
), msgIndex
, getNotificationClientName(notifier
));
9363 DLOG("%s to %s\n", getIOMessageString(notifier
->msgType
), getNotificationClientName(notifier
));
9366 assert(notifierObject
== NULL
);
9367 notifierThread
= current_thread();
9368 notifierObject
.reset(notifier
, OSRetain
);
9373 SUB_ABSOLUTETIME(×tamp
, ¬ifier
->msgAbsTime
);
9374 absolutetime_to_nanoseconds(timestamp
, &nsec
);
9375 delayMS
= (uint32_t)(nsec
/ 1000000ULL);
9376 if (delayMS
> notifier
->maxMsgDelayMS
) {
9377 notifier
->maxMsgDelayMS
= delayMS
;
9380 assert(notifierObject
== notifier
);
9381 notifierObject
.reset();
9382 notifierThread
= NULL
;
9387 IOPMrootDomain::traceNotificationAck(OSObject
*object
, uint32_t delay_ms
)
9389 if (systemBooting
) {
9392 IOPMServiceInterestNotifier
*notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, object
);
9397 kdebugTrace(kPMLogDrvResponseDelay
, notifier
->uuid0
,
9398 (uintptr_t) notifier
->uuid1
, (uintptr_t) 0, (uintptr_t) delay_ms
);
9400 DLOG("%s[%u] ack from %s took %d ms\n",
9401 getIOMessageString(notifier
->msgType
), notifier
->msgIndex
, getNotificationClientName(notifier
), delay_ms
);
9402 if (delay_ms
> notifier
->maxAckDelayMS
) {
9403 notifier
->maxAckDelayMS
= delay_ms
;
9408 IOPMrootDomain::traceNotificationResponse(OSObject
*object
, uint32_t delay_ms
, uint32_t ack_time_us
)
9410 if (systemBooting
) {
9413 IOPMServiceInterestNotifier
*notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, object
);
9418 kdebugTrace(kPMLogDrvResponseDelay
, notifier
->uuid0
,
9419 (uintptr_t) notifier
->uuid1
, (uintptr_t)(ack_time_us
/ 1000), (uintptr_t) delay_ms
);
9421 if (ack_time_us
== 0) {
9422 // Client work is done and ack will not be forthcoming
9423 DLOG("%s[%u] response from %s took %d ms\n",
9424 getIOMessageString(notifier
->msgType
), notifier
->msgIndex
, getNotificationClientName(notifier
), delay_ms
);
9426 // Client needs more time and it must ack within ack_time_us
9427 DLOG("%s[%u] response from %s took %d ms (ack in %d us)\n",
9428 getIOMessageString(notifier
->msgType
), notifier
->msgIndex
, getNotificationClientName(notifier
), delay_ms
, ack_time_us
);
9433 IOPMrootDomain::traceFilteredNotification(OSObject
*object
)
9435 if ((kIOLogDebugPower
& gIOKitDebug
) == 0) {
9438 if (systemBooting
) {
9441 IOPMServiceInterestNotifier
*notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, object
);
9446 DLOG("%s to %s dropped\n", getIOMessageString(notifier
->msgType
), getNotificationClientName(notifier
));
9450 IOPMrootDomain::traceDetail(uint32_t msgType
, uint32_t msgIndex
, uint32_t delay
)
9452 if (!systemBooting
) {
9453 uint32_t detail
= ((msgType
& 0xffff) << 16) | (delay
& 0xffff);
9454 pmTracer
->traceDetail( detail
);
9455 kdebugTrace(kPMLogSleepWakeTracePoint
, pmTracer
->getTracePhase(), msgType
, delay
);
9456 DLOG("trace point 0x%02x msgType 0x%x detail 0x%08x\n", pmTracer
->getTracePhase(), msgType
, delay
);
9461 IOPMrootDomain::configureReportGated(uint64_t channel_id
, uint64_t action
, void *result
)
9464 void **report
= NULL
;
9467 uint32_t *clientCnt
;
9472 if (channel_id
== kAssertDelayChID
) {
9473 report
= &assertOnWakeReport
;
9474 bktCnt
= kAssertDelayBcktCnt
;
9475 bktSize
= kAssertDelayBcktSize
;
9476 clientCnt
= &assertOnWakeClientCnt
;
9477 } else if (channel_id
== kSleepDelaysChID
) {
9478 report
= &sleepDelaysReport
;
9479 bktCnt
= kSleepDelaysBcktCnt
;
9480 bktSize
= kSleepDelaysBcktSize
;
9481 clientCnt
= &sleepDelaysClientCnt
;
9488 case kIOReportEnable
:
9495 reportSize
= HISTREPORT_BUFSIZE(bktCnt
);
9496 *report
= IOMalloc(reportSize
);
9497 if (*report
== NULL
) {
9500 bzero(*report
, reportSize
);
9501 HISTREPORT_INIT((uint16_t)bktCnt
, bktSize
, *report
, reportSize
,
9502 getRegistryEntryID(), channel_id
, kIOReportCategoryPower
);
9504 if (channel_id
== kAssertDelayChID
) {
9505 assertOnWakeSecs
= 0;
9510 case kIOReportDisable
:
9511 if (*clientCnt
== 0) {
9514 if (*clientCnt
== 1) {
9515 IOFree(*report
, HISTREPORT_BUFSIZE(bktCnt
));
9520 if (channel_id
== kAssertDelayChID
) {
9521 assertOnWakeSecs
= -1; // Invalid value to prevent updates
9525 case kIOReportGetDimensions
:
9527 HISTREPORT_UPDATERES(*report
, kIOReportGetDimensions
, result
);
9536 IOPMrootDomain::configureReport(IOReportChannelList
*channelList
,
9537 IOReportConfigureAction action
,
9542 uint64_t configAction
= (uint64_t)action
;
9544 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
9545 if ((channelList
->channels
[cnt
].channel_id
== kSleepCntChID
) ||
9546 (channelList
->channels
[cnt
].channel_id
== kDarkWkCntChID
) ||
9547 (channelList
->channels
[cnt
].channel_id
== kUserWkCntChID
)) {
9548 if (action
!= kIOReportGetDimensions
) {
9551 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions
, result
);
9552 } else if ((channelList
->channels
[cnt
].channel_id
== kAssertDelayChID
) ||
9553 (channelList
->channels
[cnt
].channel_id
== kSleepDelaysChID
)) {
9554 gIOPMWorkLoop
->runAction(
9555 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::configureReportGated
),
9556 (OSObject
*)this, (void *)channelList
->channels
[cnt
].channel_id
,
9557 (void *)configAction
, (void *)result
);
9561 return super::configureReport(channelList
, action
, result
, destination
);
9565 IOPMrootDomain::updateReportGated(uint64_t ch_id
, void *result
, IOBufferMemoryDescriptor
*dest
)
9574 if (ch_id
== kAssertDelayChID
) {
9575 report
= &assertOnWakeReport
;
9576 } else if (ch_id
== kSleepDelaysChID
) {
9577 report
= &sleepDelaysReport
;
9580 return kIOReturnBadArgument
;
9583 if (*report
== NULL
) {
9584 return kIOReturnNotOpen
;
9587 HISTREPORT_UPDATEPREP(*report
, data2cpy
, size2cpy
);
9588 if (size2cpy
> (dest
->getCapacity() - dest
->getLength())) {
9589 return kIOReturnOverrun
;
9592 HISTREPORT_UPDATERES(*report
, kIOReportCopyChannelData
, result
);
9593 dest
->appendBytes(data2cpy
, size2cpy
);
9595 return kIOReturnSuccess
;
9599 IOPMrootDomain::updateReport(IOReportChannelList
*channelList
,
9600 IOReportUpdateAction action
,
9606 uint8_t buf
[SIMPLEREPORT_BUFSIZE
];
9607 IOBufferMemoryDescriptor
*dest
= OSDynamicCast(IOBufferMemoryDescriptor
, (OSObject
*)destination
);
9611 if (action
!= kIOReportCopyChannelData
) {
9615 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
9616 ch_id
= channelList
->channels
[cnt
].channel_id
;
9618 if ((ch_id
== kAssertDelayChID
) || (ch_id
== kSleepDelaysChID
)) {
9619 gIOPMWorkLoop
->runAction(
9620 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::updateReportGated
),
9621 (OSObject
*)this, (void *)ch_id
,
9622 (void *)result
, (void *)dest
);
9624 } else if ((ch_id
== kSleepCntChID
) ||
9625 (ch_id
== kDarkWkCntChID
) || (ch_id
== kUserWkCntChID
)) {
9626 SIMPLEREPORT_INIT(buf
, sizeof(buf
), getRegistryEntryID(), ch_id
, kIOReportCategoryPower
);
9631 if (ch_id
== kSleepCntChID
) {
9632 SIMPLEREPORT_SETVALUE(buf
, sleepCnt
);
9633 } else if (ch_id
== kDarkWkCntChID
) {
9634 SIMPLEREPORT_SETVALUE(buf
, darkWakeCnt
);
9635 } else if (ch_id
== kUserWkCntChID
) {
9636 SIMPLEREPORT_SETVALUE(buf
, displayWakeCnt
);
9639 SIMPLEREPORT_UPDATEPREP(buf
, data2cpy
, size2cpy
);
9640 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData
, result
);
9641 dest
->appendBytes(data2cpy
, size2cpy
);
9645 return super::updateReport(channelList
, action
, result
, destination
);
9649 //******************************************************************************
9650 // PMTraceWorker Class
9652 //******************************************************************************
9655 #define super OSObject
9656 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
9658 #define kPMBestGuessPCIDevicesCount 25
9659 #define kPMMaxRTCBitfieldSize 32
9661 OSPtr
<PMTraceWorker
>
9662 PMTraceWorker::tracer(IOPMrootDomain
* owner
)
9664 OSSharedPtr
<PMTraceWorker
> me
= OSMakeShared
<PMTraceWorker
>();
9665 if (!me
|| !me
->init()) {
9669 DLOG("PMTraceWorker %p\n", OBFUSCATE(me
.get()));
9671 // Note that we cannot instantiate the PCI device -> bit mappings here, since
9672 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
9673 // this dictionary lazily.
9675 me
->pciDeviceBitMappings
= NULL
;
9676 me
->pmTraceWorkerLock
= IOLockAlloc();
9677 me
->tracePhase
= kIOPMTracePointSystemUp
;
9678 me
->traceData32
= 0;
9679 me
->loginWindowData
= 0;
9680 me
->coreDisplayData
= 0;
9681 me
->coreGraphicsData
= 0;
9686 PMTraceWorker::RTC_TRACE(void)
9688 if (tracePointHandler
&& tracePointTarget
) {
9691 IOLockLock(pmTraceWorkerLock
);
9692 wordA
= (loginWindowData
<< 24) | (coreDisplayData
<< 16) |
9693 (coreGraphicsData
<< 8) | tracePhase
;
9694 IOLockUnlock(pmTraceWorkerLock
);
9696 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
9697 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
9699 #if DEVELOPMENT || DEBUG
9700 if ((swd_panic_phase
!= 0) && (swd_panic_phase
== tracePhase
)) {
9701 DEBUG_LOG("Causing sleep wake failure in phase 0x%08x\n", tracePhase
);
9702 IOLock
*l
= IOLockAlloc();
9710 PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
9712 OSSharedPtr
<const OSSymbol
> deviceName
;
9715 IOLockLock(pmTraceWorkerLock
);
9717 if (!pciDeviceBitMappings
) {
9718 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
9719 if (!pciDeviceBitMappings
) {
9724 // Check for bitmask overflow.
9725 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
) {
9729 if ((deviceName
= pciDevice
->copyName()) &&
9730 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
.get(), 0) == (unsigned int)-1) &&
9731 pciDeviceBitMappings
->setObject(deviceName
.get())) {
9732 index
= pciDeviceBitMappings
->getCount() - 1;
9733 _LOG("PMTrace PCI array: set object %s => %d\n",
9734 deviceName
->getCStringNoCopy(), index
);
9737 if (!addedToRegistry
&& (index
>= 0)) {
9738 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
9742 IOLockUnlock(pmTraceWorkerLock
);
9747 PMTraceWorker::serialize(OSSerialize
*s
) const
9750 if (pciDeviceBitMappings
) {
9751 IOLockLock(pmTraceWorkerLock
);
9752 ok
= pciDeviceBitMappings
->serialize(s
);
9753 IOLockUnlock(pmTraceWorkerLock
);
9759 PMTraceWorker::tracePoint(uint8_t phase
)
9761 // clear trace detail when phase begins
9762 if (tracePhase
!= phase
) {
9768 DLOG("trace point 0x%02x\n", tracePhase
);
9773 PMTraceWorker::traceDetail(uint32_t detail
)
9775 if (detail
== traceData32
) {
9778 traceData32
= detail
;
9783 PMTraceWorker::traceComponentWakeProgress(uint32_t component
, uint32_t data
)
9785 switch (component
) {
9786 case kIOPMLoginWindowProgress
:
9787 loginWindowData
= data
& kIOPMLoginWindowProgressMask
;
9789 case kIOPMCoreDisplayProgress
:
9790 coreDisplayData
= data
& kIOPMCoreDisplayProgressMask
;
9792 case kIOPMCoreGraphicsProgress
:
9793 coreGraphicsData
= data
& kIOPMCoreGraphicsProgressMask
;
9799 DLOG("component trace point 0x%02x data 0x%08x\n", component
, data
);
9804 PMTraceWorker::tracePCIPowerChange(
9805 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
9808 uint32_t expectedFlag
;
9810 // Ignore PCI changes outside of system sleep/wake.
9811 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
9812 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
)) {
9816 // Only record the WillChange transition when going to sleep,
9817 // and the DidChange on the way up.
9818 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
9819 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
9820 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
9821 if (changeFlags
!= expectedFlag
) {
9825 // Mark this device off in our bitfield
9826 if (bitNum
< kPMMaxRTCBitfieldSize
) {
9827 bitMask
= (1 << bitNum
);
9829 if (kPowerChangeStart
== type
) {
9830 traceData32
|= bitMask
;
9831 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
9832 service
->getName(), bitNum
, bitMask
, traceData32
);
9833 owner
->kdebugTrace(kPMLogPCIDevChangeStart
, service
->getRegistryEntryID(), traceData32
, 0);
9835 traceData32
&= ~bitMask
;
9836 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
9837 service
->getName(), bitNum
, bitMask
, traceData32
);
9838 owner
->kdebugTrace(kPMLogPCIDevChangeDone
, service
->getRegistryEntryID(), traceData32
, 0);
9841 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
9847 PMTraceWorker::getPMStatusCode()
9849 return ((uint64_t)traceData32
<< 32) | ((uint64_t)tracePhase
);
9853 PMTraceWorker::getTracePhase()
9859 PMTraceWorker::getTraceData()
9865 // MARK: PMHaltWorker
9867 //******************************************************************************
9868 // PMHaltWorker Class
9870 //******************************************************************************
9873 PMHaltWorker::worker( void )
9879 me
= OSTypeAlloc( PMHaltWorker
);
9880 if (!me
|| !me
->init()) {
9884 me
->lock
= IOLockAlloc();
9889 DLOG("PMHaltWorker %p\n", OBFUSCATE(me
));
9890 me
->retain(); // thread holds extra retain
9891 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
)) {
9895 thread_deallocate(thread
);
9906 PMHaltWorker::free( void )
9908 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
9913 return OSObject::free();
9917 PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
9919 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
9921 IOLockLock( gPMHaltLock
);
9923 me
->depth
= gPMHaltDepth
;
9924 IOLockUnlock( gPMHaltLock
);
9926 while (me
->depth
>= 0) {
9927 PMHaltWorker::work( me
);
9929 IOLockLock( gPMHaltLock
);
9930 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
) {
9931 // This is the last thread to finish work on this level,
9932 // inform everyone to start working on next lower level.
9934 me
->depth
= gPMHaltDepth
;
9935 gPMHaltIdleCount
= 0;
9936 thread_wakeup((event_t
) &gPMHaltIdleCount
);
9938 // One or more threads are still working on this level,
9939 // this thread must wait.
9940 me
->depth
= gPMHaltDepth
- 1;
9942 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
9943 } while (me
->depth
!= gPMHaltDepth
);
9945 IOLockUnlock( gPMHaltLock
);
9948 // No more work to do, terminate thread
9949 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me
), me
->visits
);
9950 thread_wakeup( &gPMHaltDepth
);
9955 PMHaltWorker::work( PMHaltWorker
* me
)
9957 OSSharedPtr
<IOService
> service
;
9959 AbsoluteTime startTime
, elapsedTime
;
9966 // Claim an unit of work from the shared pool
9967 IOLockLock( gPMHaltLock
);
9968 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
9970 service
.reset(OSDynamicCast(IOService
, inner
->getAnyObject()), OSRetain
);
9972 inner
->removeObject(service
.get());
9975 IOLockUnlock( gPMHaltLock
);
9977 break; // no more work at this depth
9979 clock_get_uptime(&startTime
);
9981 if (!service
->isInactive() &&
9982 service
->setProperty(gPMHaltClientAcknowledgeKey
.get(), me
)) {
9983 IOLockLock(me
->lock
);
9984 me
->startTime
= startTime
;
9985 me
->service
= service
.get();
9986 me
->timeout
= false;
9987 IOLockUnlock(me
->lock
);
9989 service
->systemWillShutdown( gPMHaltMessageType
);
9991 // Wait for driver acknowledgement
9992 IOLockLock(me
->lock
);
9993 while (service
->propertyExists(gPMHaltClientAcknowledgeKey
.get())) {
9994 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
9997 timeout
= me
->timeout
;
9998 IOLockUnlock(me
->lock
);
10001 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
10002 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
) {
10003 LOG("%s driver %s (0x%llx) took %u ms\n",
10004 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ?
10005 "PowerOff" : "Restart",
10006 service
->getName(), service
->getRegistryEntryID(),
10007 (uint32_t) deltaTime
);
10008 halt_log_enter("PowerOff/Restart handler completed",
10009 OSMemberFunctionCast(const void *, service
.get(), &IOService::systemWillShutdown
),
10018 PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
10021 AbsoluteTime startTime
;
10022 AbsoluteTime endTime
;
10026 IOLockLock(me
->lock
);
10027 if (me
->service
&& !me
->timeout
) {
10028 startTime
= me
->startTime
;
10030 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0) {
10031 SUB_ABSOLUTETIME(&endTime
, &startTime
);
10032 absolutetime_to_nanoseconds(endTime
, &nano
);
10034 if (nano
> 3000000000ULL) {
10035 me
->timeout
= true;
10037 halt_log_enter("PowerOff/Restart still waiting on handler",
10038 OSMemberFunctionCast(const void *, me
->service
, &IOService::systemWillShutdown
),
10040 MSG("%s still waiting on %s\n",
10041 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" : "Restart",
10042 me
->service
->getName());
10045 IOLockUnlock(me
->lock
);
10048 //******************************************************************************
10049 // acknowledgeSystemWillShutdown
10051 // Acknowledgement from drivers that they have prepared for shutdown/restart.
10052 //******************************************************************************
10055 IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
10057 PMHaltWorker
* worker
;
10058 OSSharedPtr
<OSObject
> prop
;
10064 //DLOG("%s acknowledged\n", from->getName());
10065 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
.get());
10067 worker
= (PMHaltWorker
*) prop
.get();
10068 IOLockLock(worker
->lock
);
10069 from
->removeProperty( gPMHaltClientAcknowledgeKey
.get());
10070 thread_wakeup((event_t
) worker
);
10071 IOLockUnlock(worker
->lock
);
10073 DLOG("%s acknowledged without worker property\n",
10079 //******************************************************************************
10080 // notifySystemShutdown
10082 // Notify all objects in PM tree that system will shutdown or restart
10083 //******************************************************************************
10086 notifySystemShutdown( IOService
* root
, uint32_t messageType
)
10088 #define PLACEHOLDER ((OSSet *)gPMHaltArray.get())
10089 OSSharedPtr
<IORegistryIterator
> iter
;
10090 IORegistryEntry
* entry
;
10093 OSSharedPtr
<OSSet
> newInner
;
10094 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
10095 AbsoluteTime deadline
;
10096 unsigned int totalNodes
= 0;
10097 unsigned int depth
;
10098 unsigned int rootDepth
;
10099 unsigned int numWorkers
;
10100 unsigned int count
;
10105 DLOG("%s msgType = 0x%x\n", __FUNCTION__
, messageType
);
10107 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
10109 // Iterate the entire PM tree starting from root
10111 rootDepth
= root
->getDepth( gIOPowerPlane
);
10116 // debug - for repeated test runs
10117 while (PMHaltWorker::metaClass
->getInstanceCount()) {
10121 if (!gPMHaltArray
) {
10122 gPMHaltArray
= OSArray::withCapacity(40);
10123 if (!gPMHaltArray
) {
10127 gPMHaltArray
->flushCollection();
10130 if (!gPMHaltLock
) {
10131 gPMHaltLock
= IOLockAlloc();
10132 if (!gPMHaltLock
) {
10137 if (!gPMHaltClientAcknowledgeKey
) {
10138 gPMHaltClientAcknowledgeKey
=
10139 OSSymbol::withCStringNoCopy("PMShutdown");
10140 if (!gPMHaltClientAcknowledgeKey
) {
10145 gPMHaltMessageType
= messageType
;
10147 // Depth-first walk of PM plane
10149 iter
= IORegistryIterator::iterateOver(
10150 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
10153 while ((entry
= iter
->getNextObject())) {
10154 node
= OSDynamicCast(IOService
, entry
);
10160 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
)) {
10164 depth
= node
->getDepth( gIOPowerPlane
);
10165 if (depth
<= rootDepth
) {
10171 // adjust to zero based depth
10172 depth
-= (rootDepth
+ 1);
10174 // gPMHaltArray is an array of containers, each container
10175 // refers to nodes with the same depth.
10177 count
= gPMHaltArray
->getCount();
10178 while (depth
>= count
) {
10179 // expand array and insert placeholders
10180 gPMHaltArray
->setObject(PLACEHOLDER
);
10183 count
= gPMHaltArray
->getCount();
10184 if (depth
< count
) {
10185 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
10186 if (inner
== PLACEHOLDER
) {
10187 newInner
= OSSet::withCapacity(40);
10189 gPMHaltArray
->replaceObject(depth
, newInner
.get());
10190 inner
= newInner
.get();
10194 // PM nodes that appear more than once in the tree will have
10195 // the same depth, OSSet will refuse to add the node twice.
10197 ok
= inner
->setObject(node
);
10201 DLOG("Skipped PM node %s\n", node
->getName());
10207 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++) {
10209 if (inner
!= PLACEHOLDER
) {
10210 count
= inner
->getCount();
10212 DLOG("Nodes at depth %u = %u\n", i
, count
);
10215 // strip placeholders (not all depths are populated)
10217 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
));) {
10218 if (inner
== PLACEHOLDER
) {
10219 gPMHaltArray
->removeObject(i
);
10222 count
= inner
->getCount();
10223 if (count
> numWorkers
) {
10224 numWorkers
= count
;
10226 totalNodes
+= count
;
10230 if (gPMHaltArray
->getCount() == 0 || !numWorkers
) {
10234 gPMHaltBusyCount
= 0;
10235 gPMHaltIdleCount
= 0;
10236 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
10238 // Create multiple workers (and threads)
10240 if (numWorkers
> kPMHaltMaxWorkers
) {
10241 numWorkers
= kPMHaltMaxWorkers
;
10244 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
10245 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
10247 for (unsigned int i
= 0; i
< numWorkers
; i
++) {
10248 workers
[i
] = PMHaltWorker::worker();
10251 // Wait for workers to exhaust all available work
10253 IOLockLock(gPMHaltLock
);
10254 while (gPMHaltDepth
>= 0) {
10255 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
10257 waitResult
= IOLockSleepDeadline(
10258 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
10259 if (THREAD_TIMED_OUT
== waitResult
) {
10261 clock_get_uptime(&now
);
10263 IOLockUnlock(gPMHaltLock
);
10264 for (unsigned int i
= 0; i
< numWorkers
; i
++) {
10266 PMHaltWorker::checkTimeout(workers
[i
], &now
);
10269 IOLockLock(gPMHaltLock
);
10272 IOLockUnlock(gPMHaltLock
);
10274 // Release all workers
10276 for (unsigned int i
= 0; i
< numWorkers
; i
++) {
10278 workers
[i
]->release();
10280 // worker also retained by it's own thread
10284 DLOG("%s done\n", __FUNCTION__
);
10289 // MARK: Kernel Assertion
10291 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10293 IOPMDriverAssertionID
10294 IOPMrootDomain::createPMAssertion(
10295 IOPMDriverAssertionType whichAssertionBits
,
10296 IOPMDriverAssertionLevel assertionLevel
,
10297 IOService
*ownerService
,
10298 const char *ownerDescription
)
10301 IOPMDriverAssertionID newAssertion
;
10303 if (!pmAssertions
) {
10307 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
10309 if (kIOReturnSuccess
== ret
) {
10310 return newAssertion
;
10317 IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
10319 if (!pmAssertions
) {
10320 return kIOReturnInternalError
;
10323 return pmAssertions
->releaseAssertion(releaseAssertion
);
10328 IOPMrootDomain::setPMAssertionLevel(
10329 IOPMDriverAssertionID assertionID
,
10330 IOPMDriverAssertionLevel assertionLevel
)
10332 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
10335 IOPMDriverAssertionLevel
10336 IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
10338 IOPMDriverAssertionType sysLevels
;
10340 if (!pmAssertions
|| whichAssertion
== 0) {
10341 return kIOPMDriverAssertionLevelOff
;
10344 sysLevels
= pmAssertions
->getActivatedAssertions();
10346 // Check that every bit set in argument 'whichAssertion' is asserted
10347 // in the aggregate bits.
10348 if ((sysLevels
& whichAssertion
) == whichAssertion
) {
10349 return kIOPMDriverAssertionLevelOn
;
10351 return kIOPMDriverAssertionLevelOff
;
10356 IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
10358 if (!pmAssertions
) {
10359 return kIOReturnNotFound
;
10362 return pmAssertions
->setUserAssertionLevels(inLevels
);
10366 IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
10368 if (pmAssertions
) {
10369 pmAssertions
->publishProperties();
10371 return IOService::serializeProperties(s
);
10374 OSSharedPtr
<OSObject
>
10375 IOPMrootDomain::copyProperty( const char * aKey
) const
10377 OSSharedPtr
<OSObject
> obj
;
10378 obj
= IOService::copyProperty(aKey
);
10384 if (!strncmp(aKey
, kIOPMSleepWakeWdogRebootKey
,
10385 sizeof(kIOPMSleepWakeWdogRebootKey
))) {
10386 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
10387 return OSSharedPtr
<OSBoolean
>(kOSBooleanTrue
, OSNoRetain
);
10389 return OSSharedPtr
<OSBoolean
>(kOSBooleanFalse
, OSNoRetain
);
10393 if (!strncmp(aKey
, kIOPMSleepWakeWdogLogsValidKey
,
10394 sizeof(kIOPMSleepWakeWdogLogsValidKey
))) {
10395 if (swd_flags
& SWD_VALID_LOGS
) {
10396 return OSSharedPtr
<OSBoolean
>(kOSBooleanTrue
, OSNoRetain
);
10398 return OSSharedPtr
<OSBoolean
>(kOSBooleanFalse
, OSNoRetain
);
10403 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
10404 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
10405 * issued by DisplayWrangler on darkwake.
10407 if (!strcmp(aKey
, "DesktopMode")) {
10409 return OSSharedPtr
<OSBoolean
>(kOSBooleanTrue
, OSNoRetain
);
10411 return OSSharedPtr
<OSBoolean
>(kOSBooleanFalse
, OSNoRetain
);
10414 if (!strcmp(aKey
, "DisplayIdleForDemandSleep")) {
10415 if (displayIdleForDemandSleep
) {
10416 return OSSharedPtr
<OSBoolean
>(kOSBooleanTrue
, OSNoRetain
);
10418 return OSSharedPtr
<OSBoolean
>(kOSBooleanFalse
, OSNoRetain
);
10422 if (!strcmp(aKey
, kIOPMDriverWakeEventsKey
)) {
10423 OSSharedPtr
<OSArray
> array
;
10425 if (_systemWakeEventsArray
&& _systemWakeEventsArray
->getCount()) {
10426 OSSharedPtr
<OSCollection
> collection
= _systemWakeEventsArray
->copyCollection();
10428 array
= OSDynamicPtrCast
<OSArray
>(collection
);
10431 WAKEEVENT_UNLOCK();
10432 return os::move(array
);
10435 if (!strcmp(aKey
, kIOPMSleepStatisticsAppsKey
)) {
10436 OSSharedPtr
<OSArray
> array
;
10437 IOLockLock(pmStatsLock
);
10438 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount()) {
10439 OSSharedPtr
<OSCollection
> collection
= pmStatsAppResponses
->copyCollection();
10441 array
= OSDynamicPtrCast
<OSArray
>(collection
);
10444 IOLockUnlock(pmStatsLock
);
10445 return os::move(array
);
10448 if (!strcmp(aKey
, kIOPMIdleSleepPreventersKey
)) {
10449 OSArray
*idleSleepList
= NULL
;
10450 gRootDomain
->copySleepPreventersList(&idleSleepList
, NULL
);
10451 return OSSharedPtr
<OSArray
>(idleSleepList
, OSNoRetain
);
10454 if (!strcmp(aKey
, kIOPMSystemSleepPreventersKey
)) {
10455 OSArray
*systemSleepList
= NULL
;
10456 gRootDomain
->copySleepPreventersList(NULL
, &systemSleepList
);
10457 return OSSharedPtr
<OSArray
>(systemSleepList
, OSNoRetain
);
10460 if (!strcmp(aKey
, kIOPMIdleSleepPreventersWithIDKey
)) {
10461 OSArray
*idleSleepList
= NULL
;
10462 gRootDomain
->copySleepPreventersListWithID(&idleSleepList
, NULL
);
10463 return OSSharedPtr
<OSArray
>(idleSleepList
, OSNoRetain
);
10466 if (!strcmp(aKey
, kIOPMSystemSleepPreventersWithIDKey
)) {
10467 OSArray
*systemSleepList
= NULL
;
10468 gRootDomain
->copySleepPreventersListWithID(NULL
, &systemSleepList
);
10469 return OSSharedPtr
<OSArray
>(systemSleepList
, OSNoRetain
);
10475 // MARK: Wake Event Reporting
10478 IOPMrootDomain::copyWakeReasonString( char * outBuf
, size_t bufSize
)
10481 strlcpy(outBuf
, gWakeReasonString
, bufSize
);
10482 WAKEEVENT_UNLOCK();
10486 IOPMrootDomain::copyShutdownReasonString( char * outBuf
, size_t bufSize
)
10489 strlcpy(outBuf
, gShutdownReasonString
, bufSize
);
10490 WAKEEVENT_UNLOCK();
10493 //******************************************************************************
10494 // acceptSystemWakeEvents
10496 // Private control for the acceptance of driver wake event claims.
10497 //******************************************************************************
10500 IOPMrootDomain::acceptSystemWakeEvents( uint32_t control
)
10502 bool logWakeReason
= false;
10506 case kAcceptSystemWakeEvents_Enable
:
10507 assert(_acceptSystemWakeEvents
== false);
10508 if (!_systemWakeEventsArray
) {
10509 _systemWakeEventsArray
= OSArray::withCapacity(4);
10511 _acceptSystemWakeEvents
= (_systemWakeEventsArray
!= NULL
);
10512 if (!(_aotNow
&& (kIOPMWakeEventAOTExitFlags
& _aotPendingFlags
))) {
10513 gWakeReasonString
[0] = '\0';
10514 if (_systemWakeEventsArray
) {
10515 _systemWakeEventsArray
->flushCollection();
10519 // Remove stale WakeType property before system sleep
10520 removeProperty(kIOPMRootDomainWakeTypeKey
);
10521 removeProperty(kIOPMRootDomainWakeReasonKey
);
10524 case kAcceptSystemWakeEvents_Disable
:
10525 _acceptSystemWakeEvents
= false;
10526 #if defined(XNU_TARGET_OS_OSX)
10527 logWakeReason
= (gWakeReasonString
[0] != '\0');
10528 #else /* !defined(XNU_TARGET_OS_OSX) */
10529 logWakeReason
= gWakeReasonSysctlRegistered
;
10531 static int panic_allowed
= -1;
10533 if ((panic_allowed
== -1) &&
10534 (PE_parse_boot_argn("swd_wakereason_panic", &panic_allowed
, sizeof(panic_allowed
)) == false)) {
10538 if (panic_allowed
) {
10540 // Panic if wake reason is null or empty
10541 for (i
= 0; (i
< strlen(gWakeReasonString
)); i
++) {
10542 if ((gWakeReasonString
[i
] != ' ') && (gWakeReasonString
[i
] != '\t')) {
10546 if (i
>= strlen(gWakeReasonString
)) {
10547 panic("Wake reason is empty\n");
10550 #endif /* DEVELOPMENT */
10551 #endif /* !defined(XNU_TARGET_OS_OSX) */
10553 // publish kIOPMRootDomainWakeReasonKey if not already set
10554 if (!propertyExists(kIOPMRootDomainWakeReasonKey
)) {
10555 setProperty(kIOPMRootDomainWakeReasonKey
, gWakeReasonString
);
10559 case kAcceptSystemWakeEvents_Reenable
:
10560 assert(_acceptSystemWakeEvents
== false);
10561 _acceptSystemWakeEvents
= (_systemWakeEventsArray
!= NULL
);
10562 removeProperty(kIOPMRootDomainWakeReasonKey
);
10565 WAKEEVENT_UNLOCK();
10567 if (logWakeReason
) {
10568 MSG("system wake events: %s\n", gWakeReasonString
);
10572 //******************************************************************************
10573 // claimSystemWakeEvent
10575 // For a driver to claim a device is the source/conduit of a system wake event.
10576 //******************************************************************************
10579 IOPMrootDomain::claimSystemWakeEvent(
10580 IOService
* device
,
10581 IOOptionBits flags
,
10582 const char * reason
,
10583 OSObject
* details
)
10585 OSSharedPtr
<const OSSymbol
> deviceName
;
10586 OSSharedPtr
<OSNumber
> deviceRegId
;
10587 OSSharedPtr
<OSNumber
> claimTime
;
10588 OSSharedPtr
<OSData
> flagsData
;
10589 OSSharedPtr
<OSString
> reasonString
;
10590 OSSharedPtr
<OSDictionary
> dict
;
10591 uint64_t timestamp
;
10592 bool addWakeReason
;
10594 if (!device
|| !reason
) {
10598 pmEventTimeStamp(×tamp
);
10600 IOOptionBits aotFlags
= 0;
10601 bool needAOTEvaluate
= FALSE
;
10603 if (kIOPMAOTModeAddEventFlags
& _aotMode
) {
10604 if (!strcmp("hold", reason
)
10605 || !strcmp("help", reason
)
10606 || !strcmp("menu", reason
)
10607 || !strcmp("stockholm", reason
)
10608 || !strcmp("ringer", reason
)
10609 || !strcmp("ringerab", reason
)
10610 || !strcmp("smc0", reason
)
10611 || !strcmp("AOP.RTPWakeupAP", reason
)
10612 || !strcmp("BT.OutboxNotEmpty", reason
)
10613 || !strcmp("WL.OutboxNotEmpty", reason
)) {
10614 flags
|= kIOPMWakeEventAOTExit
;
10618 #if DEVELOPMENT || DEBUG
10619 if (_aotLingerTime
&& !strcmp("rtc", reason
)) {
10620 flags
|= kIOPMWakeEventAOTPossibleExit
;
10622 #endif /* DEVELOPMENT || DEBUG */
10624 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
10625 // Publishing the WakeType is serialized by the PM work loop
10626 if (!strcmp("rtc", reason
) && (_nextScheduledAlarmType
!= NULL
)) {
10627 pmPowerStateQueue
->submitPowerEvent(kPowerEventPublishWakeType
,
10628 (void *) _nextScheduledAlarmType
.get());
10631 // Workaround for the missing wake HID event
10632 if (gDarkWakeFlags
& kDarkWakeFlagUserWakeWorkaround
) {
10633 if (!strcmp("trackpadkeyboard", reason
)) {
10634 pmPowerStateQueue
->submitPowerEvent(kPowerEventPublishWakeType
,
10635 (void *) gIOPMWakeTypeUserKey
.get());
10640 deviceName
= device
->copyName(gIOServicePlane
);
10641 deviceRegId
= OSNumber::withNumber(device
->getRegistryEntryID(), 64);
10642 claimTime
= OSNumber::withNumber(timestamp
, 64);
10643 flagsData
= OSData::withBytes(&flags
, sizeof(flags
));
10644 reasonString
= OSString::withCString(reason
);
10645 dict
= OSDictionary::withCapacity(5 + (details
? 1 : 0));
10646 if (!dict
|| !deviceName
|| !deviceRegId
|| !claimTime
|| !flagsData
|| !reasonString
) {
10650 dict
->setObject(gIONameKey
, deviceName
.get());
10651 dict
->setObject(gIORegistryEntryIDKey
, deviceRegId
.get());
10652 dict
->setObject(kIOPMWakeEventTimeKey
, claimTime
.get());
10653 dict
->setObject(kIOPMWakeEventFlagsKey
, flagsData
.get());
10654 dict
->setObject(kIOPMWakeEventReasonKey
, reasonString
.get());
10656 dict
->setObject(kIOPMWakeEventDetailsKey
, details
);
10660 addWakeReason
= _acceptSystemWakeEvents
;
10662 IOLog("claimSystemWakeEvent(%s, %s, 0x%x) 0x%x %d\n", reason
, deviceName
->getCStringNoCopy(), (int)flags
, _aotPendingFlags
, _aotReadyToFullWake
);
10664 aotFlags
= (kIOPMWakeEventAOTFlags
& flags
);
10665 aotFlags
= (aotFlags
& ~_aotPendingFlags
);
10666 needAOTEvaluate
= false;
10667 if (_aotNow
&& aotFlags
) {
10668 if (kIOPMWakeEventAOTPossibleExit
& flags
) {
10669 _aotMetrics
->possibleCount
++;
10671 if (kIOPMWakeEventAOTConfirmedPossibleExit
& flags
) {
10672 _aotMetrics
->confirmedPossibleCount
++;
10674 if (kIOPMWakeEventAOTRejectedPossibleExit
& flags
) {
10675 _aotMetrics
->rejectedPossibleCount
++;
10677 if (kIOPMWakeEventAOTExpiredPossibleExit
& flags
) {
10678 _aotMetrics
->expiredPossibleCount
++;
10681 _aotPendingFlags
|= aotFlags
;
10682 addWakeReason
= _aotNow
&& _systemWakeEventsArray
&& ((kIOPMWakeEventAOTExitFlags
& aotFlags
));
10683 needAOTEvaluate
= _aotReadyToFullWake
;
10685 DMSG("claimSystemWakeEvent(%s, 0x%x, %s, 0x%llx) aot %d phase 0x%x add %d\n",
10686 reason
, (int)flags
, deviceName
->getCStringNoCopy(), device
->getRegistryEntryID(),
10687 _aotNow
, pmTracer
->getTracePhase(), addWakeReason
);
10689 if (!gWakeReasonSysctlRegistered
) {
10690 // Lazy registration until the platform driver stops registering
10692 gWakeReasonSysctlRegistered
= true;
10693 #if !defined(XNU_TARGET_OS_OSX)
10694 sysctl_register_oid(&sysctl__kern_wakereason
);
10695 #endif /* !defined(XNU_TARGET_OS_OSX) */
10697 if (addWakeReason
) {
10698 _systemWakeEventsArray
->setObject(dict
.get());
10699 if (gWakeReasonString
[0] != '\0') {
10700 strlcat(gWakeReasonString
, " ", sizeof(gWakeReasonString
));
10702 strlcat(gWakeReasonString
, reason
, sizeof(gWakeReasonString
));
10705 WAKEEVENT_UNLOCK();
10706 if (needAOTEvaluate
) {
10707 // Call aotEvaluate() on PM work loop since it may call
10708 // aotExit() which accesses PM state.
10709 pmPowerStateQueue
->submitPowerEvent(kPowerEventAOTEvaluate
);
10716 //******************************************************************************
10717 // claimSystemBootEvent
10719 // For a driver to claim a device is the source/conduit of a system boot event.
10720 //******************************************************************************
10723 IOPMrootDomain::claimSystemBootEvent(
10724 IOService
* device
,
10725 IOOptionBits flags
,
10726 const char * reason
,
10727 __unused OSObject
* details
)
10729 if (!device
|| !reason
) {
10733 DEBUG_LOG("claimSystemBootEvent(%s, %s, 0x%x)\n", reason
, device
->getName(), (uint32_t) flags
);
10735 if (!gBootReasonSysctlRegistered
) {
10736 // Lazy sysctl registration after setting gBootReasonString
10737 strlcat(gBootReasonString
, reason
, sizeof(gBootReasonString
));
10738 sysctl_register_oid(&sysctl__kern_bootreason
);
10739 gBootReasonSysctlRegistered
= true;
10741 WAKEEVENT_UNLOCK();
10744 //******************************************************************************
10745 // claimSystemShutdownEvent
10747 // For drivers to claim a system shutdown event on the ensuing boot.
10748 //******************************************************************************
10751 IOPMrootDomain::claimSystemShutdownEvent(
10752 IOService
* device
,
10753 IOOptionBits flags
,
10754 const char * reason
,
10755 __unused OSObject
* details
)
10757 if (!device
|| !reason
) {
10761 DEBUG_LOG("claimSystemShutdownEvent(%s, %s, 0x%x)\n", reason
, device
->getName(), (uint32_t) flags
);
10763 if (gShutdownReasonString
[0] != '\0') {
10764 strlcat(gShutdownReasonString
, " ", sizeof(gShutdownReasonString
));
10766 strlcat(gShutdownReasonString
, reason
, sizeof(gShutdownReasonString
));
10768 if (!gShutdownReasonSysctlRegistered
) {
10769 sysctl_register_oid(&sysctl__kern_shutdownreason
);
10770 gShutdownReasonSysctlRegistered
= true;
10772 WAKEEVENT_UNLOCK();
10775 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10778 // MARK: PMSettingHandle
10780 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
10783 PMSettingHandle::free( void )
10786 pmso
->clientHandleFreed();
10795 // MARK: PMSettingObject
10798 #define super OSObject
10799 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
10802 * Static constructor/initializer for PMSettingObject
10804 PMSettingObject
*PMSettingObject::pmSettingObject(
10805 IOPMrootDomain
* parent_arg
,
10806 IOPMSettingControllerCallback handler_arg
,
10807 OSObject
* target_arg
,
10808 uintptr_t refcon_arg
,
10809 uint32_t supportedPowerSources
,
10810 const OSSymbol
* settings
[],
10811 OSObject
* *handle_obj
)
10813 uint32_t settingCount
= 0;
10814 PMSettingObject
*pmso
= NULL
;
10815 PMSettingHandle
*pmsh
= NULL
;
10817 if (!parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
) {
10821 // count OSSymbol entries in NULL terminated settings array
10822 while (settings
[settingCount
]) {
10825 if (0 == settingCount
) {
10829 pmso
= new PMSettingObject
;
10830 if (!pmso
|| !pmso
->init()) {
10834 pmsh
= new PMSettingHandle
;
10835 if (!pmsh
|| !pmsh
->init()) {
10839 queue_init(&pmso
->calloutQueue
);
10840 pmso
->parent
= parent_arg
;
10841 pmso
->func
= handler_arg
;
10842 pmso
->target
= target_arg
;
10843 pmso
->refcon
= refcon_arg
;
10844 pmso
->settingCount
= settingCount
;
10846 pmso
->retain(); // handle holds a retain on pmso
10850 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t) * settingCount
);
10851 if (pmso
->publishedFeatureID
) {
10852 for (unsigned int i
= 0; i
< settingCount
; i
++) {
10853 // Since there is now at least one listener to this setting, publish
10854 // PM root domain support for it.
10855 parent_arg
->publishPMSetting( settings
[i
],
10856 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
10860 *handle_obj
= pmsh
;
10874 PMSettingObject::free( void )
10876 if (publishedFeatureID
) {
10877 for (uint32_t i
= 0; i
< settingCount
; i
++) {
10878 if (publishedFeatureID
[i
]) {
10879 parent
->removePublishedFeature( publishedFeatureID
[i
] );
10883 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
10890 PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
10892 return (*func
)(target
, type
, object
, refcon
);
10896 PMSettingObject::clientHandleFreed( void )
10898 parent
->deregisterPMSettingObject(this);
10902 // MARK: PMAssertionsTracker
10904 //*********************************************************************************
10905 //*********************************************************************************
10906 //*********************************************************************************
10907 // class PMAssertionsTracker Implementation
10909 #define kAssertUniqueIDStart 500
10911 PMAssertionsTracker
*
10912 PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
10914 PMAssertionsTracker
*me
;
10916 me
= new PMAssertionsTracker
;
10917 if (!me
|| !me
->init()) {
10924 me
->owner
= rootDomain
;
10925 me
->issuingUniqueID
= kAssertUniqueIDStart
;
10926 me
->assertionsArray
= OSArray::withCapacity(5);
10927 me
->assertionsKernel
= 0;
10928 me
->assertionsUser
= 0;
10929 me
->assertionsCombined
= 0;
10930 me
->assertionsArrayLock
= IOLockAlloc();
10931 me
->tabulateProducerCount
= me
->tabulateConsumerCount
= 0;
10933 assert(me
->assertionsArray
);
10934 assert(me
->assertionsArrayLock
);
10940 * - Update assertionsKernel to reflect the state of all
10941 * assertions in the kernel.
10942 * - Update assertionsCombined to reflect both kernel & user space.
10945 PMAssertionsTracker::tabulate(void)
10949 PMAssertStruct
*_a
= NULL
;
10952 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
10953 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
10957 assertionsKernel
= 0;
10958 assertionsCombined
= 0;
10960 if (!assertionsArray
) {
10964 if ((count
= assertionsArray
->getCount())) {
10965 for (i
= 0; i
< count
; i
++) {
10966 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
10968 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
10969 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
)) {
10970 assertionsKernel
|= _a
->assertionBits
;
10976 tabulateProducerCount
++;
10977 assertionsCombined
= assertionsKernel
| assertionsUser
;
10979 if ((assertionsKernel
!= oldKernel
) ||
10980 (assertionsCombined
!= oldCombined
)) {
10981 owner
->evaluateAssertions(assertionsCombined
, oldCombined
);
10986 PMAssertionsTracker::updateCPUBitAccounting( PMAssertStruct
*assertStruct
)
10991 if (((assertStruct
->assertionBits
& kIOPMDriverAssertionCPUBit
) == 0) ||
10992 (assertStruct
->assertCPUStartTime
== 0)) {
10996 now
= mach_absolute_time();
10997 SUB_ABSOLUTETIME(&now
, &assertStruct
->assertCPUStartTime
);
10998 absolutetime_to_nanoseconds(now
, &nsec
);
10999 assertStruct
->assertCPUDuration
+= nsec
;
11000 assertStruct
->assertCPUStartTime
= 0;
11002 if (assertStruct
->assertCPUDuration
> maxAssertCPUDuration
) {
11003 maxAssertCPUDuration
= assertStruct
->assertCPUDuration
;
11004 maxAssertCPUEntryId
= assertStruct
->registryEntryID
;
11009 PMAssertionsTracker::reportCPUBitAccounting( void )
11011 PMAssertStruct
*_a
;
11019 // Account for drivers that are still holding the CPU assertion
11020 if (assertionsKernel
& kIOPMDriverAssertionCPUBit
) {
11021 now
= mach_absolute_time();
11022 if ((count
= assertionsArray
->getCount())) {
11023 for (i
= 0; i
< count
; i
++) {
11024 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
11026 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
11027 if ((_a
->assertionBits
& kIOPMDriverAssertionCPUBit
) &&
11028 (_a
->level
== kIOPMDriverAssertionLevelOn
) &&
11029 (_a
->assertCPUStartTime
!= 0)) {
11030 // Don't modify PMAssertStruct, leave that
11031 // for updateCPUBitAccounting()
11032 SUB_ABSOLUTETIME(&now
, &_a
->assertCPUStartTime
);
11033 absolutetime_to_nanoseconds(now
, &nsec
);
11034 nsec
+= _a
->assertCPUDuration
;
11035 if (nsec
> maxAssertCPUDuration
) {
11036 maxAssertCPUDuration
= nsec
;
11037 maxAssertCPUEntryId
= _a
->registryEntryID
;
11045 if (maxAssertCPUDuration
) {
11046 DLOG("cpu assertion held for %llu ms by 0x%llx\n",
11047 (maxAssertCPUDuration
/ NSEC_PER_MSEC
), maxAssertCPUEntryId
);
11050 maxAssertCPUDuration
= 0;
11051 maxAssertCPUEntryId
= 0;
11055 PMAssertionsTracker::publishProperties( void )
11057 OSSharedPtr
<OSArray
> assertionsSummary
;
11059 if (tabulateConsumerCount
!= tabulateProducerCount
) {
11060 IOLockLock(assertionsArrayLock
);
11062 tabulateConsumerCount
= tabulateProducerCount
;
11064 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
11066 assertionsSummary
= copyAssertionsArray();
11067 if (assertionsSummary
) {
11068 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
.get());
11070 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
11073 /* Publish the IOPMrootDomain property "DriverPMAssertions"
11075 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
11077 IOLockUnlock(assertionsArrayLock
);
11081 PMAssertionsTracker::PMAssertStruct
*
11082 PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
11084 PMAssertStruct
*_a
= NULL
;
11090 if (assertionsArray
11091 && (count
= assertionsArray
->getCount())) {
11092 for (i
= 0; i
< count
; i
++) {
11093 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
11095 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
11096 if (_a
&& (_id
== _a
->id
)) {
11114 /* PMAssertionsTracker::handleCreateAssertion
11115 * Perform assertion work on the PM workloop. Do not call directly.
11118 PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
11120 PMAssertStruct
*assertStruct
;
11124 if (newAssertion
) {
11125 IOLockLock(assertionsArrayLock
);
11126 assertStruct
= (PMAssertStruct
*) newAssertion
->getBytesNoCopy();
11127 if ((assertStruct
->assertionBits
& kIOPMDriverAssertionCPUBit
) &&
11128 (assertStruct
->level
== kIOPMDriverAssertionLevelOn
)) {
11129 assertStruct
->assertCPUStartTime
= mach_absolute_time();
11131 assertionsArray
->setObject(newAssertion
);
11132 IOLockUnlock(assertionsArrayLock
);
11133 newAssertion
->release();
11137 return kIOReturnSuccess
;
11140 /* PMAssertionsTracker::createAssertion
11141 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
11145 PMAssertionsTracker::createAssertion(
11146 IOPMDriverAssertionType which
,
11147 IOPMDriverAssertionLevel level
,
11148 IOService
*serviceID
,
11149 const char *whoItIs
,
11150 IOPMDriverAssertionID
*outID
)
11152 OSSharedPtr
<OSData
> dataStore
;
11153 PMAssertStruct track
;
11155 // Warning: trillions and trillions of created assertions may overflow the unique ID.
11156 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
11157 track
.level
= level
;
11158 track
.assertionBits
= which
;
11160 // NB: ownerString is explicitly managed by PMAssertStruct
11161 // it will be released in `handleReleaseAssertion' below
11162 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
).detach():nullptr;
11163 track
.ownerService
= serviceID
;
11164 track
.registryEntryID
= serviceID
? serviceID
->getRegistryEntryID():0;
11165 track
.modifiedTime
= 0;
11166 pmEventTimeStamp(&track
.createdTime
);
11167 track
.assertCPUStartTime
= 0;
11168 track
.assertCPUDuration
= 0;
11170 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
11172 if (track
.ownerString
) {
11173 track
.ownerString
->release();
11174 track
.ownerString
= NULL
;
11176 return kIOReturnNoMemory
;
11181 if (owner
&& owner
->pmPowerStateQueue
) {
11182 // queue action is responsible for releasing dataStore
11183 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
.detach());
11186 return kIOReturnSuccess
;
11189 /* PMAssertionsTracker::handleReleaseAssertion
11190 * Runs in PM workloop. Do not call directly.
11193 PMAssertionsTracker::handleReleaseAssertion(
11194 IOPMDriverAssertionID _id
)
11199 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
11201 if (!assertStruct
) {
11202 return kIOReturnNotFound
;
11205 IOLockLock(assertionsArrayLock
);
11207 if ((assertStruct
->assertionBits
& kIOPMDriverAssertionCPUBit
) &&
11208 (assertStruct
->level
== kIOPMDriverAssertionLevelOn
)) {
11209 updateCPUBitAccounting(assertStruct
);
11212 if (assertStruct
->ownerString
) {
11213 assertStruct
->ownerString
->release();
11214 assertStruct
->ownerString
= NULL
;
11217 assertionsArray
->removeObject(index
);
11218 IOLockUnlock(assertionsArrayLock
);
11221 return kIOReturnSuccess
;
11224 /* PMAssertionsTracker::releaseAssertion
11225 * Releases an assertion and affects system behavior if appropiate.
11226 * Actual work happens on PM workloop.
11229 PMAssertionsTracker::releaseAssertion(
11230 IOPMDriverAssertionID _id
)
11232 if (owner
&& owner
->pmPowerStateQueue
) {
11233 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, NULL
, _id
);
11235 return kIOReturnSuccess
;
11238 /* PMAssertionsTracker::handleSetAssertionLevel
11239 * Runs in PM workloop. Do not call directly.
11242 PMAssertionsTracker::handleSetAssertionLevel(
11243 IOPMDriverAssertionID _id
,
11244 IOPMDriverAssertionLevel _level
)
11246 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
11250 if (!assertStruct
) {
11251 return kIOReturnNotFound
;
11254 IOLockLock(assertionsArrayLock
);
11255 pmEventTimeStamp(&assertStruct
->modifiedTime
);
11256 if ((assertStruct
->assertionBits
& kIOPMDriverAssertionCPUBit
) &&
11257 (assertStruct
->level
!= _level
)) {
11258 if (_level
== kIOPMDriverAssertionLevelOn
) {
11259 assertStruct
->assertCPUStartTime
= mach_absolute_time();
11261 updateCPUBitAccounting(assertStruct
);
11264 assertStruct
->level
= _level
;
11265 IOLockUnlock(assertionsArrayLock
);
11268 return kIOReturnSuccess
;
11271 /* PMAssertionsTracker::setAssertionLevel
11274 PMAssertionsTracker::setAssertionLevel(
11275 IOPMDriverAssertionID _id
,
11276 IOPMDriverAssertionLevel _level
)
11278 if (owner
&& owner
->pmPowerStateQueue
) {
11279 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
11280 (void *)(uintptr_t)_level
, _id
);
11283 return kIOReturnSuccess
;
11287 PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
11289 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
11293 if (new_user_levels
!= assertionsUser
) {
11294 DLOG("assertionsUser 0x%llx->0x%llx\n", assertionsUser
, new_user_levels
);
11295 assertionsUser
= new_user_levels
;
11299 return kIOReturnSuccess
;
11303 PMAssertionsTracker::setUserAssertionLevels(
11304 IOPMDriverAssertionType new_user_levels
)
11306 if (gIOPMWorkLoop
) {
11307 gIOPMWorkLoop
->runAction(
11308 OSMemberFunctionCast(
11309 IOWorkLoop::Action
,
11311 &PMAssertionsTracker::handleSetUserAssertionLevels
),
11313 (void *) &new_user_levels
, NULL
, NULL
, NULL
);
11316 return kIOReturnSuccess
;
11320 OSSharedPtr
<OSArray
>
11321 PMAssertionsTracker::copyAssertionsArray(void)
11325 OSSharedPtr
<OSArray
> outArray
= NULL
;
11327 if (!assertionsArray
|| (0 == (count
= assertionsArray
->getCount()))) {
11330 outArray
= OSArray::withCapacity(count
);
11335 for (i
= 0; i
< count
; i
++) {
11336 PMAssertStruct
*_a
= NULL
;
11338 OSSharedPtr
<OSDictionary
> details
;
11340 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
11341 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy())) {
11342 OSSharedPtr
<OSNumber
> _n
;
11344 details
= OSDictionary::withCapacity(7);
11349 outArray
->setObject(details
.get());
11351 _n
= OSNumber::withNumber(_a
->id
, 64);
11353 details
->setObject(kIOPMDriverAssertionIDKey
, _n
.get());
11355 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
11357 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
.get());
11359 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
11361 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
.get());
11363 _n
= OSNumber::withNumber((uintptr_t)_a
->registryEntryID
, 64);
11365 details
->setObject(kIOPMDriverAssertionRegistryEntryIDKey
, _n
.get());
11367 _n
= OSNumber::withNumber(_a
->level
, 64);
11369 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
.get());
11371 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
11373 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
.get());
11376 if (_a
->ownerString
) {
11377 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
11383 return os::move(outArray
);
11386 IOPMDriverAssertionType
11387 PMAssertionsTracker::getActivatedAssertions(void)
11389 return assertionsCombined
;
11392 IOPMDriverAssertionLevel
11393 PMAssertionsTracker::getAssertionLevel(
11394 IOPMDriverAssertionType type
)
11396 // FIXME: unused and also wrong
11397 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
)) {
11398 return kIOPMDriverAssertionLevelOn
;
11400 return kIOPMDriverAssertionLevelOff
;
11404 //*********************************************************************************
11405 //*********************************************************************************
11406 //*********************************************************************************
11410 pmEventTimeStamp(uint64_t *recordTS
)
11413 clock_usec_t tusec
;
11419 // We assume tsec fits into 32 bits; 32 bits holds enough
11420 // seconds for 136 years since the epoch in 1970.
11421 clock_get_calendar_microtime(&tsec
, &tusec
);
11424 // Pack the sec & microsec calendar time into a uint64_t, for fun.
11426 *recordTS
|= (uint32_t)tusec
;
11427 *recordTS
|= ((uint64_t)tsec
<< 32);
11433 // MARK: IORootParent
11435 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
11437 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
11439 // The reason that root domain needs a root parent is to facilitate demand
11440 // sleep, since a power change from the root parent cannot be vetoed.
11442 // The above statement is no longer true since root domain now performs
11443 // demand sleep using overrides. But root parent remains to avoid changing
11444 // the power tree stacking. Root parent is parked at the max power state.
11447 static IOPMPowerState patriarchPowerStates
[2] =
11449 {1, 0, ON_POWER
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
11450 {1, 0, ON_POWER
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
11454 IORootParent::initialize( void )
11457 gIOPMPSExternalConnectedKey
= OSSymbol::withCStringNoCopy(kIOPMPSExternalConnectedKey
);
11458 gIOPMPSExternalChargeCapableKey
= OSSymbol::withCStringNoCopy(kIOPMPSExternalChargeCapableKey
);
11459 gIOPMPSBatteryInstalledKey
= OSSymbol::withCStringNoCopy(kIOPMPSBatteryInstalledKey
);
11460 gIOPMPSIsChargingKey
= OSSymbol::withCStringNoCopy(kIOPMPSIsChargingKey
);
11461 gIOPMPSAtWarnLevelKey
= OSSymbol::withCStringNoCopy(kIOPMPSAtWarnLevelKey
);
11462 gIOPMPSAtCriticalLevelKey
= OSSymbol::withCStringNoCopy(kIOPMPSAtCriticalLevelKey
);
11463 gIOPMPSCurrentCapacityKey
= OSSymbol::withCStringNoCopy(kIOPMPSCurrentCapacityKey
);
11464 gIOPMPSMaxCapacityKey
= OSSymbol::withCStringNoCopy(kIOPMPSMaxCapacityKey
);
11465 gIOPMPSDesignCapacityKey
= OSSymbol::withCStringNoCopy(kIOPMPSDesignCapacityKey
);
11466 gIOPMPSTimeRemainingKey
= OSSymbol::withCStringNoCopy(kIOPMPSTimeRemainingKey
);
11467 gIOPMPSAmperageKey
= OSSymbol::withCStringNoCopy(kIOPMPSAmperageKey
);
11468 gIOPMPSVoltageKey
= OSSymbol::withCStringNoCopy(kIOPMPSVoltageKey
);
11469 gIOPMPSCycleCountKey
= OSSymbol::withCStringNoCopy(kIOPMPSCycleCountKey
);
11470 gIOPMPSMaxErrKey
= OSSymbol::withCStringNoCopy(kIOPMPSMaxErrKey
);
11471 gIOPMPSAdapterInfoKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterInfoKey
);
11472 gIOPMPSLocationKey
= OSSymbol::withCStringNoCopy(kIOPMPSLocationKey
);
11473 gIOPMPSErrorConditionKey
= OSSymbol::withCStringNoCopy(kIOPMPSErrorConditionKey
);
11474 gIOPMPSManufacturerKey
= OSSymbol::withCStringNoCopy(kIOPMPSManufacturerKey
);
11475 gIOPMPSManufactureDateKey
= OSSymbol::withCStringNoCopy(kIOPMPSManufactureDateKey
);
11476 gIOPMPSModelKey
= OSSymbol::withCStringNoCopy(kIOPMPSModelKey
);
11477 gIOPMPSSerialKey
= OSSymbol::withCStringNoCopy(kIOPMPSSerialKey
);
11478 gIOPMPSLegacyBatteryInfoKey
= OSSymbol::withCStringNoCopy(kIOPMPSLegacyBatteryInfoKey
);
11479 gIOPMPSBatteryHealthKey
= OSSymbol::withCStringNoCopy(kIOPMPSBatteryHealthKey
);
11480 gIOPMPSHealthConfidenceKey
= OSSymbol::withCStringNoCopy(kIOPMPSHealthConfidenceKey
);
11481 gIOPMPSCapacityEstimatedKey
= OSSymbol::withCStringNoCopy(kIOPMPSCapacityEstimatedKey
);
11482 gIOPMPSBatteryChargeStatusKey
= OSSymbol::withCStringNoCopy(kIOPMPSBatteryChargeStatusKey
);
11483 gIOPMPSBatteryTemperatureKey
= OSSymbol::withCStringNoCopy(kIOPMPSBatteryTemperatureKey
);
11484 gIOPMPSAdapterDetailsKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsKey
);
11485 gIOPMPSChargerConfigurationKey
= OSSymbol::withCStringNoCopy(kIOPMPSChargerConfigurationKey
);
11486 gIOPMPSAdapterDetailsIDKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsIDKey
);
11487 gIOPMPSAdapterDetailsWattsKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsWattsKey
);
11488 gIOPMPSAdapterDetailsRevisionKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsRevisionKey
);
11489 gIOPMPSAdapterDetailsSerialNumberKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsSerialNumberKey
);
11490 gIOPMPSAdapterDetailsFamilyKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsFamilyKey
);
11491 gIOPMPSAdapterDetailsAmperageKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsAmperageKey
);
11492 gIOPMPSAdapterDetailsDescriptionKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsDescriptionKey
);
11493 gIOPMPSAdapterDetailsPMUConfigurationKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsPMUConfigurationKey
);
11494 gIOPMPSAdapterDetailsSourceIDKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsSourceIDKey
);
11495 gIOPMPSAdapterDetailsErrorFlagsKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsErrorFlagsKey
);
11496 gIOPMPSAdapterDetailsSharedSourceKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsSharedSourceKey
);
11497 gIOPMPSAdapterDetailsCloakedKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsCloakedKey
);
11498 gIOPMPSInvalidWakeSecondsKey
= OSSymbol::withCStringNoCopy(kIOPMPSInvalidWakeSecondsKey
);
11499 gIOPMPSPostChargeWaitSecondsKey
= OSSymbol::withCStringNoCopy(kIOPMPSPostChargeWaitSecondsKey
);
11500 gIOPMPSPostDishargeWaitSecondsKey
= OSSymbol::withCStringNoCopy(kIOPMPSPostDishargeWaitSecondsKey
);
11504 IORootParent::start( IOService
* nub
)
11506 IOService::start(nub
);
11507 attachToParent( getRegistryRoot(), gIOPowerPlane
);
11509 registerPowerDriver(this, patriarchPowerStates
, 2);
11515 IORootParent::shutDownSystem( void )
11520 IORootParent::restartSystem( void )
11525 IORootParent::sleepSystem( void )
11530 IORootParent::dozeSystem( void )
11535 IORootParent::sleepToDoze( void )
11540 IORootParent::wakeSystem( void )
11544 OSSharedPtr
<OSObject
>
11545 IORootParent::copyProperty( const char * aKey
) const
11547 return IOService::copyProperty(aKey
);
11551 IOPMrootDomain::getWatchdogTimeout()
11553 if (gSwdSleepWakeTimeout
) {
11554 gSwdSleepTimeout
= gSwdWakeTimeout
= gSwdSleepWakeTimeout
;
11556 if ((pmTracer
->getTracePhase() < kIOPMTracePointSystemSleep
) ||
11557 (pmTracer
->getTracePhase() == kIOPMTracePointDarkWakeEntry
)) {
11558 return gSwdSleepTimeout
? gSwdSleepTimeout
: WATCHDOG_SLEEP_TIMEOUT
;
11560 return gSwdWakeTimeout
? gSwdWakeTimeout
: WATCHDOG_WAKE_TIMEOUT
;
11565 #if defined(__i386__) || defined(__x86_64__) || (defined(__arm64__) && HIBERNATION)
11567 IOPMrootDomain::restartWithStackshot()
11569 takeStackshot(true);
11571 return kIOReturnSuccess
;
11575 IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger
)
11577 takeStackshot(wdogTrigger
);
11581 IOPMrootDomain::tracePhase2String(uint32_t tracePhase
, const char **phaseString
, const char **description
)
11583 switch (tracePhase
) {
11584 case kIOPMTracePointSleepStarted
:
11585 *phaseString
= "kIOPMTracePointSleepStarted";
11586 *description
= "starting sleep";
11589 case kIOPMTracePointSleepApplications
:
11590 *phaseString
= "kIOPMTracePointSleepApplications";
11591 *description
= "notifying applications";
11594 case kIOPMTracePointSleepPriorityClients
:
11595 *phaseString
= "kIOPMTracePointSleepPriorityClients";
11596 *description
= "notifying clients about upcoming system capability changes";
11599 case kIOPMTracePointSleepWillChangeInterests
:
11600 *phaseString
= "kIOPMTracePointSleepWillChangeInterests";
11601 *description
= "creating hibernation file or while calling rootDomain's clients about upcoming rootDomain's state changes";
11604 case kIOPMTracePointSleepPowerPlaneDrivers
:
11605 *phaseString
= "kIOPMTracePointSleepPowerPlaneDrivers";
11606 *description
= "calling power state change callbacks";
11609 case kIOPMTracePointSleepDidChangeInterests
:
11610 *phaseString
= "kIOPMTracePointSleepDidChangeInterests";
11611 *description
= "calling rootDomain's clients about rootDomain's state changes";
11614 case kIOPMTracePointSleepCapabilityClients
:
11615 *phaseString
= "kIOPMTracePointSleepCapabilityClients";
11616 *description
= "notifying clients about current system capabilities";
11619 case kIOPMTracePointSleepPlatformActions
:
11620 *phaseString
= "kIOPMTracePointSleepPlatformActions";
11621 *description
= "calling Quiesce/Sleep action callbacks";
11624 case kIOPMTracePointSleepCPUs
:
11626 *phaseString
= "kIOPMTracePointSleepCPUs";
11627 #if defined(__i386__) || defined(__x86_64__)
11629 * We cannot use the getCPUNumber() method to get the cpu number, since
11630 * that cpu number is unrelated to the cpu number we need (we need the cpu
11631 * number as enumerated by the scheduler, NOT the CPU number enumerated
11632 * by ACPIPlatform as the CPUs are enumerated in MADT order).
11633 * Instead, pass the Mach processor pointer associated with the current
11634 * shutdown target so its associated cpu_id can be used in
11635 * processor_to_datastring.
11637 if (currentShutdownTarget
!= NULL
&&
11638 currentShutdownTarget
->getMachProcessor() != NULL
) {
11639 const char *sbuf
= processor_to_datastring("halting all non-boot CPUs",
11640 currentShutdownTarget
->getMachProcessor());
11641 *description
= sbuf
;
11643 *description
= "halting all non-boot CPUs";
11646 *description
= "halting all non-boot CPUs";
11650 case kIOPMTracePointSleepPlatformDriver
:
11651 *phaseString
= "kIOPMTracePointSleepPlatformDriver";
11652 *description
= "executing platform specific code";
11655 case kIOPMTracePointHibernate
:
11656 *phaseString
= "kIOPMTracePointHibernate";
11657 *description
= "writing the hibernation image";
11660 case kIOPMTracePointSystemSleep
:
11661 *phaseString
= "kIOPMTracePointSystemSleep";
11662 *description
= "in EFI/Bootrom after last point of entry to sleep";
11665 case kIOPMTracePointWakePlatformDriver
:
11666 *phaseString
= "kIOPMTracePointWakePlatformDriver";
11667 *description
= "executing platform specific code";
11671 case kIOPMTracePointWakePlatformActions
:
11672 *phaseString
= "kIOPMTracePointWakePlatformActions";
11673 *description
= "calling Wake action callbacks";
11676 case kIOPMTracePointWakeCPUs
:
11677 *phaseString
= "kIOPMTracePointWakeCPUs";
11678 *description
= "starting non-boot CPUs";
11681 case kIOPMTracePointWakeWillPowerOnClients
:
11682 *phaseString
= "kIOPMTracePointWakeWillPowerOnClients";
11683 *description
= "sending kIOMessageSystemWillPowerOn message to kernel and userspace clients";
11686 case kIOPMTracePointWakeWillChangeInterests
:
11687 *phaseString
= "kIOPMTracePointWakeWillChangeInterests";
11688 *description
= "calling rootDomain's clients about upcoming rootDomain's state changes";
11691 case kIOPMTracePointWakeDidChangeInterests
:
11692 *phaseString
= "kIOPMTracePointWakeDidChangeInterests";
11693 *description
= "calling rootDomain's clients about completed rootDomain's state changes";
11696 case kIOPMTracePointWakePowerPlaneDrivers
:
11697 *phaseString
= "kIOPMTracePointWakePowerPlaneDrivers";
11698 *description
= "calling power state change callbacks";
11701 case kIOPMTracePointWakeCapabilityClients
:
11702 *phaseString
= "kIOPMTracePointWakeCapabilityClients";
11703 *description
= "informing clients about current system capabilities";
11706 case kIOPMTracePointWakeApplications
:
11707 *phaseString
= "kIOPMTracePointWakeApplications";
11708 *description
= "sending asynchronous kIOMessageSystemHasPoweredOn message to userspace clients";
11711 case kIOPMTracePointDarkWakeEntry
:
11712 *phaseString
= "kIOPMTracePointDarkWakeEntry";
11713 *description
= "entering darkwake on way to sleep";
11716 case kIOPMTracePointDarkWakeExit
:
11717 *phaseString
= "kIOPMTracePointDarkWakeExit";
11718 *description
= "entering fullwake from darkwake";
11722 *phaseString
= NULL
;
11723 *description
= NULL
;
11728 IOPMrootDomain::saveFailureData2File()
11730 unsigned int len
= 0;
11731 char failureStr
[512];
11734 OSNumber
*statusCode
;
11735 uint64_t pmStatusCode
= 0;
11736 uint32_t phaseData
= 0;
11737 uint32_t phaseDetail
= 0;
11738 bool efiFailure
= false;
11740 OSSharedPtr
<OSObject
> statusCodeProp
= copyProperty(kIOPMSleepWakeFailureCodeKey
);
11741 statusCode
= OSDynamicCast(OSNumber
, statusCodeProp
.get());
11743 pmStatusCode
= statusCode
->unsigned64BitValue();
11744 phaseData
= pmStatusCode
& 0xFFFFFFFF;
11745 phaseDetail
= (pmStatusCode
>> 32) & 0xFFFFFFFF;
11746 if ((phaseData
& 0xFF) == kIOPMTracePointSystemSleep
) {
11747 LOG("Sleep Wake failure in EFI\n");
11750 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
);
11751 len
= (typeof(len
))strnlen(failureStr
, sizeof(failureStr
));
11756 if (PEReadNVRAMProperty(kIOSleepWakeFailurePanic
, NULL
, &len
)) {
11757 swd_flags
|= SWD_BOOT_BY_SW_WDOG
;
11758 PERemoveNVRAMProperty(kIOSleepWakeFailurePanic
);
11759 // dump panic will handle saving nvram data
11763 /* Keeping this around for capturing data during power
11766 if (!PEReadNVRAMProperty(kIOSleepWakeFailureString
, NULL
, &len
)) {
11767 DLOG("No sleep wake failure string\n");
11771 DLOG("Ignoring zero byte SleepWake failure string\n");
11775 // if PMStatus code is zero, delete stackshot and return
11777 if (((pmStatusCode
& 0xFFFFFFFF) & 0xFF) == 0) {
11778 // there was no sleep wake failure
11779 // this can happen if delete stackshot was called
11780 // before take stackshot completed. Let us delete any
11781 // sleep wake failure data in nvram
11782 DLOG("Deleting stackshot on successful wake\n");
11788 if (len
> sizeof(failureStr
)) {
11789 len
= sizeof(failureStr
);
11792 PEReadNVRAMProperty(kIOSleepWakeFailureString
, failureStr
, &len
);
11794 if (failureStr
[0] != 0) {
11795 error
= sleepWakeDebugSaveFile(kSleepWakeFailureStringFile
, failureStr
, len
);
11797 DLOG("Failed to save SleepWake failure string to file. error:%d\n", error
);
11799 DLOG("Saved SleepWake failure string to file.\n");
11803 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
)) {
11808 unsigned int len
= 0;
11810 char nvram_var_name_buffer
[20];
11811 unsigned int concat_len
= 0;
11812 swd_hdr
*hdr
= NULL
;
11815 hdr
= (swd_hdr
*)swd_buffer
;
11816 outbuf
= (char *)hdr
+ hdr
->spindump_offset
;
11817 OSBoundedArrayRef
<char> boundedOutBuf(outbuf
, hdr
->alloc_size
- hdr
->spindump_offset
);
11819 for (int i
= 0; i
< 8; i
++) {
11820 snprintf(nvram_var_name_buffer
, sizeof(nvram_var_name_buffer
), "%s%02d", SWD_STACKSHOT_VAR_PREFIX
, i
+ 1);
11821 if (!PEReadNVRAMProperty(nvram_var_name_buffer
, NULL
, &len
)) {
11822 LOG("No SleepWake blob to read beyond chunk %d\n", i
);
11825 if (PEReadNVRAMProperty(nvram_var_name_buffer
, boundedOutBuf
.slice(concat_len
, len
).data(), &len
) == FALSE
) {
11826 PERemoveNVRAMProperty(nvram_var_name_buffer
);
11827 LOG("Could not read the property :-(\n");
11830 PERemoveNVRAMProperty(nvram_var_name_buffer
);
11833 LOG("Concatenated length for the SWD blob %d\n", concat_len
);
11836 error
= sleepWakeDebugSaveFile(kSleepWakeStacksFilename
, outbuf
, concat_len
);
11838 LOG("Failed to save SleepWake zipped data to file. error:%d\n", error
);
11840 LOG("Saved SleepWake zipped data to file.\n");
11843 // There is a sleep wake failure string but no stackshot
11844 // Write a placeholder stacks file so that swd runs
11845 snprintf(outbuf
, 20, "%s", "No stackshot data\n");
11846 error
= sleepWakeDebugSaveFile(kSleepWakeStacksFilename
, outbuf
, 20);
11848 LOG("Failed to save SleepWake zipped data to file. error:%d\n", error
);
11850 LOG("Saved SleepWake zipped data to file.\n");
11854 LOG("No buffer allocated to save failure stackshot\n");
11858 gRootDomain
->swd_lock
= 0;
11860 PERemoveNVRAMProperty(kIOSleepWakeFailureString
);
11866 IOPMrootDomain::getFailureData(thread_t
*thread
, char *failureStr
, size_t strLen
)
11868 OSSharedPtr
<IORegistryIterator
> iter
;
11869 OSSharedPtr
<const OSSymbol
> kextName
= NULL
;
11870 IORegistryEntry
* entry
;
11872 bool nodeFound
= false;
11874 const void * callMethod
= NULL
;
11875 const char * objectName
= NULL
;
11876 uint32_t timeout
= getWatchdogTimeout();
11877 const char * phaseString
= NULL
;
11878 const char * phaseDescription
= NULL
;
11880 IOPMServiceInterestNotifier
*notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, notifierObject
.get());
11881 uint32_t tracePhase
= pmTracer
->getTracePhase();
11884 if ((tracePhase
< kIOPMTracePointSystemSleep
) || (tracePhase
== kIOPMTracePointDarkWakeEntry
)) {
11885 snprintf(failureStr
, strLen
, "Sleep transition timed out after %d seconds", timeout
);
11887 snprintf(failureStr
, strLen
, "Wake transition timed out after %d seconds", timeout
);
11889 tracePhase2String(tracePhase
, &phaseString
, &phaseDescription
);
11891 if (notifierThread
) {
11892 if (notifier
&& (notifier
->identifier
)) {
11893 objectName
= notifier
->identifier
->getCStringNoCopy();
11895 *thread
= notifierThread
;
11897 iter
= IORegistryIterator::iterateOver(
11898 getPMRootDomain(), gIOPowerPlane
, kIORegistryIterateRecursively
);
11901 while ((entry
= iter
->getNextObject())) {
11902 node
= OSDynamicCast(IOService
, entry
);
11906 if (OSDynamicCast(IOPowerConnection
, node
)) {
11910 if (node
->getBlockingDriverCall(thread
, &callMethod
)) {
11917 kextName
= copyKextIdentifierWithAddress((vm_address_t
) callMethod
);
11919 objectName
= kextName
->getCStringNoCopy();
11923 if (phaseDescription
) {
11924 strlcat(failureStr
, " while ", strLen
);
11925 strlcat(failureStr
, phaseDescription
, strLen
);
11926 strlcat(failureStr
, ".", strLen
);
11929 strlcat(failureStr
, " Suspected bundle: ", strLen
);
11930 strlcat(failureStr
, objectName
, strLen
);
11931 strlcat(failureStr
, ".", strLen
);
11934 char threadName
[40];
11935 snprintf(threadName
, sizeof(threadName
), " Thread 0x%llx.", thread_tid(*thread
));
11936 strlcat(failureStr
, threadName
, strLen
);
11939 DLOG("%s\n", failureStr
);
11942 struct swd_stackshot_compressed_data
{
11943 z_output_func zoutput
;
11945 uint64_t totalbytes
;
11946 uint64_t lastpercent
;
11948 unsigned outremain
;
11953 struct swd_stackshot_compressed_data swd_zip_var
= { };
11956 swd_zs_alloc(void *__unused ref
, u_int items
, u_int size
)
11959 LOG("Alloc in zipping %d items of size %d\n", items
, size
);
11961 result
= (void *)(swd_zs_zmem
+ swd_zs_zoffset
);
11962 swd_zs_zoffset
+= ~31L & (31 + (items
* size
)); // 32b align for vector crc
11963 LOG("Offset %zu\n", swd_zs_zoffset
);
11968 swd_zinput(z_streamp strm
, Bytef
*buf
, unsigned size
)
11972 len
= strm
->avail_in
;
11981 if (strm
->next_in
!= (Bytef
*) strm
) {
11982 memcpy(buf
, strm
->next_in
, len
);
11987 strm
->adler
= z_crc32(strm
->adler
, buf
, len
);
11989 strm
->avail_in
-= len
;
11990 strm
->next_in
+= len
;
11991 strm
->total_in
+= len
;
11997 swd_zoutput(z_streamp strm
, Bytef
*buf
, unsigned len
)
11999 unsigned int i
= 0;
12000 // if outlen > max size don't add to the buffer
12001 assert(buf
!= NULL
);
12003 if (swd_zip_var
.outlen
+ len
> SWD_COMPRESSED_BUFSIZE
) {
12004 LOG("No space to GZIP... not writing to NVRAM\n");
12008 for (i
= 0; i
< len
; i
++) {
12009 *(swd_zip_var
.outbuf
+ swd_zip_var
.outlen
+ i
) = *(buf
+ i
);
12011 swd_zip_var
.outlen
+= len
;
12016 swd_zs_free(void * __unused ref
, void * __unused ptr
)
12021 swd_compress(char *inPtr
, char *outPtr
, size_t numBytes
)
12026 if (((unsigned int) numBytes
) != numBytes
) {
12030 if (!swd_zs
.zalloc
) {
12031 swd_zs
.zalloc
= swd_zs_alloc
;
12032 swd_zs
.zfree
= swd_zs_free
;
12033 if (deflateInit2(&swd_zs
, Z_BEST_SPEED
, Z_DEFLATED
, wbits
+ 16, memlevel
, Z_DEFAULT_STRATEGY
)) {
12034 // allocation failed
12035 bzero(&swd_zs
, sizeof(swd_zs
));
12036 // swd_zs_zoffset = 0;
12038 LOG("PMRD inited the zlib allocation routines\n");
12042 swd_zip_var
.zipped
= 0;
12043 swd_zip_var
.totalbytes
= 0; // should this be the max that we have?
12044 swd_zip_var
.lastpercent
= 0;
12045 swd_zip_var
.error
= kIOReturnSuccess
;
12046 swd_zip_var
.outremain
= 0;
12047 swd_zip_var
.outlen
= 0;
12048 swd_zip_var
.writes
= 0;
12049 swd_zip_var
.outbuf
= (Bytef
*)outPtr
;
12051 swd_zip_var
.totalbytes
= numBytes
;
12053 swd_zs
.avail_in
= 0;
12054 swd_zs
.next_in
= NULL
;
12055 swd_zs
.avail_out
= 0;
12056 swd_zs
.next_out
= NULL
;
12058 deflateResetWithIO(&swd_zs
, swd_zinput
, swd_zoutput
);
12064 while (swd_zip_var
.error
>= 0) {
12065 if (!zs
->avail_in
) {
12066 zs
->next_in
= (unsigned char *)inPtr
? (Bytef
*)inPtr
: (Bytef
*)zs
; /* zero marker? */
12067 zs
->avail_in
= (unsigned int) numBytes
;
12069 if (!zs
->avail_out
) {
12070 zs
->next_out
= (Bytef
*)zs
;
12071 zs
->avail_out
= UINT32_MAX
;
12073 zr
= deflate(zs
, Z_NO_FLUSH
);
12074 if (Z_STREAM_END
== zr
) {
12078 LOG("ZERR %d\n", zr
);
12079 swd_zip_var
.error
= zr
;
12081 if (zs
->total_in
== numBytes
) {
12087 //now flush the stream
12088 while (swd_zip_var
.error
>= 0) {
12089 if (!zs
->avail_out
) {
12090 zs
->next_out
= (Bytef
*)zs
;
12091 zs
->avail_out
= UINT32_MAX
;
12093 zr
= deflate(zs
, Z_FINISH
);
12094 if (Z_STREAM_END
== zr
) {
12098 LOG("ZERR %d\n", zr
);
12099 swd_zip_var
.error
= zr
;
12101 if (zs
->total_in
== numBytes
) {
12102 LOG("Total output size %d\n", swd_zip_var
.outlen
);
12108 return swd_zip_var
.outlen
;
12112 IOPMrootDomain::deleteStackshot()
12114 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
)) {
12115 // takeStackshot hasn't completed
12118 LOG("Deleting any sleepwake failure data in nvram\n");
12120 PERemoveNVRAMProperty(kIOSleepWakeFailureString
);
12121 char nvram_var_name_buf
[20];
12122 for (int i
= 0; i
< 8; i
++) {
12123 snprintf(nvram_var_name_buf
, sizeof(nvram_var_name_buf
), "%s%02d", SWD_STACKSHOT_VAR_PREFIX
, i
+ 1);
12124 if (PERemoveNVRAMProperty(nvram_var_name_buf
) == false) {
12125 LOG("Removing %s returned false\n", nvram_var_name_buf
);
12128 // force NVRAM sync
12129 if (PEWriteNVRAMProperty(kIONVRAMSyncNowPropertyKey
, kIONVRAMSyncNowPropertyKey
, (unsigned int) strlen(kIONVRAMSyncNowPropertyKey
)) == false) {
12130 DLOG("Failed to force nvram sync\n");
12132 gRootDomain
->swd_lock
= 0;
12136 IOPMrootDomain::takeStackshot(bool wdogTrigger
)
12138 swd_hdr
* hdr
= NULL
;
12142 kern_return_t kr
= KERN_SUCCESS
;
12147 uint32_t bytesRemaining
;
12148 unsigned bytesWritten
= 0;
12150 char failureStr
[512];
12151 thread_t thread
= NULL
;
12152 const char * swfPanic
= "swfPanic";
12157 #if defined(__i386__) || defined(__x86_64__)
12158 const bool concise
= false;
12160 const bool concise
= true;
12163 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
)) {
12168 if ((kIOSleepWakeWdogOff
& gIOKitDebug
) || systemBooting
|| systemShutdown
|| gWillShutdown
) {
12173 getFailureData(&thread
, failureStr
, sizeof(failureStr
));
12175 if (concise
|| (PEGetCoprocessorVersion() >= kCoprocessorVersion2
)) {
12176 goto skip_stackshot
;
12181 clock_get_uptime(&now
);
12182 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
12183 absolutetime_to_nanoseconds(now
, &nsec
);
12184 snprintf(failureStr
, sizeof(failureStr
), "Power button pressed during wake transition after %u ms.\n", ((int)((nsec
) / NSEC_PER_MSEC
)));
12187 if (swd_buffer
== NULL
) {
12188 sleepWakeDebugMemAlloc();
12189 if (swd_buffer
== NULL
) {
12193 hdr
= (swd_hdr
*)swd_buffer
;
12194 bufSize
= hdr
->alloc_size
;
12196 dstAddr
= (char*)hdr
+ hdr
->spindump_offset
;
12197 flags
= STACKSHOT_KCDATA_FORMAT
| STACKSHOT_NO_IO_STATS
| STACKSHOT_SAVE_KEXT_LOADINFO
| STACKSHOT_ACTIVE_KERNEL_THREADS_ONLY
| STACKSHOT_THREAD_WAITINFO
;
12198 /* If not wdogTrigger only take kernel tasks stackshot
12206 /* Attempt to take stackshot with all ACTIVE_KERNEL_THREADS
12207 * If we run out of space, take stackshot with only kernel task
12209 while (success
== 0 && cnt
< max_cnt
) {
12210 bytesRemaining
= bufSize
- hdr
->spindump_offset
;
12212 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining
);
12214 size
= bytesRemaining
;
12215 kr
= stack_snapshot_from_kernel(pid
, dstAddr
, size
, flags
, 0, 0, &bytesWritten
);
12216 DLOG("stack_snapshot_from_kernel returned 0x%x. pid: %d bufsize:0x%x flags:0x%llx bytesWritten: %d\n",
12217 kr
, pid
, size
, flags
, bytesWritten
);
12218 if (kr
== KERN_INSUFFICIENT_BUFFER_SIZE
) {
12222 LOG("Insufficient buffer size for only kernel task\n");
12226 if (kr
== KERN_SUCCESS
) {
12227 if (bytesWritten
== 0) {
12228 MSG("Failed to get stackshot(0x%x) bufsize:0x%x flags:0x%llx\n", kr
, size
, flags
);
12231 bytesRemaining
-= bytesWritten
;
12232 hdr
->spindump_size
= (bufSize
- bytesRemaining
- hdr
->spindump_offset
);
12234 memset(hdr
->reason
, 0x20, sizeof(hdr
->reason
));
12236 // Compress stackshot and save to NVRAM
12238 char *outbuf
= (char *)swd_compressed_buffer
;
12240 int num_chunks
= 0;
12241 int max_chunks
= 0;
12243 char nvram_var_name_buffer
[20];
12245 outlen
= swd_compress((char*)hdr
+ hdr
->spindump_offset
, outbuf
, bytesWritten
);
12248 max_chunks
= outlen
/ (2096 - 200);
12249 leftover
= outlen
% (2096 - 200);
12251 if (max_chunks
< 8) {
12252 for (num_chunks
= 0; num_chunks
< max_chunks
; 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))), (2096 - 200)) == FALSE
) {
12255 LOG("Failed to update NVRAM %d\n", num_chunks
);
12260 snprintf(nvram_var_name_buffer
, sizeof(nvram_var_name_buffer
), "%s%02d", SWD_STACKSHOT_VAR_PREFIX
, num_chunks
+ 1);
12261 if (PEWriteNVRAMPropertyWithCopy(nvram_var_name_buffer
, (outbuf
+ (num_chunks
* (2096 - 200))), leftover
) == FALSE
) {
12262 LOG("Failed to update NVRAM with leftovers\n");
12266 LOG("Successfully saved stackshot to NVRAM\n");
12268 LOG("Compressed failure stackshot is too large. size=%d bytes\n", outlen
);
12272 LOG("Compressed failure stackshot of only kernel is too large size=%d bytes\n", outlen
);
12281 if (failureStr
[0]) {
12282 // append sleep-wake failure code
12283 char traceCode
[80];
12284 snprintf(traceCode
, sizeof(traceCode
), "\nFailure code:: 0x%08x %08x\n",
12285 pmTracer
->getTraceData(), pmTracer
->getTracePhase());
12286 strlcat(failureStr
, traceCode
, sizeof(failureStr
));
12287 if (PEWriteNVRAMProperty(kIOSleepWakeFailureString
, failureStr
, (unsigned int) strnlen(failureStr
, sizeof(failureStr
))) == false) {
12288 DLOG("Failed to write SleepWake failure string\n");
12292 // force NVRAM sync
12293 if (PEWriteNVRAMProperty(kIONVRAMSyncNowPropertyKey
, kIONVRAMSyncNowPropertyKey
, (unsigned int) strlen(kIONVRAMSyncNowPropertyKey
)) == false) {
12294 DLOG("Failed to force nvram sync\n");
12299 if (PEGetCoprocessorVersion() < kCoprocessorVersion2
) {
12300 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
12301 // If current boot is due to this watch dog trigger restart in previous boot,
12302 // then don't trigger again until at least 1 successful sleep & wake.
12303 if (!(sleepCnt
&& (displayWakeCnt
|| darkWakeCnt
))) {
12304 LOG("Shutting down due to repeated Sleep/Wake failures\n");
12305 if (!tasksSuspended
) {
12306 tasksSuspended
= TRUE
;
12307 updateTasksSuspend();
12309 PEHaltRestart(kPEHaltCPU
);
12313 if (gSwdPanic
== 0) {
12314 LOG("Calling panic prevented by swd_panic boot-args. Calling restart");
12315 if (!tasksSuspended
) {
12316 tasksSuspended
= TRUE
;
12317 updateTasksSuspend();
12319 PEHaltRestart(kPERestartCPU
);
12322 if (!concise
&& (PEWriteNVRAMProperty(kIOSleepWakeFailurePanic
, swfPanic
, (unsigned int) strlen(swfPanic
)) == false)) {
12323 DLOG("Failed to write SleepWake failure panic key\n");
12325 #if defined(__x86_64__)
12327 panic_with_thread_context(0, NULL
, DEBUGGER_OPTION_ATTEMPTCOREDUMPANDREBOOT
, thread
, "%s", failureStr
);
12329 #endif /* defined(__x86_64__) */
12331 panic_with_options(0, NULL
, DEBUGGER_OPTION_ATTEMPTCOREDUMPANDREBOOT
, "%s", failureStr
);
12334 gRootDomain
->swd_lock
= 0;
12340 IOPMrootDomain::sleepWakeDebugMemAlloc()
12342 vm_size_t size
= SWD_STACKSHOT_SIZE
+ SWD_COMPRESSED_BUFSIZE
+ SWD_ZLIB_BUFSIZE
;
12344 swd_hdr
*hdr
= NULL
;
12345 void *bufPtr
= NULL
;
12347 OSSharedPtr
<IOBufferMemoryDescriptor
> memDesc
;
12350 if (kIOSleepWakeWdogOff
& gIOKitDebug
) {
12354 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
)) {
12358 memDesc
= IOBufferMemoryDescriptor::inTaskWithOptions(
12359 kernel_task
, kIODirectionIn
| kIOMemoryMapperNone
,
12361 if (memDesc
== NULL
) {
12362 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
12366 bufPtr
= memDesc
->getBytesNoCopy();
12368 // Carve out memory for zlib routines
12369 swd_zs_zmem
= (vm_offset_t
)bufPtr
;
12370 bufPtr
= (char *)bufPtr
+ SWD_ZLIB_BUFSIZE
;
12372 // Carve out memory for compressed stackshots
12373 swd_compressed_buffer
= bufPtr
;
12374 bufPtr
= (char *)bufPtr
+ SWD_COMPRESSED_BUFSIZE
;
12376 // Remaining is used for holding stackshot
12377 hdr
= (swd_hdr
*)bufPtr
;
12378 memset(hdr
, 0, sizeof(swd_hdr
));
12380 hdr
->signature
= SWD_HDR_SIGNATURE
;
12381 hdr
->alloc_size
= SWD_STACKSHOT_SIZE
;
12383 hdr
->spindump_offset
= sizeof(swd_hdr
);
12384 swd_buffer
= (void *)hdr
;
12385 swd_memDesc
= os::move(memDesc
);
12386 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr
->alloc_size
, hdr
->spindump_offset
);
12389 gRootDomain
->swd_lock
= 0;
12393 IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc()
12396 vm_size_t size
= SWD_SPINDUMP_SIZE
;
12398 swd_hdr
*hdr
= NULL
;
12400 OSSharedPtr
<IOBufferMemoryDescriptor
> memDesc
;
12402 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
)) {
12406 memDesc
= IOBufferMemoryDescriptor::inTaskWithOptions(
12407 kernel_task
, kIODirectionIn
| kIOMemoryMapperNone
,
12408 SWD_SPINDUMP_SIZE
);
12410 if (memDesc
== NULL
) {
12411 DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
12416 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
12417 memset(hdr
, 0, sizeof(swd_hdr
));
12419 hdr
->signature
= SWD_HDR_SIGNATURE
;
12420 hdr
->alloc_size
= size
;
12422 hdr
->spindump_offset
= sizeof(swd_hdr
);
12423 swd_spindump_buffer
= (void *)hdr
;
12424 swd_spindump_memDesc
= os::move(memDesc
);
12427 gRootDomain
->swd_lock
= 0;
12428 #endif /* UNUSED */
12432 IOPMrootDomain::sleepWakeDebugEnableWdog()
12437 IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
12439 return !systemBooting
&& !systemShutdown
&& !gWillShutdown
;
12443 IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
12445 swd_hdr
*hdr
= NULL
;
12446 errno_t error
= EIO
;
12448 if (swd_spindump_buffer
&& gSpinDumpBufferFull
) {
12449 hdr
= (swd_hdr
*)swd_spindump_buffer
;
12451 error
= sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
12452 (char*)hdr
+ hdr
->spindump_offset
, hdr
->spindump_size
);
12458 sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
12459 (char*)hdr
+ offsetof(swd_hdr
, UUID
),
12460 sizeof(swd_hdr
) - offsetof(swd_hdr
, UUID
));
12462 gSpinDumpBufferFull
= false;
12467 IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)
12469 struct vnode
*vp
= NULL
;
12470 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
12471 kauth_cred_t cred
= vfs_context_ucred(ctx
);
12472 struct vnode_attr va
;
12473 errno_t error
= EIO
;
12475 if (vnode_open(name
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
12476 S_IRUSR
| S_IRGRP
| S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0) {
12477 LOG("Failed to open the file %s\n", name
);
12478 swd_flags
|= SWD_FILEOP_ERROR
;
12482 VATTR_WANTED(&va
, va_nlink
);
12483 /* Don't dump to non-regular files or files with links. */
12484 if (vp
->v_type
!= VREG
||
12485 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
12486 LOG("Bailing as this is not a regular file\n");
12487 swd_flags
|= SWD_FILEOP_ERROR
;
12491 VATTR_SET(&va
, va_data_size
, 0);
12492 vnode_setattr(vp
, &va
, ctx
);
12496 error
= vn_rdwr(UIO_WRITE
, vp
, buf
, len
, 0,
12497 UIO_SYSSPACE
, IO_NODELOCKED
| IO_UNIT
, cred
, (int *) NULL
, vfs_context_proc(ctx
));
12499 LOG("Failed to save sleep wake log. err 0x%x\n", error
);
12500 swd_flags
|= SWD_FILEOP_ERROR
;
12502 DLOG("Saved %d bytes to file %s\n", len
, name
);
12508 vnode_close(vp
, FWRITE
, ctx
);
12511 vfs_context_rele(ctx
);
12517 #else /* defined(__i386__) || defined(__x86_64__) */
12520 IOPMrootDomain::sleepWakeDebugTrig(bool restart
)
12523 if (gSwdPanic
== 0) {
12526 panic("Sleep/Wake hang detected");
12532 IOPMrootDomain::takeStackshot(bool restart
)
12534 #pragma unused(restart)
12538 IOPMrootDomain::deleteStackshot()
12543 IOPMrootDomain::sleepWakeDebugMemAlloc()
12548 IOPMrootDomain::saveFailureData2File()
12553 IOPMrootDomain::sleepWakeDebugEnableWdog()
12558 IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
12564 IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
12569 IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)
12574 #endif /* defined(__i386__) || defined(__x86_64__) */