2 * Copyright (c) 1998-2020 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #define IOKIT_ENABLE_SHARED_PTR
31 #include <libkern/c++/OSKext.h>
32 #include <libkern/c++/OSMetaClass.h>
33 #include <libkern/OSAtomic.h>
34 #include <libkern/OSDebug.h>
35 #include <IOKit/IOWorkLoop.h>
36 #include <IOKit/IOCommandGate.h>
37 #include <IOKit/IOTimerEventSource.h>
38 #include <IOKit/IOPlatformExpert.h>
39 #include <IOKit/IOCPU.h>
40 #include <IOKit/IOPlatformActions.h>
41 #include <IOKit/IOKitDebug.h>
42 #include <IOKit/IOTimeStamp.h>
43 #include <IOKit/pwr_mgt/IOPMlog.h>
44 #include <IOKit/pwr_mgt/RootDomain.h>
45 #include <IOKit/pwr_mgt/IOPMPrivate.h>
46 #include <IOKit/IODeviceTreeSupport.h>
47 #include <IOKit/IOMessage.h>
48 #include <IOKit/IOReturn.h>
49 #include <IOKit/IONVRAM.h>
50 #include "RootDomainUserClient.h"
51 #include "IOKit/pwr_mgt/IOPowerConnection.h"
52 #include "IOPMPowerStateQueue.h"
53 #include <IOKit/IOCatalogue.h>
54 #include <IOKit/IOReportMacros.h>
55 #include <IOKit/IOLib.h>
56 #include <IOKit/IOKitKeys.h>
57 #include "IOKitKernelInternal.h"
59 #include <IOKit/IOHibernatePrivate.h>
60 #endif /* HIBERNATION */
61 #include <console/video_console.h>
62 #include <sys/syslog.h>
63 #include <sys/sysctl.h>
64 #include <sys/vnode.h>
65 #include <sys/vnode_internal.h>
66 #include <sys/fcntl.h>
68 #include <pexpert/protos.h>
69 #include <AssertMacros.h>
72 #include "IOServicePrivate.h" // _IOServiceInterestNotifier
73 #include "IOServicePMPrivate.h"
75 #include <libkern/zlib.h>
76 #include <os/cpp_util.h>
77 #include <libkern/c++/OSBoundedArrayRef.h>
80 #include <mach/shared_region.h>
81 #include <kern/clock.h>
84 #if defined(__i386__) || defined(__x86_64__)
86 #include "IOPMrootDomainInternal.h"
87 const char *processor_to_datastring(const char *prefix
, processor_t target_processor
);
91 #define kIOPMrootDomainClass "IOPMrootDomain"
92 #define LOG_PREFIX "PMRD: "
96 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
99 do { kprintf(LOG_PREFIX x); } while (false)
101 #if DEVELOPMENT || DEBUG
102 #define DEBUG_LOG(x...) do { \
103 if (kIOLogPMRootDomain & gIOKitDebug) \
104 kprintf(LOG_PREFIX x); \
105 os_log_debug(OS_LOG_DEFAULT, LOG_PREFIX x); \
108 #define DEBUG_LOG(x...)
111 #define DLOG(x...) do { \
112 if (kIOLogPMRootDomain & gIOKitDebug) \
113 kprintf(LOG_PREFIX x); \
115 os_log(OS_LOG_DEFAULT, LOG_PREFIX x); \
118 #define DMSG(x...) do { \
119 if (kIOLogPMRootDomain & gIOKitDebug) { \
120 kprintf(LOG_PREFIX x); \
127 #define CHECK_THREAD_CONTEXT
128 #ifdef CHECK_THREAD_CONTEXT
129 static IOWorkLoop
* gIOPMWorkLoop
= NULL
;
130 #define ASSERT_GATED() \
132 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
133 panic("RootDomain: not inside PM gate"); \
137 #define ASSERT_GATED()
138 #endif /* CHECK_THREAD_CONTEXT */
140 #define CAP_LOSS(c) \
141 (((_pendingCapability & (c)) == 0) && \
142 ((_currentCapability & (c)) != 0))
144 #define CAP_GAIN(c) \
145 (((_currentCapability & (c)) == 0) && \
146 ((_pendingCapability & (c)) != 0))
148 #define CAP_CHANGE(c) \
149 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
151 #define CAP_CURRENT(c) \
152 ((_currentCapability & (c)) != 0)
154 #define CAP_HIGHEST(c) \
155 ((_highestCapability & (c)) != 0)
157 #define CAP_PENDING(c) \
158 ((_pendingCapability & (c)) != 0)
160 // rdar://problem/9157444
161 #if defined(__i386__) || defined(__x86_64__)
162 #define DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY 20
165 // Event types for IOPMPowerStateQueue::submitPowerEvent()
167 kPowerEventFeatureChanged
= 1, // 1
168 kPowerEventReceivedPowerNotification
, // 2
169 kPowerEventSystemBootCompleted
, // 3
170 kPowerEventSystemShutdown
, // 4
171 kPowerEventUserDisabledSleep
, // 5
172 kPowerEventRegisterSystemCapabilityClient
, // 6
173 kPowerEventRegisterKernelCapabilityClient
, // 7
174 kPowerEventPolicyStimulus
, // 8
175 kPowerEventAssertionCreate
, // 9
176 kPowerEventAssertionRelease
, // 10
177 kPowerEventAssertionSetLevel
, // 11
178 kPowerEventQueueSleepWakeUUID
, // 12
179 kPowerEventPublishSleepWakeUUID
, // 13
180 kPowerEventSetDisplayPowerOn
, // 14
181 kPowerEventPublishWakeType
, // 15
182 kPowerEventAOTEvaluate
// 16
185 // For evaluatePolicy()
186 // List of stimuli that affects the root domain policy.
188 kStimulusDisplayWranglerSleep
, // 0
189 kStimulusDisplayWranglerWake
, // 1
190 kStimulusAggressivenessChanged
, // 2
191 kStimulusDemandSystemSleep
, // 3
192 kStimulusAllowSystemSleepChanged
, // 4
193 kStimulusDarkWakeActivityTickle
, // 5
194 kStimulusDarkWakeEntry
, // 6
195 kStimulusDarkWakeReentry
, // 7
196 kStimulusDarkWakeEvaluate
, // 8
197 kStimulusNoIdleSleepPreventers
, // 9
198 kStimulusEnterUserActiveState
, // 10
199 kStimulusLeaveUserActiveState
// 11
202 // Internal power state change reasons
203 // Must be less than kIOPMSleepReasonClamshell=101
205 kCPSReasonNone
= 0, // 0
208 kCPSReasonIdleSleepPrevent
, // 3
209 kCPSReasonIdleSleepAllow
, // 4
210 kCPSReasonPowerOverride
, // 5
211 kCPSReasonPowerDownCancel
, // 6
212 kCPSReasonAOTExit
, // 7
213 kCPSReasonAdjustPowerState
, // 8
214 kCPSReasonDarkWakeCannotSleep
, // 9
215 kCPSReasonIdleSleepEnabled
, // 10
216 kCPSReasonEvaluatePolicy
, // 11
217 kCPSReasonSustainFullWake
, // 12
218 kCPSReasonPMInternals
= (kIOPMSleepReasonClamshell
- 1)
222 IOReturn
OSKextSystemSleepOrWake( UInt32
);
224 extern "C" ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
);
225 extern "C" addr64_t
kvtophys(vm_offset_t va
);
226 extern "C" boolean_t
kdp_has_polled_corefile();
228 static void idleSleepTimerExpired( thread_call_param_t
, thread_call_param_t
);
229 static void notifySystemShutdown( IOService
* root
, uint32_t messageType
);
230 static void handleAggressivesFunction( thread_call_param_t
, thread_call_param_t
);
231 static void pmEventTimeStamp(uint64_t *recordTS
);
232 static void powerButtonUpCallout( thread_call_param_t
, thread_call_param_t
);
233 static void powerButtonDownCallout( thread_call_param_t
, thread_call_param_t
);
234 static OSPtr
<const OSSymbol
> copyKextIdentifierWithAddress(vm_address_t address
);
236 static int IOPMConvertSecondsToCalendar(clock_sec_t secs
, IOPMCalendarStruct
* dt
);
237 static clock_sec_t
IOPMConvertCalendarToSeconds(const IOPMCalendarStruct
* dt
);
238 #define YMDTF "%04d/%02d/%d %02d:%02d:%02d"
239 #define YMDT(cal) ((int)(cal)->year), (cal)->month, (cal)->day, (cal)->hour, (cal)->minute, (cal)->second
241 // "IOPMSetSleepSupported" callPlatformFunction name
242 static OSSharedPtr
<const OSSymbol
> sleepSupportedPEFunction
;
243 static OSSharedPtr
<const OSSymbol
> sleepMessagePEFunction
;
244 static OSSharedPtr
<const OSSymbol
> gIOPMWakeTypeUserKey
;
246 static OSSharedPtr
<const OSSymbol
> gIOPMPSExternalConnectedKey
;
247 static OSSharedPtr
<const OSSymbol
> gIOPMPSExternalChargeCapableKey
;
248 static OSSharedPtr
<const OSSymbol
> gIOPMPSBatteryInstalledKey
;
249 static OSSharedPtr
<const OSSymbol
> gIOPMPSIsChargingKey
;
250 static OSSharedPtr
<const OSSymbol
> gIOPMPSAtWarnLevelKey
;
251 static OSSharedPtr
<const OSSymbol
> gIOPMPSAtCriticalLevelKey
;
252 static OSSharedPtr
<const OSSymbol
> gIOPMPSCurrentCapacityKey
;
253 static OSSharedPtr
<const OSSymbol
> gIOPMPSMaxCapacityKey
;
254 static OSSharedPtr
<const OSSymbol
> gIOPMPSDesignCapacityKey
;
255 static OSSharedPtr
<const OSSymbol
> gIOPMPSTimeRemainingKey
;
256 static OSSharedPtr
<const OSSymbol
> gIOPMPSAmperageKey
;
257 static OSSharedPtr
<const OSSymbol
> gIOPMPSVoltageKey
;
258 static OSSharedPtr
<const OSSymbol
> gIOPMPSCycleCountKey
;
259 static OSSharedPtr
<const OSSymbol
> gIOPMPSMaxErrKey
;
260 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterInfoKey
;
261 static OSSharedPtr
<const OSSymbol
> gIOPMPSLocationKey
;
262 static OSSharedPtr
<const OSSymbol
> gIOPMPSErrorConditionKey
;
263 static OSSharedPtr
<const OSSymbol
> gIOPMPSManufacturerKey
;
264 static OSSharedPtr
<const OSSymbol
> gIOPMPSManufactureDateKey
;
265 static OSSharedPtr
<const OSSymbol
> gIOPMPSModelKey
;
266 static OSSharedPtr
<const OSSymbol
> gIOPMPSSerialKey
;
267 static OSSharedPtr
<const OSSymbol
> gIOPMPSLegacyBatteryInfoKey
;
268 static OSSharedPtr
<const OSSymbol
> gIOPMPSBatteryHealthKey
;
269 static OSSharedPtr
<const OSSymbol
> gIOPMPSHealthConfidenceKey
;
270 static OSSharedPtr
<const OSSymbol
> gIOPMPSCapacityEstimatedKey
;
271 static OSSharedPtr
<const OSSymbol
> gIOPMPSBatteryChargeStatusKey
;
272 static OSSharedPtr
<const OSSymbol
> gIOPMPSBatteryTemperatureKey
;
273 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsKey
;
274 static OSSharedPtr
<const OSSymbol
> gIOPMPSChargerConfigurationKey
;
275 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsIDKey
;
276 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsWattsKey
;
277 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsRevisionKey
;
278 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsSerialNumberKey
;
279 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsFamilyKey
;
280 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsAmperageKey
;
281 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsDescriptionKey
;
282 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsPMUConfigurationKey
;
283 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsSourceIDKey
;
284 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsErrorFlagsKey
;
285 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsSharedSourceKey
;
286 static OSSharedPtr
<const OSSymbol
> gIOPMPSAdapterDetailsCloakedKey
;
287 static OSSharedPtr
<const OSSymbol
> gIOPMPSInvalidWakeSecondsKey
;
288 static OSSharedPtr
<const OSSymbol
> gIOPMPSPostChargeWaitSecondsKey
;
289 static OSSharedPtr
<const OSSymbol
> gIOPMPSPostDishargeWaitSecondsKey
;
291 #define kIOSleepSupportedKey "IOSleepSupported"
292 #define kIOPMSystemCapabilitiesKey "System Capabilities"
293 #define kIOPMSystemDefaultOverrideKey "SystemPowerProfileOverrideDict"
295 #define kIORequestWranglerIdleKey "IORequestIdle"
296 #define kDefaultWranglerIdlePeriod 1000 // in milliseconds
298 #define kIOSleepWakeFailureString "SleepWakeFailureString"
299 #define kIOEFIBootRomFailureKey "wake-failure"
300 #define kIOSleepWakeFailurePanic "SleepWakeFailurePanic"
302 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
303 | kIOPMSupportedOnBatt \
304 | kIOPMSupportedOnUPS)
306 #define kLocalEvalClamshellCommand (1 << 15)
307 #define kIdleSleepRetryInterval (3 * 60)
309 #define DISPLAY_WRANGLER_PRESENT (!NO_KERNEL_HID)
312 kWranglerPowerStateMin
= 0,
313 kWranglerPowerStateSleep
= 2,
314 kWranglerPowerStateDim
= 3,
315 kWranglerPowerStateMax
= 4
328 getPowerStateString( uint32_t state
)
330 #define POWER_STATE(x) {(uint32_t) x, #x}
332 static const IONamedValue powerStates
[] = {
333 POWER_STATE( OFF_STATE
),
334 POWER_STATE( RESTART_STATE
),
335 POWER_STATE( SLEEP_STATE
),
336 POWER_STATE( AOT_STATE
),
337 POWER_STATE( ON_STATE
),
340 return IOFindNameForValue(state
, powerStates
);
343 #define ON_POWER kIOPMPowerOn
344 #define RESTART_POWER kIOPMRestart
345 #define SLEEP_POWER kIOPMAuxPowerOn
347 static IOPMPowerState
348 ourPowerStates
[NUM_POWER_STATES
] =
351 .capabilityFlags
= 0,
352 .outputPowerCharacter
= 0,
353 .inputPowerRequirement
= 0 },
355 .capabilityFlags
= kIOPMRestartCapability
,
356 .outputPowerCharacter
= kIOPMRestart
,
357 .inputPowerRequirement
= RESTART_POWER
},
359 .capabilityFlags
= kIOPMSleepCapability
,
360 .outputPowerCharacter
= kIOPMSleep
,
361 .inputPowerRequirement
= SLEEP_POWER
},
363 .capabilityFlags
= kIOPMAOTCapability
,
364 .outputPowerCharacter
= kIOPMAOTPower
,
365 .inputPowerRequirement
= ON_POWER
},
367 .capabilityFlags
= kIOPMPowerOn
,
368 .outputPowerCharacter
= kIOPMPowerOn
,
369 .inputPowerRequirement
= ON_POWER
},
372 #define kIOPMRootDomainWakeTypeSleepService "SleepService"
373 #define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
374 #define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
375 #define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
376 #define kIOPMRootDomainWakeTypeUser "User"
377 #define kIOPMRootDomainWakeTypeAlarm "Alarm"
378 #define kIOPMRootDomainWakeTypeNetwork "Network"
379 #define kIOPMRootDomainWakeTypeHIDActivity "HID Activity"
380 #define kIOPMRootDomainWakeTypeNotification "Notification"
381 #define kIOPMRootDomainWakeTypeHibernateError "HibernateError"
383 // Special interest that entitles the interested client from receiving
384 // all system messages. Only used by powerd.
386 #define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
388 // Entitlement required for root domain clients
389 #define kRootDomainEntitlementSetProperty "com.apple.private.iokit.rootdomain-set-property"
391 #define WAKEEVENT_LOCK() IOLockLock(wakeEventLock)
392 #define WAKEEVENT_UNLOCK() IOLockUnlock(wakeEventLock)
397 #define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
398 #define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
400 #define kAggressivesMinValue 1
403 getAggressivenessTypeString( uint32_t type
)
405 #define AGGRESSIVENESS_TYPE(x) {(uint32_t) x, #x}
407 static const IONamedValue aggressivenessTypes
[] = {
408 AGGRESSIVENESS_TYPE( kPMGeneralAggressiveness
),
409 AGGRESSIVENESS_TYPE( kPMMinutesToDim
),
410 AGGRESSIVENESS_TYPE( kPMMinutesToSpinDown
),
411 AGGRESSIVENESS_TYPE( kPMMinutesToSleep
),
412 AGGRESSIVENESS_TYPE( kPMEthernetWakeOnLANSettings
),
413 AGGRESSIVENESS_TYPE( kPMSetProcessorSpeed
),
414 AGGRESSIVENESS_TYPE( kPMPowerSource
),
415 AGGRESSIVENESS_TYPE( kPMMotionSensor
),
416 AGGRESSIVENESS_TYPE( kPMLastAggressivenessType
),
419 return IOFindNameForValue(type
, aggressivenessTypes
);
423 kAggressivesStateBusy
= 0x01,
424 kAggressivesStateQuickSpindown
= 0x02
427 struct AggressivesRecord
{
433 struct AggressivesRequest
{
438 OSSharedPtr
<IOService
> service
;
439 AggressivesRecord record
;
444 kAggressivesRequestTypeService
= 1,
445 kAggressivesRequestTypeRecord
449 kAggressivesOptionSynchronous
= 0x00000001,
450 kAggressivesOptionQuickSpindownEnable
= 0x00000100,
451 kAggressivesOptionQuickSpindownDisable
= 0x00000200,
452 kAggressivesOptionQuickSpindownMask
= 0x00000300
456 kAggressivesRecordFlagModified
= 0x00000001,
457 kAggressivesRecordFlagMinValue
= 0x00000002
460 // System Sleep Preventers
463 kPMUserDisabledAllSleep
= 1,
464 kPMSystemRestartBootingInProgress
,
465 kPMConfigPreventSystemSleep
,
466 kPMChildPreventSystemSleep
,
472 getSystemSleepPreventerString( uint32_t preventer
)
474 #define SYSTEM_SLEEP_PREVENTER(x) {(int) x, #x}
475 static const IONamedValue systemSleepPreventers
[] = {
476 SYSTEM_SLEEP_PREVENTER( kPMUserDisabledAllSleep
),
477 SYSTEM_SLEEP_PREVENTER( kPMSystemRestartBootingInProgress
),
478 SYSTEM_SLEEP_PREVENTER( kPMConfigPreventSystemSleep
),
479 SYSTEM_SLEEP_PREVENTER( kPMChildPreventSystemSleep
),
480 SYSTEM_SLEEP_PREVENTER( kPMCPUAssertion
),
481 SYSTEM_SLEEP_PREVENTER( kPMPCIUnsupported
),
484 return IOFindNameForValue(preventer
, systemSleepPreventers
);
489 kDarkWakeFlagPromotionNone
= 0x0000,
490 kDarkWakeFlagPromotionEarly
= 0x0001, // promote before gfx clamp
491 kDarkWakeFlagPromotionLate
= 0x0002, // promote after gfx clamp
492 kDarkWakeFlagPromotionMask
= 0x0003,
493 kDarkWakeFlagAlarmIsDark
= 0x0100,
494 kDarkWakeFlagAudioNotSuppressed
= 0x0200,
495 kDarkWakeFlagUserWakeWorkaround
= 0x1000
499 // The workaround for 9157444 is enabled at compile time using the
500 // DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY macro and is not represented below.
502 kClamshell_WAR_38378787
= 0x00000001,
503 kClamshell_WAR_47715679
= 0x00000002,
504 kClamshell_WAR_58009435
= 0x00000004
507 // acceptSystemWakeEvents()
509 kAcceptSystemWakeEvents_Disable
= 0,
510 kAcceptSystemWakeEvents_Enable
,
511 kAcceptSystemWakeEvents_Reenable
514 static IOPMrootDomain
* gRootDomain
;
515 static IORootParent
* gPatriarch
;
516 static IONotifier
* gSysPowerDownNotifier
= NULL
;
517 static UInt32 gSleepOrShutdownPending
= 0;
518 static UInt32 gWillShutdown
= 0;
519 static UInt32 gPagingOff
= 0;
520 static UInt32 gSleepWakeUUIDIsSet
= false;
521 static uint32_t gAggressivesState
= 0;
522 static uint32_t gHaltTimeMaxLog
;
523 static uint32_t gHaltTimeMaxPanic
;
524 IOLock
* gHaltLogLock
;
525 static char * gHaltLog
;
526 enum { kHaltLogSize
= 2048 };
527 static size_t gHaltLogPos
;
528 static uint64_t gHaltStartTime
;
529 static char gKextNameBuf
[64];
530 static size_t gKextNamePos
;
531 static bool gKextNameEnd
;
533 uuid_string_t bootsessionuuid_string
;
535 #if defined(XNU_TARGET_OS_OSX)
536 #if DISPLAY_WRANGLER_PRESENT
537 static uint32_t gDarkWakeFlags
= kDarkWakeFlagPromotionNone
;
539 // Enable temporary full wake promotion workarounds
540 static uint32_t gDarkWakeFlags
= kDarkWakeFlagUserWakeWorkaround
;
542 // Enable full wake promotion workarounds
543 static uint32_t gDarkWakeFlags
= kDarkWakeFlagUserWakeWorkaround
;
545 #else /* !defined(XNU_TARGET_OS_OSX) */
546 static uint32_t gDarkWakeFlags
= kDarkWakeFlagPromotionEarly
;
547 #endif /* !defined(XNU_TARGET_OS_OSX) */
549 static uint32_t gNoIdleFlag
= 0;
550 static uint32_t gSwdPanic
= 1;
551 static uint32_t gSwdSleepTimeout
= 0;
552 static uint32_t gSwdWakeTimeout
= 0;
553 static uint32_t gSwdSleepWakeTimeout
= 0;
554 static PMStatsStruct gPMStats
;
555 #if DEVELOPMENT || DEBUG
556 static uint32_t swd_panic_phase
;
559 static uint32_t gClamshellFlags
= 0
560 #if defined(__i386__) || defined(__x86_64__)
561 | kClamshell_WAR_58009435
567 #if defined(__arm64__)
569 defaultSleepPolicyHandler(void *ctx
, const IOPMSystemSleepPolicyVariables
*vars
, IOPMSystemSleepParameters
*params
)
571 uint32_t sleepType
= kIOPMSleepTypeDeepIdle
;
573 assert(vars
->signature
== kIOPMSystemSleepPolicySignature
);
574 assert(vars
->version
== kIOPMSystemSleepPolicyVersion
);
576 // Hibernation enabled and either user forced hibernate or low battery sleep
577 if ((vars
->hibernateMode
& kIOHibernateModeOn
) &&
578 (((vars
->hibernateMode
& kIOHibernateModeSleep
) == 0) ||
579 (vars
->sleepFactors
& kIOPMSleepFactorBatteryLow
))) {
580 sleepType
= kIOPMSleepTypeHibernate
;
582 params
->version
= kIOPMSystemSleepParametersVersion
;
583 params
->sleepType
= sleepType
;
584 return kIOReturnSuccess
;
586 static IOPMSystemSleepPolicyHandler gSleepPolicyHandler
= &defaultSleepPolicyHandler
;
587 #else /* defined(__arm64__) */
588 static IOPMSystemSleepPolicyHandler gSleepPolicyHandler
= NULL
;
589 #endif /* defined(__arm64__) */
591 static IOPMSystemSleepPolicyVariables
* gSleepPolicyVars
= NULL
;
592 static void * gSleepPolicyTarget
;
595 struct timeval gIOLastSleepTime
;
596 struct timeval gIOLastWakeTime
;
597 AbsoluteTime gIOLastWakeAbsTime
;
598 AbsoluteTime gIOLastSleepAbsTime
;
600 struct timeval gIOLastUserSleepTime
;
602 static char gWakeReasonString
[128];
603 static char gBootReasonString
[80];
604 static char gShutdownReasonString
[80];
605 static bool gWakeReasonSysctlRegistered
= false;
606 static bool gBootReasonSysctlRegistered
= false;
607 static bool gShutdownReasonSysctlRegistered
= false;
608 static AbsoluteTime gUserActiveAbsTime
;
609 static AbsoluteTime gUserInactiveAbsTime
;
611 #if defined(__i386__) || defined(__x86_64__) || (defined(__arm64__) && HIBERNATION)
612 static bool gSpinDumpBufferFull
= false;
616 vm_offset_t swd_zs_zmem
;
617 //size_t swd_zs_zsize;
618 size_t swd_zs_zoffset
;
619 #if defined(__i386__) || defined(__x86_64__)
620 IOCPU
*currentShutdownTarget
= NULL
;
623 static unsigned int gPMHaltBusyCount
;
624 static unsigned int gPMHaltIdleCount
;
625 static int gPMHaltDepth
;
626 static uint32_t gPMHaltMessageType
;
627 static IOLock
* gPMHaltLock
= NULL
;
628 static OSSharedPtr
<OSArray
> gPMHaltArray
;
629 static OSSharedPtr
<const OSSymbol
> gPMHaltClientAcknowledgeKey
;
630 static bool gPMQuiesced
;
632 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
633 #define kCPUUnknownIndex 9999999
640 OSSharedPtr
<const OSSymbol
> gIOPMStatsResponseTimedOut
;
641 OSSharedPtr
<const OSSymbol
> gIOPMStatsResponseCancel
;
642 OSSharedPtr
<const OSSymbol
> gIOPMStatsResponseSlow
;
643 OSSharedPtr
<const OSSymbol
> gIOPMStatsResponsePrompt
;
644 OSSharedPtr
<const OSSymbol
> gIOPMStatsDriverPSChangeSlow
;
646 #define kBadPMFeatureID 0
650 * Opaque handle passed to clients of registerPMSettingController()
652 class PMSettingHandle
: public OSObject
654 OSDeclareFinalStructors( PMSettingHandle
);
655 friend class PMSettingObject
;
658 PMSettingObject
*pmso
;
659 void free(void) APPLE_KEXT_OVERRIDE
;
664 * Internal object to track each PM setting controller
666 class PMSettingObject
: public OSObject
668 OSDeclareFinalStructors( PMSettingObject
);
669 friend class IOPMrootDomain
;
672 queue_head_t calloutQueue
;
674 IOPMrootDomain
*parent
;
675 PMSettingHandle
*pmsh
;
676 IOPMSettingControllerCallback func
;
679 uint32_t *publishedFeatureID
;
680 uint32_t settingCount
;
683 void free(void) APPLE_KEXT_OVERRIDE
;
686 static PMSettingObject
*pmSettingObject(
687 IOPMrootDomain
*parent_arg
,
688 IOPMSettingControllerCallback handler_arg
,
689 OSObject
*target_arg
,
690 uintptr_t refcon_arg
,
691 uint32_t supportedPowerSources
,
692 const OSSymbol
*settings
[],
693 OSObject
**handle_obj
);
695 IOReturn
dispatchPMSetting(const OSSymbol
*type
, OSObject
*object
);
696 void clientHandleFreed(void);
699 struct PMSettingCallEntry
{
704 #define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
705 #define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
706 #define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
707 #define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
711 * Internal helper object for logging trace points to RTC
712 * IOPMrootDomain and only IOPMrootDomain should instantiate
713 * exactly one of these.
716 typedef void (*IOPMTracePointHandler
)(
717 void * target
, uint32_t code
, uint32_t data
);
719 class PMTraceWorker
: public OSObject
721 OSDeclareDefaultStructors(PMTraceWorker
);
723 typedef enum { kPowerChangeStart
, kPowerChangeCompleted
} change_t
;
725 static OSPtr
<PMTraceWorker
> tracer( IOPMrootDomain
* );
726 void tracePCIPowerChange(change_t
, IOService
*, uint32_t, uint32_t);
727 void tracePoint(uint8_t phase
);
728 void traceDetail(uint32_t detail
);
729 void traceComponentWakeProgress(uint32_t component
, uint32_t data
);
730 int recordTopLevelPCIDevice(IOService
*);
731 void RTC_TRACE(void);
732 virtual bool serialize(OSSerialize
*s
) const APPLE_KEXT_OVERRIDE
;
734 IOPMTracePointHandler tracePointHandler
;
735 void * tracePointTarget
;
736 uint64_t getPMStatusCode();
737 uint8_t getTracePhase();
738 uint32_t getTraceData();
740 IOPMrootDomain
*owner
;
741 IOLock
*pmTraceWorkerLock
;
742 OSSharedPtr
<OSArray
> pciDeviceBitMappings
;
744 uint8_t addedToRegistry
;
746 uint32_t traceData32
;
747 uint8_t loginWindowData
;
748 uint8_t coreDisplayData
;
749 uint8_t coreGraphicsData
;
753 * PMAssertionsTracker
754 * Tracks kernel and user space PM assertions
756 class PMAssertionsTracker
: public OSObject
758 OSDeclareFinalStructors(PMAssertionsTracker
);
760 static PMAssertionsTracker
*pmAssertionsTracker( IOPMrootDomain
* );
762 IOReturn
createAssertion(IOPMDriverAssertionType
, IOPMDriverAssertionLevel
, IOService
*, const char *, IOPMDriverAssertionID
*);
763 IOReturn
releaseAssertion(IOPMDriverAssertionID
);
764 IOReturn
setAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
765 IOReturn
setUserAssertionLevels(IOPMDriverAssertionType
);
767 OSSharedPtr
<OSArray
> copyAssertionsArray(void);
768 IOPMDriverAssertionType
getActivatedAssertions(void);
769 IOPMDriverAssertionLevel
getAssertionLevel(IOPMDriverAssertionType
);
771 IOReturn
handleCreateAssertion(OSData
*);
772 IOReturn
handleReleaseAssertion(IOPMDriverAssertionID
);
773 IOReturn
handleSetAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
774 IOReturn
handleSetUserAssertionLevels(void * arg0
);
775 void publishProperties(void);
776 void reportCPUBitAccounting(void);
780 * this should be treated as POD, as it's byte-copied around
781 * and we cannot rely on d'tor firing at the right time
784 IOPMDriverAssertionID id
;
785 IOPMDriverAssertionType assertionBits
;
786 uint64_t createdTime
;
787 uint64_t modifiedTime
;
788 const OSSymbol
*ownerString
;
789 IOService
*ownerService
;
790 uint64_t registryEntryID
;
791 IOPMDriverAssertionLevel level
;
792 uint64_t assertCPUStartTime
;
793 uint64_t assertCPUDuration
;
796 uint32_t tabulateProducerCount
;
797 uint32_t tabulateConsumerCount
;
799 uint64_t maxAssertCPUDuration
;
800 uint64_t maxAssertCPUEntryId
;
802 PMAssertStruct
*detailsForID(IOPMDriverAssertionID
, int *);
804 void updateCPUBitAccounting(PMAssertStruct
* assertStruct
);
806 IOPMrootDomain
*owner
;
807 OSSharedPtr
<OSArray
> assertionsArray
;
808 IOLock
*assertionsArrayLock
;
809 IOPMDriverAssertionID issuingUniqueID
__attribute__((aligned(8)));/* aligned for atomic access */
810 IOPMDriverAssertionType assertionsKernel
;
811 IOPMDriverAssertionType assertionsUser
;
812 IOPMDriverAssertionType assertionsCombined
;
815 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker
, OSObject
);
819 * Internal helper object for Shutdown/Restart notifications.
821 #define kPMHaltMaxWorkers 8
822 #define kPMHaltTimeoutMS 100
824 class PMHaltWorker
: public OSObject
826 OSDeclareFinalStructors( PMHaltWorker
);
829 IOService
* service
;// service being worked on
830 AbsoluteTime startTime
; // time when work started
831 int depth
; // work on nubs at this PM-tree depth
832 int visits
; // number of nodes visited (debug)
834 bool timeout
;// service took too long
836 static PMHaltWorker
* worker( void );
837 static void main( void * arg
, wait_result_t waitResult
);
838 static void work( PMHaltWorker
* me
);
839 static void checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
);
840 virtual void free( void ) APPLE_KEXT_OVERRIDE
;
843 OSDefineMetaClassAndFinalStructors( PMHaltWorker
, OSObject
)
846 #define super IOService
847 OSDefineMetaClassAndFinalStructors(IOPMrootDomain
, IOService
)
850 IOPMRootDomainGetWillShutdown(void)
852 return gWillShutdown
!= 0;
856 IOPMRootDomainWillShutdown(void)
858 if (OSCompareAndSwap(0, 1, &gWillShutdown
)) {
859 IOService::willShutdown();
860 for (int i
= 0; i
< 100; i
++) {
861 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending
)) {
869 extern "C" IONotifier
*
870 registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
872 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
).detach();
875 extern "C" IONotifier
*
876 registerPrioritySleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
878 return gRootDomain
->registerInterest( gIOPriorityPowerStateInterest
, handler
, self
, ref
).detach();
882 acknowledgeSleepWakeNotification(void * PMrefcon
)
884 return gRootDomain
->allowPowerChange((unsigned long)PMrefcon
);
888 vetoSleepWakeNotification(void * PMrefcon
)
890 return gRootDomain
->cancelPowerChange((unsigned long)PMrefcon
);
894 rootDomainRestart( void )
896 return gRootDomain
->restartSystem();
900 rootDomainShutdown( void )
902 return gRootDomain
->shutdownSystem();
906 halt_log_putc(char c
)
908 if (gHaltLogPos
>= (kHaltLogSize
- 2)) {
911 gHaltLog
[gHaltLogPos
++] = c
;
915 _doprnt_log(const char *fmt
,
921 halt_log(const char *fmt
, ...)
925 va_start(listp
, fmt
);
926 _doprnt_log(fmt
, &listp
, &halt_log_putc
, 16);
933 halt_log_enter(const char * what
, const void * pc
, uint64_t time
)
935 uint64_t nano
, millis
;
940 absolutetime_to_nanoseconds(time
, &nano
);
941 millis
= nano
/ NSEC_PER_MSEC
;
946 IOLockLock(gHaltLogLock
);
948 halt_log("%s: %qd ms @ 0x%lx, ", what
, millis
, VM_KERNEL_UNSLIDE(pc
));
949 OSKext::printKextsInBacktrace((vm_offset_t
*) &pc
, 1, &halt_log
,
950 OSKext::kPrintKextsLock
| OSKext::kPrintKextsUnslide
| OSKext::kPrintKextsTerse
);
952 halt_log("%s: %qd ms\n", what
, millis
);
955 gHaltLog
[gHaltLogPos
] = 0;
956 IOLockUnlock(gHaltLogLock
);
959 extern uint32_t gFSState
;
962 IOSystemShutdownNotification(int stage
)
966 if (kIOSystemShutdownNotificationStageRootUnmount
== stage
) {
967 #if defined(XNU_TARGET_OS_OSX)
968 uint64_t nano
, millis
;
969 startTime
= mach_absolute_time();
970 IOService::getPlatform()->waitQuiet(30 * NSEC_PER_SEC
);
971 absolutetime_to_nanoseconds(mach_absolute_time() - startTime
, &nano
);
972 millis
= nano
/ NSEC_PER_MSEC
;
973 if (gHaltTimeMaxLog
&& (millis
>= gHaltTimeMaxLog
)) {
974 printf("waitQuiet() for unmount %qd ms\n", millis
);
976 #endif /* defined(XNU_TARGET_OS_OSX) */
980 assert(kIOSystemShutdownNotificationStageProcessExit
== stage
);
982 IOLockLock(gHaltLogLock
);
984 gHaltLog
= IONew(char, kHaltLogSize
);
985 gHaltStartTime
= mach_absolute_time();
990 IOLockUnlock(gHaltLogLock
);
992 startTime
= mach_absolute_time();
993 IOPMRootDomainWillShutdown();
994 halt_log_enter("IOPMRootDomainWillShutdown", NULL
, mach_absolute_time() - startTime
);
996 startTime
= mach_absolute_time();
997 IOHibernateSystemPostWake(true);
998 halt_log_enter("IOHibernateSystemPostWake", NULL
, mach_absolute_time() - startTime
);
1000 if (OSCompareAndSwap(0, 1, &gPagingOff
)) {
1001 gRootDomain
->handlePlatformHaltRestart(kPEPagingOff
);
1006 extern "C" int sync_internal(void);
1009 * A device is always in the highest power state which satisfies its driver,
1010 * its policy-maker, and any power children it has, but within the constraint
1011 * of the power state provided by its parent. The driver expresses its desire by
1012 * calling changePowerStateTo(), the policy-maker expresses its desire by calling
1013 * changePowerStateToPriv(), and the children express their desires by calling
1014 * requestPowerDomainState().
1016 * The Root Power Domain owns the policy for idle and demand sleep for the system.
1017 * It is a power-managed IOService just like the others in the system.
1018 * It implements several power states which map to what we see as Sleep and On.
1020 * The sleep policy is as follows:
1021 * 1. Sleep is prevented if the case is open so that nobody will think the machine
1022 * is off and plug/unplug cards.
1023 * 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
1024 * 3. System cannot Sleep if some object in the tree is in a power state marked
1025 * kIOPMPreventSystemSleep.
1027 * These three conditions are enforced using the "driver clamp" by calling
1028 * changePowerStateTo(). For example, if the case is opened,
1029 * changePowerStateTo(ON_STATE) is called to hold the system on regardless
1030 * of the desires of the children of the root or the state of the other clamp.
1032 * Demand Sleep is initiated by pressing the front panel power button, closing
1033 * the clamshell, or selecting the menu item. In this case the root's parent
1034 * actually initiates the power state change so that the root domain has no
1035 * choice and does not give applications the opportunity to veto the change.
1037 * Idle Sleep occurs if no objects in the tree are in a state marked
1038 * kIOPMPreventIdleSleep. When this is true, the root's children are not holding
1039 * the root on, so it sets the "policy-maker clamp" by calling
1040 * changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
1041 * This timer is set for the difference between the sleep timeout slider and the
1042 * display dim timeout slider. When the timer expires, it releases its clamp and
1043 * now nothing is holding it awake, so it falls asleep.
1045 * Demand sleep is prevented when the system is booting. When preferences are
1046 * transmitted by the loginwindow at the end of boot, a flag is cleared,
1047 * and this allows subsequent Demand Sleep.
1050 //******************************************************************************
1053 IOPMrootDomain::construct( void )
1055 IOPMrootDomain
*root
;
1057 root
= new IOPMrootDomain
;
1065 //******************************************************************************
1066 // updateConsoleUsersCallout
1068 //******************************************************************************
1071 updateConsoleUsersCallout(thread_call_param_t p0
, thread_call_param_t p1
)
1073 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
1074 rootDomain
->updateConsoleUsers();
1078 IOPMrootDomain::updateConsoleUsers(void)
1080 IOService::updateConsoleUsers(NULL
, kIOMessageSystemHasPoweredOn
);
1081 if (tasksSuspended
) {
1082 tasksSuspended
= FALSE
;
1083 updateTasksSuspend();
1088 IOPMrootDomain::updateTasksSuspend(void)
1092 newSuspend
= (tasksSuspended
|| _aotTasksSuspended
);
1093 if (newSuspend
== tasksSuspendState
) {
1096 tasksSuspendState
= newSuspend
;
1097 tasks_system_suspend(newSuspend
);
1100 //******************************************************************************
1103 disk_sync_callout( thread_call_param_t p0
, thread_call_param_t p1
)
1105 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
1106 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
1107 uint32_t powerState
= rootDomain
->getPowerState();
1109 DLOG("disk_sync_callout ps=%u\n", powerState
);
1111 if (ON_STATE
== powerState
) {
1115 // Block sleep until trim issued on previous wake path is completed.
1116 IOHibernateSystemPostWake(true);
1121 IOHibernateSystemPostWake(false);
1123 rootDomain
->sleepWakeDebugSaveSpinDumpFile();
1127 rootDomain
->allowPowerChange(notifyRef
);
1128 DLOG("disk_sync_callout finish\n");
1131 //******************************************************************************
1133 computeDeltaTimeMS( const AbsoluteTime
* startTime
, AbsoluteTime
* elapsedTime
)
1135 AbsoluteTime endTime
;
1138 clock_get_uptime(&endTime
);
1139 if (CMP_ABSOLUTETIME(&endTime
, startTime
) <= 0) {
1142 SUB_ABSOLUTETIME(&endTime
, startTime
);
1143 absolutetime_to_nanoseconds(endTime
, &nano
);
1144 *elapsedTime
= endTime
;
1147 return (UInt32
)(nano
/ NSEC_PER_MSEC
);
1150 //******************************************************************************
1153 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
1155 struct timeval
*swt
= (struct timeval
*)arg1
;
1156 struct proc
*p
= req
->p
;
1158 if (p
== kernproc
) {
1159 return sysctl_io_opaque(req
, swt
, sizeof(*swt
), NULL
);
1160 } else if (proc_is64bit(p
)) {
1161 struct user64_timeval t
= {};
1162 t
.tv_sec
= swt
->tv_sec
;
1163 t
.tv_usec
= swt
->tv_usec
;
1164 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
1166 struct user32_timeval t
= {};
1167 t
.tv_sec
= (typeof(t
.tv_sec
))swt
->tv_sec
;
1168 t
.tv_usec
= swt
->tv_usec
;
1169 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
1173 static SYSCTL_PROC(_kern
, OID_AUTO
, sleeptime
,
1174 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1175 &gIOLastUserSleepTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
1177 static SYSCTL_PROC(_kern
, OID_AUTO
, waketime
,
1178 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1179 &gIOLastWakeTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
1181 SYSCTL_QUAD(_kern
, OID_AUTO
, wake_abs_time
, CTLFLAG_RD
| CTLFLAG_LOCKED
, &gIOLastWakeAbsTime
, "");
1182 SYSCTL_QUAD(_kern
, OID_AUTO
, sleep_abs_time
, CTLFLAG_RD
| CTLFLAG_LOCKED
, &gIOLastSleepAbsTime
, "");
1183 SYSCTL_QUAD(_kern
, OID_AUTO
, useractive_abs_time
, CTLFLAG_RD
| CTLFLAG_LOCKED
, &gUserActiveAbsTime
, "");
1184 SYSCTL_QUAD(_kern
, OID_AUTO
, userinactive_abs_time
, CTLFLAG_RD
| CTLFLAG_LOCKED
, &gUserInactiveAbsTime
, "");
1188 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
1190 int new_value
, changed
;
1191 int error
= sysctl_io_number(req
, gWillShutdown
, sizeof(int), &new_value
, &changed
);
1193 if (!gWillShutdown
&& (new_value
== 1)) {
1194 IOPMRootDomainWillShutdown();
1202 static SYSCTL_PROC(_kern
, OID_AUTO
, willshutdown
,
1203 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1204 NULL
, 0, sysctl_willshutdown
, "I", "");
1206 extern struct sysctl_oid sysctl__kern_iokittest
;
1207 extern struct sysctl_oid sysctl__debug_iokit
;
1209 #if defined(XNU_TARGET_OS_OSX)
1212 sysctl_progressmeterenable
1213 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
1216 int new_value
, changed
;
1218 error
= sysctl_io_number(req
, vc_progressmeter_enable
, sizeof(int), &new_value
, &changed
);
1221 vc_enable_progressmeter(new_value
);
1228 sysctl_progressmeter
1229 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
1232 int new_value
, changed
;
1234 error
= sysctl_io_number(req
, vc_progressmeter_value
, sizeof(int), &new_value
, &changed
);
1237 vc_set_progressmeter(new_value
);
1243 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeterenable
,
1244 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1245 NULL
, 0, sysctl_progressmeterenable
, "I", "");
1247 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeter
,
1248 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1249 NULL
, 0, sysctl_progressmeter
, "I", "");
1251 #endif /* defined(XNU_TARGET_OS_OSX) */
1256 sysctl_consoleoptions
1257 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
1262 error
= sysctl_io_number(req
, vc_user_options
.options
, sizeof(uint32_t), &new_value
, &changed
);
1265 vc_user_options
.options
= new_value
;
1271 static SYSCTL_PROC(_kern
, OID_AUTO
, consoleoptions
,
1272 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1273 NULL
, 0, sysctl_consoleoptions
, "I", "");
1277 sysctl_progressoptions SYSCTL_HANDLER_ARGS
1279 return sysctl_io_opaque(req
, &vc_user_options
, sizeof(vc_user_options
), NULL
);
1282 static SYSCTL_PROC(_kern
, OID_AUTO
, progressoptions
,
1283 CTLTYPE_STRUCT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
| CTLFLAG_ANYBODY
,
1284 NULL
, 0, sysctl_progressoptions
, "S,vc_progress_user_options", "");
1288 sysctl_wakereason SYSCTL_HANDLER_ARGS
1290 char wr
[sizeof(gWakeReasonString
)];
1294 gRootDomain
->copyWakeReasonString(wr
, sizeof(wr
));
1297 return sysctl_io_string(req
, wr
, 0, 0, NULL
);
1300 SYSCTL_PROC(_kern
, OID_AUTO
, wakereason
,
1301 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1302 NULL
, 0, sysctl_wakereason
, "A", "wakereason");
1304 SYSCTL_STRING(_kern
, OID_AUTO
, bootreason
,
1305 CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1306 gBootReasonString
, sizeof(gBootReasonString
), "");
1309 sysctl_shutdownreason SYSCTL_HANDLER_ARGS
1311 char sr
[sizeof(gShutdownReasonString
)];
1315 gRootDomain
->copyShutdownReasonString(sr
, sizeof(sr
));
1318 return sysctl_io_string(req
, sr
, 0, 0, NULL
);
1321 SYSCTL_PROC(_kern
, OID_AUTO
, shutdownreason
,
1322 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1323 NULL
, 0, sysctl_shutdownreason
, "A", "shutdownreason");
1326 sysctl_targettype SYSCTL_HANDLER_ARGS
1329 OSSharedPtr
<OSObject
> obj
;
1334 root
= IOService::getServiceRoot();
1335 if (root
&& (obj
= root
->copyProperty(gIODTTargetTypeKey
))) {
1336 if ((data
= OSDynamicCast(OSData
, obj
.get()))) {
1337 strlcpy(tt
, (const char *) data
->getBytesNoCopy(), sizeof(tt
));
1340 return sysctl_io_string(req
, tt
, 0, 0, NULL
);
1343 SYSCTL_PROC(_hw
, OID_AUTO
, targettype
,
1344 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1345 NULL
, 0, sysctl_targettype
, "A", "targettype");
1347 static SYSCTL_INT(_debug
, OID_AUTO
, noidle
, CTLFLAG_RW
, &gNoIdleFlag
, 0, "");
1348 static SYSCTL_INT(_debug
, OID_AUTO
, swd_sleep_timeout
, CTLFLAG_RW
, &gSwdSleepTimeout
, 0, "");
1349 static SYSCTL_INT(_debug
, OID_AUTO
, swd_wake_timeout
, CTLFLAG_RW
, &gSwdWakeTimeout
, 0, "");
1350 static SYSCTL_INT(_debug
, OID_AUTO
, swd_timeout
, CTLFLAG_RW
, &gSwdSleepWakeTimeout
, 0, "");
1351 static SYSCTL_INT(_debug
, OID_AUTO
, swd_panic
, CTLFLAG_RW
, &gSwdPanic
, 0, "");
1352 #if DEVELOPMENT || DEBUG
1353 static SYSCTL_INT(_debug
, OID_AUTO
, swd_panic_phase
, CTLFLAG_RW
, &swd_panic_phase
, 0, "");
1354 #if defined(XNU_TARGET_OS_OSX)
1355 static SYSCTL_INT(_debug
, OID_AUTO
, clamshell
, CTLFLAG_RW
, &gClamshellFlags
, 0, "");
1356 static SYSCTL_INT(_debug
, OID_AUTO
, darkwake
, CTLFLAG_RW
, &gDarkWakeFlags
, 0, "");
1357 #endif /* defined(XNU_TARGET_OS_OSX) */
1358 #endif /* DEVELOPMENT || DEBUG */
1360 //******************************************************************************
1364 sysctl_aotmetrics SYSCTL_HANDLER_ARGS
1366 if (NULL
== gRootDomain
) {
1369 if (NULL
== gRootDomain
->_aotMetrics
) {
1372 return sysctl_io_opaque(req
, gRootDomain
->_aotMetrics
, sizeof(IOPMAOTMetrics
), NULL
);
1375 static SYSCTL_PROC(_kern
, OID_AUTO
, aotmetrics
,
1376 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
| CTLFLAG_ANYBODY
,
1377 NULL
, 0, sysctl_aotmetrics
, "S,IOPMAOTMetrics", "");
1381 update_aotmode(uint32_t mode
)
1385 if (!gIOPMWorkLoop
) {
1388 result
= gIOPMWorkLoop
->runActionBlock(^IOReturn (void) {
1389 unsigned int oldCount
;
1391 if (mode
&& !gRootDomain
->_aotMetrics
) {
1392 gRootDomain
->_aotMetrics
= IONewZero(IOPMAOTMetrics
, 1);
1393 if (!gRootDomain
->_aotMetrics
) {
1398 oldCount
= gRootDomain
->idleSleepPreventersCount();
1399 gRootDomain
->_aotMode
= (mode
& kIOPMAOTModeMask
);
1400 gRootDomain
->updatePreventIdleSleepListInternal(NULL
, false, oldCount
);
1408 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
1413 if (NULL
== gRootDomain
) {
1416 error
= sysctl_io_number(req
, gRootDomain
->_aotMode
, sizeof(uint32_t), &new_value
, &changed
);
1417 if (changed
&& gIOPMWorkLoop
) {
1418 error
= update_aotmode(new_value
);
1424 static SYSCTL_PROC(_kern
, OID_AUTO
, aotmodebits
,
1425 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1426 NULL
, 0, sysctl_aotmodebits
, "I", "");
1430 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
1435 if (NULL
== gRootDomain
) {
1438 error
= sysctl_io_number(req
, gRootDomain
->_aotMode
, sizeof(uint32_t), &new_value
, &changed
);
1439 if (changed
&& gIOPMWorkLoop
) {
1441 new_value
= kIOPMAOTModeDefault
; // & ~kIOPMAOTModeRespectTimers;
1443 error
= update_aotmode(new_value
);
1449 static SYSCTL_PROC(_kern
, OID_AUTO
, aotmode
,
1450 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
| CTLFLAG_ANYBODY
,
1451 NULL
, 0, sysctl_aotmode
, "I", "");
1453 //******************************************************************************
1455 static OSSharedPtr
<const OSSymbol
> gIOPMSettingAutoWakeCalendarKey
;
1456 static OSSharedPtr
<const OSSymbol
> gIOPMSettingAutoWakeSecondsKey
;
1457 static OSSharedPtr
<const OSSymbol
> gIOPMSettingAutoPowerCalendarKey
;
1458 static OSSharedPtr
<const OSSymbol
> gIOPMSettingAutoPowerSecondsKey
;
1459 static OSSharedPtr
<const OSSymbol
> gIOPMSettingDebugWakeRelativeKey
;
1460 static OSSharedPtr
<const OSSymbol
> gIOPMSettingDebugPowerRelativeKey
;
1461 static OSSharedPtr
<const OSSymbol
> gIOPMSettingMaintenanceWakeCalendarKey
;
1462 static OSSharedPtr
<const OSSymbol
> gIOPMSettingSleepServiceWakeCalendarKey
;
1463 static OSSharedPtr
<const OSSymbol
> gIOPMSettingSilentRunningKey
;
1464 static OSSharedPtr
<const OSSymbol
> gIOPMUserTriggeredFullWakeKey
;
1465 static OSSharedPtr
<const OSSymbol
> gIOPMUserIsActiveKey
;
1466 static OSSharedPtr
<const OSSymbol
> gIOPMSettingLowLatencyAudioModeKey
;
1468 //******************************************************************************
1471 //******************************************************************************
1473 #define kRootDomainSettingsCount 20
1474 #define kRootDomainNoPublishSettingsCount 4
1477 IOPMrootDomain::start( IOService
* nub
)
1479 OSSharedPtr
<OSIterator
> psIterator
;
1480 OSSharedPtr
<OSDictionary
> tmpDict
;
1485 gIOPMSettingAutoWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
);
1486 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
1487 gIOPMSettingAutoPowerCalendarKey
= OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
);
1488 gIOPMSettingAutoPowerSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
);
1489 gIOPMSettingDebugWakeRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
);
1490 gIOPMSettingDebugPowerRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
);
1491 gIOPMSettingMaintenanceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
1492 gIOPMSettingSleepServiceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey
);
1493 gIOPMSettingSilentRunningKey
= OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey
);
1494 gIOPMUserTriggeredFullWakeKey
= OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey
);
1495 gIOPMUserIsActiveKey
= OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey
);
1496 gIOPMSettingLowLatencyAudioModeKey
= OSSymbol::withCStringNoCopy(kIOPMSettingLowLatencyAudioModeKey
);
1498 gIOPMStatsResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
1499 gIOPMStatsResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
1500 gIOPMStatsResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
1501 gIOPMStatsResponsePrompt
= OSSymbol::withCString(kIOPMStatsResponsePrompt
);
1502 gIOPMStatsDriverPSChangeSlow
= OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow
);
1504 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
1505 sleepMessagePEFunction
= OSSymbol::withCString("IOPMSystemSleepMessage");
1506 gIOPMWakeTypeUserKey
= OSSymbol::withCStringNoCopy(kIOPMRootDomainWakeTypeUser
);
1508 OSSharedPtr
<const OSSymbol
> settingsArr
[kRootDomainSettingsCount
] =
1510 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
1511 gIOPMSettingAutoWakeSecondsKey
,
1512 gIOPMSettingAutoPowerSecondsKey
,
1513 gIOPMSettingAutoWakeCalendarKey
,
1514 gIOPMSettingAutoPowerCalendarKey
,
1515 gIOPMSettingDebugWakeRelativeKey
,
1516 gIOPMSettingDebugPowerRelativeKey
,
1517 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
1518 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
1519 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
1520 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
1521 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
1522 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
1523 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
1524 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
1525 OSSymbol::withCString(kIOPMStateConsoleShutdown
),
1526 OSSymbol::withCString(kIOPMSettingProModeControl
),
1527 OSSymbol::withCString(kIOPMSettingProModeDefer
),
1528 gIOPMSettingSilentRunningKey
,
1529 gIOPMSettingLowLatencyAudioModeKey
,
1532 OSSharedPtr
<const OSSymbol
> noPublishSettingsArr
[kRootDomainNoPublishSettingsCount
] =
1534 OSSymbol::withCString(kIOPMSettingProModeControl
),
1535 OSSymbol::withCString(kIOPMSettingProModeDefer
),
1536 gIOPMSettingSilentRunningKey
,
1537 gIOPMSettingLowLatencyAudioModeKey
,
1540 #if DEVELOPMENT || DEBUG
1541 #if defined(XNU_TARGET_OS_OSX)
1542 PE_parse_boot_argn("darkwake", &gDarkWakeFlags
, sizeof(gDarkWakeFlags
));
1543 PE_parse_boot_argn("clamshell", &gClamshellFlags
, sizeof(gClamshellFlags
));
1544 #endif /* defined(XNU_TARGET_OS_OSX) */
1545 #endif /* DEVELOPMENT || DEBUG */
1547 PE_parse_boot_argn("noidle", &gNoIdleFlag
, sizeof(gNoIdleFlag
));
1548 PE_parse_boot_argn("swd_sleeptimeout", &gSwdSleepTimeout
, sizeof(gSwdSleepTimeout
));
1549 PE_parse_boot_argn("swd_waketimeout", &gSwdWakeTimeout
, sizeof(gSwdWakeTimeout
));
1550 PE_parse_boot_argn("swd_timeout", &gSwdSleepWakeTimeout
, sizeof(gSwdSleepWakeTimeout
));
1551 PE_parse_boot_argn("haltmspanic", &gHaltTimeMaxPanic
, sizeof(gHaltTimeMaxPanic
));
1552 PE_parse_boot_argn("haltmslog", &gHaltTimeMaxLog
, sizeof(gHaltTimeMaxLog
));
1554 queue_init(&aggressivesQueue
);
1555 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
1556 aggressivesData
= OSData::withCapacity(
1557 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
1559 featuresDictLock
= IOLockAlloc();
1560 settingsCtrlLock
= IOLockAlloc();
1561 wakeEventLock
= IOLockAlloc();
1562 gHaltLogLock
= IOLockAlloc();
1563 setPMRootDomain(this);
1565 extraSleepTimer
= thread_call_allocate(
1566 idleSleepTimerExpired
,
1567 (thread_call_param_t
) this);
1569 powerButtonDown
= thread_call_allocate(
1570 powerButtonDownCallout
,
1571 (thread_call_param_t
) this);
1573 powerButtonUp
= thread_call_allocate(
1574 powerButtonUpCallout
,
1575 (thread_call_param_t
) this);
1577 diskSyncCalloutEntry
= thread_call_allocate(
1579 (thread_call_param_t
) this);
1580 updateConsoleUsersEntry
= thread_call_allocate(
1581 &updateConsoleUsersCallout
,
1582 (thread_call_param_t
) this);
1584 #if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
1585 fullWakeThreadCall
= thread_call_allocate_with_options(
1586 OSMemberFunctionCast(thread_call_func_t
, this,
1587 &IOPMrootDomain::fullWakeDelayedWork
),
1588 (thread_call_param_t
) this, THREAD_CALL_PRIORITY_KERNEL
,
1589 THREAD_CALL_OPTIONS_ONCE
);
1592 setProperty(kIOSleepSupportedKey
, true);
1594 bzero(&gPMStats
, sizeof(gPMStats
));
1596 pmTracer
= PMTraceWorker::tracer(this);
1598 pmAssertions
= PMAssertionsTracker::pmAssertionsTracker(this);
1600 userDisabledAllSleep
= false;
1601 systemBooting
= true;
1602 idleSleepEnabled
= false;
1604 idleSleepTimerPending
= false;
1606 clamshellClosed
= false;
1607 clamshellExists
= false;
1608 #if DISPLAY_WRANGLER_PRESENT
1609 clamshellDisabled
= true;
1611 clamshellDisabled
= false;
1613 clamshellIgnoreClose
= false;
1614 acAdaptorConnected
= true;
1615 clamshellSleepDisableMask
= 0;
1616 gWakeReasonString
[0] = '\0';
1618 // Initialize to user active.
1619 // Will never transition to user inactive w/o wrangler.
1620 fullWakeReason
= kFullWakeReasonLocalUser
;
1621 userIsActive
= userWasActive
= true;
1622 clock_get_uptime(&gUserActiveAbsTime
);
1623 setProperty(gIOPMUserIsActiveKey
.get(), kOSBooleanTrue
);
1625 // Set the default system capabilities at boot.
1626 _currentCapability
= kIOPMSystemCapabilityCPU
|
1627 kIOPMSystemCapabilityGraphics
|
1628 kIOPMSystemCapabilityAudio
|
1629 kIOPMSystemCapabilityNetwork
;
1631 _pendingCapability
= _currentCapability
;
1632 _desiredCapability
= _currentCapability
;
1633 _highestCapability
= _currentCapability
;
1634 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
1636 queuedSleepWakeUUIDString
= NULL
;
1637 initializeBootSessionUUID();
1638 pmStatsAppResponses
= OSArray::withCapacity(5);
1639 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
1640 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
1641 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
1642 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
1643 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
1644 _statsPowerCapsKey
= OSSymbol::withCString(kIOPMStatsPowerCapabilityKey
);
1645 assertOnWakeSecs
= -1;// Invalid value to prevent updates
1647 pmStatsLock
= IOLockAlloc();
1648 idxPMCPUClamshell
= kCPUUnknownIndex
;
1649 idxPMCPULimitedPower
= kCPUUnknownIndex
;
1651 tmpDict
= OSDictionary::withCapacity(1);
1652 setProperty(kRootDomainSupportedFeatures
, tmpDict
.get());
1654 // Set a default "SystemPowerProfileOverrideDict" for platform
1655 // drivers without any overrides.
1656 if (!propertyExists(kIOPMSystemDefaultOverrideKey
)) {
1657 tmpDict
= OSDictionary::withCapacity(1);
1658 setProperty(kIOPMSystemDefaultOverrideKey
, tmpDict
.get());
1661 settingsCallbacks
= OSDictionary::withCapacity(1);
1663 // Create a list of the valid PM settings that we'll relay to
1664 // interested clients in setProperties() => setPMSetting()
1665 allowedPMSettings
= OSArray::withObjects(
1666 (const OSObject
**)settingsArr
,
1667 kRootDomainSettingsCount
,
1670 // List of PM settings that should not automatically publish itself
1671 // as a feature when registered by a listener.
1672 noPublishPMSettings
= OSArray::withObjects(
1673 (const OSObject
**)noPublishSettingsArr
,
1674 kRootDomainNoPublishSettingsCount
,
1677 fPMSettingsDict
= OSDictionary::withCapacity(5);
1678 preventIdleSleepList
= OSSet::withCapacity(8);
1679 preventSystemSleepList
= OSSet::withCapacity(2);
1681 PMinit(); // creates gIOPMWorkLoop
1682 gIOPMWorkLoop
= getIOPMWorkloop();
1684 // Create IOPMPowerStateQueue used to queue external power
1685 // events, and to handle those events on the PM work loop.
1686 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
1687 this, OSMemberFunctionCast(IOEventSource::Action
, this,
1688 &IOPMrootDomain::dispatchPowerEvent
));
1689 gIOPMWorkLoop
->addEventSource(pmPowerStateQueue
);
1692 _aotTimerES
= IOTimerEventSource::timerEventSource(this,
1693 OSMemberFunctionCast(IOTimerEventSource::Action
,
1694 this, &IOPMrootDomain::aotEvaluate
));
1695 gIOPMWorkLoop
->addEventSource(_aotTimerES
.get());
1697 // create our power parent
1698 gPatriarch
= new IORootParent
;
1700 gPatriarch
->attach(this);
1701 gPatriarch
->start(this);
1702 gPatriarch
->addPowerChild(this);
1704 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
1705 changePowerStateWithTagToPriv(ON_STATE
, kCPSReasonInit
);
1707 // install power change handler
1708 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, NULL
);
1710 #if DISPLAY_WRANGLER_PRESENT
1711 wranglerIdleSettings
= OSDictionary::withCapacity(1);
1712 OSSharedPtr
<OSNumber
> wranglerIdlePeriod
= OSNumber::withNumber(kDefaultWranglerIdlePeriod
, 32);
1714 if (wranglerIdleSettings
&& wranglerIdlePeriod
) {
1715 wranglerIdleSettings
->setObject(kIORequestWranglerIdleKey
,
1716 wranglerIdlePeriod
.get());
1719 #endif /* DISPLAY_WRANGLER_PRESENT */
1721 lowLatencyAudioNotifierDict
= OSDictionary::withCapacity(2);
1722 lowLatencyAudioNotifyStateSym
= OSSymbol::withCString("LowLatencyAudioNotifyState");
1723 lowLatencyAudioNotifyTimestampSym
= OSSymbol::withCString("LowLatencyAudioNotifyTimestamp");
1724 lowLatencyAudioNotifyStateVal
= OSNumber::withNumber(0ull, 32);
1725 lowLatencyAudioNotifyTimestampVal
= OSNumber::withNumber(0ull, 64);
1727 if (lowLatencyAudioNotifierDict
&& lowLatencyAudioNotifyStateSym
&& lowLatencyAudioNotifyTimestampSym
&&
1728 lowLatencyAudioNotifyStateVal
&& lowLatencyAudioNotifyTimestampVal
) {
1729 lowLatencyAudioNotifierDict
->setObject(lowLatencyAudioNotifyStateSym
.get(), lowLatencyAudioNotifyStateVal
.get());
1730 lowLatencyAudioNotifierDict
->setObject(lowLatencyAudioNotifyTimestampSym
.get(), lowLatencyAudioNotifyTimestampVal
.get());
1733 OSSharedPtr
<const OSSymbol
> ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
1734 setProperty(gIOUserClientClassKey
, const_cast<OSObject
*>(static_cast<const OSObject
*>(ucClassName
.get())));
1736 // IOBacklightDisplay can take a long time to load at boot, or it may
1737 // not load at all if you're booting with clamshell closed. We publish
1738 // 'DisplayDims' here redundantly to get it published early and at all.
1739 OSSharedPtr
<OSDictionary
> matching
;
1740 matching
= serviceMatching("IOPMPowerSource");
1741 psIterator
= getMatchingServices(matching
.get());
1743 if (psIterator
&& psIterator
->getNextObject()) {
1744 // There's at least one battery on the system, so we publish
1745 // 'DisplayDims' support for the LCD.
1746 publishFeature("DisplayDims");
1749 // read swd_panic boot-arg
1750 PE_parse_boot_argn("swd_panic", &gSwdPanic
, sizeof(gSwdPanic
));
1751 sysctl_register_oid(&sysctl__kern_sleeptime
);
1752 sysctl_register_oid(&sysctl__kern_waketime
);
1753 sysctl_register_oid(&sysctl__kern_willshutdown
);
1754 sysctl_register_oid(&sysctl__kern_iokittest
);
1755 sysctl_register_oid(&sysctl__debug_iokit
);
1756 sysctl_register_oid(&sysctl__hw_targettype
);
1758 #if defined(XNU_TARGET_OS_OSX)
1759 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
1760 sysctl_register_oid(&sysctl__kern_progressmeter
);
1761 sysctl_register_oid(&sysctl__kern_wakereason
);
1762 #endif /* defined(XNU_TARGET_OS_OSX) */
1763 sysctl_register_oid(&sysctl__kern_consoleoptions
);
1764 sysctl_register_oid(&sysctl__kern_progressoptions
);
1766 sysctl_register_oid(&sysctl__kern_aotmode
);
1767 sysctl_register_oid(&sysctl__kern_aotmodebits
);
1768 sysctl_register_oid(&sysctl__kern_aotmetrics
);
1771 #if defined(__arm64__)
1772 #endif /* defined(__arm64__) */
1773 IOHibernateSystemInit(this);
1776 registerService(); // let clients find us
1781 //******************************************************************************
1784 // Receive a setProperty call
1785 // The "System Boot" property means the system is completely booted.
1786 //******************************************************************************
1789 IOPMrootDomain::setProperties( OSObject
* props_obj
)
1791 IOReturn return_value
= kIOReturnSuccess
;
1792 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
1793 OSBoolean
*b
= NULL
;
1795 const OSSymbol
*key
= NULL
;
1796 OSObject
*obj
= NULL
;
1797 OSSharedPtr
<OSCollectionIterator
> iter
;
1800 return kIOReturnBadArgument
;
1803 bool clientEntitled
= false;
1805 OSSharedPtr
<OSObject
> obj
= IOUserClient::copyClientEntitlement(current_task(), kRootDomainEntitlementSetProperty
);
1806 clientEntitled
= (obj
== kOSBooleanTrue
);
1809 if (!clientEntitled
) {
1810 const char * errorSuffix
= NULL
;
1812 // IOPMSchedulePowerEvent() clients may not be entitled, but must be root.
1813 // That API can set 6 possible keys that are checked below.
1814 if ((dict
->getCount() == 1) &&
1815 (dict
->getObject(gIOPMSettingAutoWakeSecondsKey
.get()) ||
1816 dict
->getObject(gIOPMSettingAutoPowerSecondsKey
.get()) ||
1817 dict
->getObject(gIOPMSettingAutoWakeCalendarKey
.get()) ||
1818 dict
->getObject(gIOPMSettingAutoPowerCalendarKey
.get()) ||
1819 dict
->getObject(gIOPMSettingDebugWakeRelativeKey
.get()) ||
1820 dict
->getObject(gIOPMSettingDebugPowerRelativeKey
.get()))) {
1821 return_value
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
1822 if (return_value
!= kIOReturnSuccess
) {
1823 errorSuffix
= "privileged";
1826 return_value
= kIOReturnNotPermitted
;
1827 errorSuffix
= "entitled";
1830 if (return_value
!= kIOReturnSuccess
) {
1831 OSSharedPtr
<OSString
> procName(IOCopyLogNameForPID(proc_selfpid()), OSNoRetain
);
1832 DLOG("%s failed, process %s is not %s\n", __func__
,
1833 procName
? procName
->getCStringNoCopy() : "", errorSuffix
);
1834 return return_value
;
1838 OSSharedPtr
<const OSSymbol
> publish_simulated_battery_string
= OSSymbol::withCString("SoftwareSimulatedBatteries");
1839 OSSharedPtr
<const OSSymbol
> boot_complete_string
= OSSymbol::withCString("System Boot Complete");
1840 OSSharedPtr
<const OSSymbol
> sys_shutdown_string
= OSSymbol::withCString("System Shutdown");
1841 OSSharedPtr
<const OSSymbol
> stall_halt_string
= OSSymbol::withCString("StallSystemAtHalt");
1842 OSSharedPtr
<const OSSymbol
> battery_warning_disabled_string
= OSSymbol::withCString("BatteryWarningsDisabled");
1843 OSSharedPtr
<const OSSymbol
> idle_seconds_string
= OSSymbol::withCString("System Idle Seconds");
1844 OSSharedPtr
<const OSSymbol
> sleepdisabled_string
= OSSymbol::withCString("SleepDisabled");
1845 OSSharedPtr
<const OSSymbol
> ondeck_sleepwake_uuid_string
= OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
1846 OSSharedPtr
<const OSSymbol
> loginwindow_progress_string
= OSSymbol::withCString(kIOPMLoginWindowProgressKey
);
1847 OSSharedPtr
<const OSSymbol
> coredisplay_progress_string
= OSSymbol::withCString(kIOPMCoreDisplayProgressKey
);
1848 OSSharedPtr
<const OSSymbol
> coregraphics_progress_string
= OSSymbol::withCString(kIOPMCoreGraphicsProgressKey
);
1849 #if DEBUG || DEVELOPMENT
1850 OSSharedPtr
<const OSSymbol
> clamshell_close_string
= OSSymbol::withCString("IOPMTestClamshellClose");
1851 OSSharedPtr
<const OSSymbol
> clamshell_open_string
= OSSymbol::withCString("IOPMTestClamshellOpen");
1852 OSSharedPtr
<const OSSymbol
> ac_detach_string
= OSSymbol::withCString("IOPMTestACDetach");
1853 OSSharedPtr
<const OSSymbol
> ac_attach_string
= OSSymbol::withCString("IOPMTestACAttach");
1854 OSSharedPtr
<const OSSymbol
> desktopmode_set_string
= OSSymbol::withCString("IOPMTestDesktopModeSet");
1855 OSSharedPtr
<const OSSymbol
> desktopmode_remove_string
= OSSymbol::withCString("IOPMTestDesktopModeRemove");
1859 OSSharedPtr
<const OSSymbol
> hibernatemode_string
= OSSymbol::withCString(kIOHibernateModeKey
);
1860 OSSharedPtr
<const OSSymbol
> hibernatefile_string
= OSSymbol::withCString(kIOHibernateFileKey
);
1861 OSSharedPtr
<const OSSymbol
> hibernatefilemin_string
= OSSymbol::withCString(kIOHibernateFileMinSizeKey
);
1862 OSSharedPtr
<const OSSymbol
> hibernatefilemax_string
= OSSymbol::withCString(kIOHibernateFileMaxSizeKey
);
1863 OSSharedPtr
<const OSSymbol
> hibernatefreeratio_string
= OSSymbol::withCString(kIOHibernateFreeRatioKey
);
1864 OSSharedPtr
<const OSSymbol
> hibernatefreetime_string
= OSSymbol::withCString(kIOHibernateFreeTimeKey
);
1867 iter
= OSCollectionIterator::withCollection(dict
);
1869 return_value
= kIOReturnNoMemory
;
1873 while ((key
= (const OSSymbol
*) iter
->getNextObject()) &&
1874 (obj
= dict
->getObject(key
))) {
1875 if (key
->isEqualTo(publish_simulated_battery_string
.get())) {
1876 if (OSDynamicCast(OSBoolean
, obj
)) {
1877 publishResource(key
, kOSBooleanTrue
);
1879 } else if (key
->isEqualTo(idle_seconds_string
.get())) {
1880 if ((n
= OSDynamicCast(OSNumber
, obj
))) {
1881 setProperty(key
, n
);
1882 idleSeconds
= n
->unsigned32BitValue();
1884 } else if (key
->isEqualTo(boot_complete_string
.get())) {
1885 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemBootCompleted
);
1886 } else if (key
->isEqualTo(sys_shutdown_string
.get())) {
1887 if ((b
= OSDynamicCast(OSBoolean
, obj
))) {
1888 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
1890 } else if (key
->isEqualTo(battery_warning_disabled_string
.get())) {
1891 setProperty(key
, obj
);
1894 else if (key
->isEqualTo(hibernatemode_string
.get()) ||
1895 key
->isEqualTo(hibernatefilemin_string
.get()) ||
1896 key
->isEqualTo(hibernatefilemax_string
.get()) ||
1897 key
->isEqualTo(hibernatefreeratio_string
.get()) ||
1898 key
->isEqualTo(hibernatefreetime_string
.get())) {
1899 if ((n
= OSDynamicCast(OSNumber
, obj
))) {
1900 setProperty(key
, n
);
1902 } else if (key
->isEqualTo(hibernatefile_string
.get())) {
1903 OSString
* str
= OSDynamicCast(OSString
, obj
);
1905 setProperty(key
, str
);
1909 else if (key
->isEqualTo(sleepdisabled_string
.get())) {
1910 if ((b
= OSDynamicCast(OSBoolean
, obj
))) {
1911 setProperty(key
, b
);
1912 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
1914 } else if (key
->isEqualTo(ondeck_sleepwake_uuid_string
.get())) {
1916 pmPowerStateQueue
->submitPowerEvent(kPowerEventQueueSleepWakeUUID
, (void *)obj
);
1917 } else if (key
->isEqualTo(loginwindow_progress_string
.get())) {
1918 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1919 uint32_t data
= n
->unsigned32BitValue();
1920 pmTracer
->traceComponentWakeProgress(kIOPMLoginWindowProgress
, data
);
1921 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMLoginWindowProgress
, data
);
1923 } else if (key
->isEqualTo(coredisplay_progress_string
.get())) {
1924 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1925 uint32_t data
= n
->unsigned32BitValue();
1926 pmTracer
->traceComponentWakeProgress(kIOPMCoreDisplayProgress
, data
);
1927 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMCoreDisplayProgress
, data
);
1929 } else if (key
->isEqualTo(coregraphics_progress_string
.get())) {
1930 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1931 uint32_t data
= n
->unsigned32BitValue();
1932 pmTracer
->traceComponentWakeProgress(kIOPMCoreGraphicsProgress
, data
);
1933 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMCoreGraphicsProgress
, data
);
1935 } else if (key
->isEqualTo(kIOPMDeepSleepEnabledKey
) ||
1936 key
->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey
) ||
1937 key
->isEqualTo(kIOPMAutoPowerOffEnabledKey
) ||
1938 key
->isEqualTo(stall_halt_string
.get())) {
1939 if ((b
= OSDynamicCast(OSBoolean
, obj
))) {
1940 setProperty(key
, b
);
1942 } else if (key
->isEqualTo(kIOPMDeepSleepDelayKey
) ||
1943 key
->isEqualTo(kIOPMDeepSleepTimerKey
) ||
1944 key
->isEqualTo(kIOPMAutoPowerOffDelayKey
) ||
1945 key
->isEqualTo(kIOPMAutoPowerOffTimerKey
)) {
1946 if ((n
= OSDynamicCast(OSNumber
, obj
))) {
1947 setProperty(key
, n
);
1949 } else if (key
->isEqualTo(kIOPMUserWakeAlarmScheduledKey
)) {
1950 if (kOSBooleanTrue
== obj
) {
1951 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_userScheduledAlarmMask
);
1953 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_userScheduledAlarmMask
);
1955 DLOG("_userScheduledAlarmMask 0x%x\n", (uint32_t) _userScheduledAlarmMask
);
1957 #if DEBUG || DEVELOPMENT
1958 else if (key
->isEqualTo(clamshell_close_string
.get())) {
1959 DLOG("SetProperties: setting clamshell close\n");
1960 UInt32 msg
= kIOPMClamshellClosed
;
1961 pmPowerStateQueue
->submitPowerEvent(kPowerEventReceivedPowerNotification
, (void *)(uintptr_t)msg
);
1962 } else if (key
->isEqualTo(clamshell_open_string
.get())) {
1963 DLOG("SetProperties: setting clamshell open\n");
1964 UInt32 msg
= kIOPMClamshellOpened
;
1965 pmPowerStateQueue
->submitPowerEvent(kPowerEventReceivedPowerNotification
, (void *)(uintptr_t)msg
);
1966 } else if (key
->isEqualTo(ac_detach_string
.get())) {
1967 DLOG("SetProperties: setting ac detach\n");
1968 UInt32 msg
= kIOPMSetACAdaptorConnected
;
1969 pmPowerStateQueue
->submitPowerEvent(kPowerEventReceivedPowerNotification
, (void *)(uintptr_t)msg
);
1970 } else if (key
->isEqualTo(ac_attach_string
.get())) {
1971 DLOG("SetProperties: setting ac attach\n");
1972 UInt32 msg
= kIOPMSetACAdaptorConnected
| kIOPMSetValue
;
1973 pmPowerStateQueue
->submitPowerEvent(kPowerEventReceivedPowerNotification
, (void *)(uintptr_t)msg
);
1974 } else if (key
->isEqualTo(desktopmode_set_string
.get())) {
1975 DLOG("SetProperties: setting desktopmode");
1976 UInt32 msg
= kIOPMSetDesktopMode
| kIOPMSetValue
;
1977 pmPowerStateQueue
->submitPowerEvent(kPowerEventReceivedPowerNotification
, (void *)(uintptr_t)msg
);
1978 } else if (key
->isEqualTo(desktopmode_remove_string
.get())) {
1979 DLOG("SetProperties: removing desktopmode\n");
1980 UInt32 msg
= kIOPMSetDesktopMode
;
1981 pmPowerStateQueue
->submitPowerEvent(kPowerEventReceivedPowerNotification
, (void *)(uintptr_t)msg
);
1984 // Relay our allowed PM settings onto our registered PM clients
1985 else if ((allowedPMSettings
->getNextIndexOfObject(key
, 0) != (unsigned int) -1)) {
1986 return_value
= setPMSetting(key
, obj
);
1987 if (kIOReturnSuccess
!= return_value
) {
1991 DLOG("setProperties(%s) not handled\n", key
->getCStringNoCopy());
1996 return return_value
;
2000 // MARK: Aggressiveness
2002 //******************************************************************************
2003 // setAggressiveness
2005 // Override IOService::setAggressiveness()
2006 //******************************************************************************
2009 IOPMrootDomain::setAggressiveness(
2011 unsigned long value
)
2013 return setAggressiveness( type
, value
, 0 );
2017 * Private setAggressiveness() with an internal options argument.
2020 IOPMrootDomain::setAggressiveness(
2022 unsigned long value
,
2023 IOOptionBits options
)
2025 AggressivesRequest
* entry
;
2026 AggressivesRequest
* request
;
2029 if ((type
> UINT_MAX
) || (value
> UINT_MAX
)) {
2030 return kIOReturnBadArgument
;
2033 if (type
== kPMMinutesToDim
|| type
== kPMMinutesToSleep
) {
2034 DLOG("setAggressiveness(%x) %s = %u\n",
2035 (uint32_t) options
, getAggressivenessTypeString((uint32_t) type
), (uint32_t) value
);
2037 DEBUG_LOG("setAggressiveness(%x) %s = %u\n",
2038 (uint32_t) options
, getAggressivenessTypeString((uint32_t) type
), (uint32_t) value
);
2041 request
= IONew(AggressivesRequest
, 1);
2043 return kIOReturnNoMemory
;
2046 memset(request
, 0, sizeof(*request
));
2047 request
->options
= options
;
2048 request
->dataType
= kAggressivesRequestTypeRecord
;
2049 request
->data
.record
.type
= (uint32_t) type
;
2050 request
->data
.record
.value
= (uint32_t) value
;
2054 // Update disk quick spindown flag used by getAggressiveness().
2055 // Never merge requests with quick spindown flags set.
2057 if (options
& kAggressivesOptionQuickSpindownEnable
) {
2058 gAggressivesState
|= kAggressivesStateQuickSpindown
;
2059 } else if (options
& kAggressivesOptionQuickSpindownDisable
) {
2060 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
2062 // Coalesce requests with identical aggressives types.
2063 // Deal with callers that calls us too "aggressively".
2065 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
2067 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
2068 (entry
->data
.record
.type
== type
) &&
2069 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0)) {
2070 entry
->data
.record
.value
= (uint32_t) value
;
2078 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
2081 AGGRESSIVES_UNLOCK();
2084 IODelete(request
, AggressivesRequest
, 1);
2087 if (options
& kAggressivesOptionSynchronous
) {
2088 handleAggressivesRequests(); // not truly synchronous
2090 thread_call_enter(aggressivesThreadCall
);
2093 return kIOReturnSuccess
;
2096 //******************************************************************************
2097 // getAggressiveness
2099 // Override IOService::setAggressiveness()
2100 // Fetch the aggressiveness factor with the given type.
2101 //******************************************************************************
2104 IOPMrootDomain::getAggressiveness(
2106 unsigned long * outLevel
)
2111 if (!outLevel
|| (type
> UINT_MAX
)) {
2112 return kIOReturnBadArgument
;
2117 // Disk quick spindown in effect, report value = 1
2119 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
2120 (type
== kPMMinutesToSpinDown
)) {
2121 value
= kAggressivesMinValue
;
2125 // Consult the pending request queue.
2128 AggressivesRequest
* entry
;
2130 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
2132 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
2133 (entry
->data
.record
.type
== type
) &&
2134 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0)) {
2135 value
= entry
->data
.record
.value
;
2142 // Consult the backend records.
2144 if (!source
&& aggressivesData
) {
2145 AggressivesRecord
* record
;
2148 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
2149 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
2151 for (i
= 0; i
< count
; i
++, record
++) {
2152 if (record
->type
== type
) {
2153 value
= record
->value
;
2160 AGGRESSIVES_UNLOCK();
2163 *outLevel
= (unsigned long) value
;
2164 return kIOReturnSuccess
;
2166 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
2167 *outLevel
= 0; // default return = 0, driver may not check for error
2168 return kIOReturnInvalid
;
2172 //******************************************************************************
2173 // joinAggressiveness
2175 // Request from IOService to join future aggressiveness broadcasts.
2176 //******************************************************************************
2179 IOPMrootDomain::joinAggressiveness(
2180 IOService
* service
)
2182 AggressivesRequest
* request
;
2184 if (!service
|| (service
== this)) {
2185 return kIOReturnBadArgument
;
2188 DEBUG_LOG("joinAggressiveness %s %p\n", service
->getName(), OBFUSCATE(service
));
2190 request
= IONew(AggressivesRequest
, 1);
2192 return kIOReturnNoMemory
;
2195 memset(request
, 0, sizeof(*request
));
2196 request
->dataType
= kAggressivesRequestTypeService
;
2197 request
->data
.service
.reset(service
, OSRetain
); // released by synchronizeAggressives()
2200 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
2201 AGGRESSIVES_UNLOCK();
2203 thread_call_enter(aggressivesThreadCall
);
2205 return kIOReturnSuccess
;
2208 //******************************************************************************
2209 // handleAggressivesRequests
2211 // Backend thread processes all incoming aggressiveness requests in the queue.
2212 //******************************************************************************
2215 handleAggressivesFunction(
2216 thread_call_param_t param1
,
2217 thread_call_param_t param2
)
2220 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
2225 IOPMrootDomain::handleAggressivesRequests( void )
2227 AggressivesRecord
* start
;
2228 AggressivesRecord
* record
;
2229 AggressivesRequest
* request
;
2230 queue_head_t joinedQueue
;
2234 bool pingSelf
= false;
2238 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
2239 queue_empty(&aggressivesQueue
)) {
2243 gAggressivesState
|= kAggressivesStateBusy
;
2244 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
2245 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
2249 queue_init(&joinedQueue
);
2252 // Remove request from the incoming queue in FIFO order.
2253 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
2254 switch (request
->dataType
) {
2255 case kAggressivesRequestTypeRecord
:
2256 // Update existing record if found.
2258 for (i
= 0, record
= start
; i
< count
; i
++, record
++) {
2259 if (record
->type
== request
->data
.record
.type
) {
2262 if (request
->options
& kAggressivesOptionQuickSpindownEnable
) {
2263 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0) {
2265 record
->flags
|= (kAggressivesRecordFlagMinValue
|
2266 kAggressivesRecordFlagModified
);
2267 DLOG("disk spindown accelerated, was %u min\n",
2270 } else if (request
->options
& kAggressivesOptionQuickSpindownDisable
) {
2271 if (record
->flags
& kAggressivesRecordFlagMinValue
) {
2273 record
->flags
|= kAggressivesRecordFlagModified
;
2274 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
2275 DLOG("disk spindown restored to %u min\n",
2278 } else if (record
->value
!= request
->data
.record
.value
) {
2279 record
->value
= request
->data
.record
.value
;
2280 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0) {
2282 record
->flags
|= kAggressivesRecordFlagModified
;
2289 // No matching record, append a new record.
2291 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0)) {
2292 AggressivesRecord newRecord
;
2294 newRecord
.flags
= kAggressivesRecordFlagModified
;
2295 newRecord
.type
= request
->data
.record
.type
;
2296 newRecord
.value
= request
->data
.record
.value
;
2297 if (request
->options
& kAggressivesOptionQuickSpindownEnable
) {
2298 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
2299 DLOG("disk spindown accelerated\n");
2302 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
2304 // OSData may have switched to another (larger) buffer.
2305 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
2306 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
2310 // Finished processing the request, release it.
2311 IODelete(request
, AggressivesRequest
, 1);
2314 case kAggressivesRequestTypeService
:
2315 // synchronizeAggressives() will free request.
2316 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
2320 panic("bad aggressives request type %x\n", request
->dataType
);
2323 } while (!queue_empty(&aggressivesQueue
));
2325 // Release the lock to perform work, with busy flag set.
2326 if (!queue_empty(&joinedQueue
) || broadcast
) {
2327 AGGRESSIVES_UNLOCK();
2328 if (!queue_empty(&joinedQueue
)) {
2329 synchronizeAggressives(&joinedQueue
, start
, count
);
2332 broadcastAggressives(start
, count
);
2337 // Remove the modified flag from all records.
2338 for (i
= 0, record
= start
; i
< count
; i
++, record
++) {
2339 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
2340 ((record
->type
== kPMMinutesToDim
) ||
2341 (record
->type
== kPMMinutesToSleep
))) {
2345 record
->flags
&= ~kAggressivesRecordFlagModified
;
2348 // Check the incoming queue again since new entries may have been
2349 // added while lock was released above.
2350 } while (!queue_empty(&aggressivesQueue
));
2352 gAggressivesState
&= ~kAggressivesStateBusy
;
2355 AGGRESSIVES_UNLOCK();
2357 // Root domain is interested in system and display sleep slider changes.
2358 // Submit a power event to handle those changes on the PM work loop.
2360 if (pingSelf
&& pmPowerStateQueue
) {
2361 pmPowerStateQueue
->submitPowerEvent(
2362 kPowerEventPolicyStimulus
,
2363 (void *) kStimulusAggressivenessChanged
);
2367 //******************************************************************************
2368 // synchronizeAggressives
2370 // Push all known aggressiveness records to one or more IOService.
2371 //******************************************************************************
2374 IOPMrootDomain::synchronizeAggressives(
2375 queue_head_t
* joinedQueue
,
2376 const AggressivesRecord
* array
,
2379 OSSharedPtr
<IOService
> service
;
2380 AggressivesRequest
* request
;
2381 const AggressivesRecord
* record
;
2382 IOPMDriverCallEntry callEntry
;
2386 while (!queue_empty(joinedQueue
)) {
2387 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
2388 if (request
->dataType
== kAggressivesRequestTypeService
) {
2389 // retained by joinAggressiveness(), so take ownership
2390 service
= os::move(request
->data
.service
);
2395 IODelete(request
, AggressivesRequest
, 1);
2399 if (service
->assertPMDriverCall(&callEntry
, kIOPMDriverCallMethodSetAggressive
)) {
2400 for (i
= 0, record
= array
; i
< count
; i
++, record
++) {
2401 value
= record
->value
;
2402 if (record
->flags
& kAggressivesRecordFlagMinValue
) {
2403 value
= kAggressivesMinValue
;
2406 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
2407 record
->type
, value
, service
->getName());
2408 service
->setAggressiveness(record
->type
, value
);
2410 service
->deassertPMDriverCall(&callEntry
);
2416 //******************************************************************************
2417 // broadcastAggressives
2419 // Traverse PM tree and call setAggressiveness() for records that have changed.
2420 //******************************************************************************
2423 IOPMrootDomain::broadcastAggressives(
2424 const AggressivesRecord
* array
,
2427 OSSharedPtr
<IORegistryIterator
> iter
;
2428 IORegistryEntry
*entry
;
2429 OSSharedPtr
<IORegistryEntry
> child
;
2430 IOPowerConnection
*connect
;
2432 const AggressivesRecord
*record
;
2433 IOPMDriverCallEntry callEntry
;
2437 iter
= IORegistryIterator::iterateOver(
2438 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
2441 // !! reset the iterator
2443 while ((entry
= iter
->getNextObject())) {
2444 connect
= OSDynamicCast(IOPowerConnection
, entry
);
2445 if (!connect
|| !connect
->getReadyFlag()) {
2449 child
= connect
->copyChildEntry(gIOPowerPlane
);
2451 if ((service
= OSDynamicCast(IOService
, child
.get()))) {
2452 if (service
->assertPMDriverCall(&callEntry
, kIOPMDriverCallMethodSetAggressive
)) {
2453 for (i
= 0, record
= array
; i
< count
; i
++, record
++) {
2454 if (record
->flags
& kAggressivesRecordFlagModified
) {
2455 value
= record
->value
;
2456 if (record
->flags
& kAggressivesRecordFlagMinValue
) {
2457 value
= kAggressivesMinValue
;
2459 _LOG("broadcastAggressives %x = %u to %s\n",
2460 record
->type
, value
, service
->getName());
2461 service
->setAggressiveness(record
->type
, value
);
2464 service
->deassertPMDriverCall(&callEntry
);
2469 }while (!entry
&& !iter
->isValid());
2473 //*****************************************
2474 // stackshot on power button press
2475 // ***************************************
2477 powerButtonDownCallout(thread_call_param_t us
, thread_call_param_t
)
2479 /* Power button pressed during wake
2482 DEBUG_LOG("Powerbutton: down. Taking stackshot\n");
2483 ((IOPMrootDomain
*)us
)->takeStackshot(false);
2487 powerButtonUpCallout(thread_call_param_t us
, thread_call_param_t
)
2489 /* Power button released.
2490 * Delete any stackshot data
2492 DEBUG_LOG("PowerButton: up callout. Delete stackshot\n");
2493 ((IOPMrootDomain
*)us
)->deleteStackshot();
2495 //*************************************************************************
2499 // MARK: System Sleep
2501 //******************************************************************************
2502 // startIdleSleepTimer
2504 //******************************************************************************
2507 IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
2509 AbsoluteTime deadline
;
2513 DLOG("idle timer not set (noidle=%d)\n", gNoIdleFlag
);
2517 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
2518 thread_call_enter_delayed(extraSleepTimer
, deadline
);
2519 idleSleepTimerPending
= true;
2521 thread_call_enter(extraSleepTimer
);
2523 DLOG("idle timer set for %u seconds\n", inSeconds
);
2526 //******************************************************************************
2527 // cancelIdleSleepTimer
2529 //******************************************************************************
2532 IOPMrootDomain::cancelIdleSleepTimer( void )
2535 if (idleSleepTimerPending
) {
2536 DLOG("idle timer cancelled\n");
2537 thread_call_cancel(extraSleepTimer
);
2538 idleSleepTimerPending
= false;
2540 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
2542 clock_usec_t microsecs
;
2543 clock_get_uptime(&now
);
2544 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
2545 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
2546 if (assertOnWakeReport
) {
2547 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
2548 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
2554 //******************************************************************************
2555 // idleSleepTimerExpired
2557 //******************************************************************************
2560 idleSleepTimerExpired(
2561 thread_call_param_t us
, thread_call_param_t
)
2563 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
2566 //******************************************************************************
2567 // handleSleepTimerExpiration
2569 // The time between the sleep idle timeout and the next longest one has elapsed.
2570 // It's time to sleep. Start that by removing the clamp that's holding us awake.
2571 //******************************************************************************
2574 IOPMrootDomain::handleSleepTimerExpiration( void )
2576 if (!gIOPMWorkLoop
->inGate()) {
2577 gIOPMWorkLoop
->runAction(
2578 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2579 &IOPMrootDomain::handleSleepTimerExpiration
),
2584 DLOG("sleep timer expired\n");
2587 idleSleepTimerPending
= false;
2588 setQuickSpinDownTimeout();
2589 adjustPowerState(true);
2592 //******************************************************************************
2593 // getTimeToIdleSleep
2595 // Returns number of seconds left before going into idle sleep.
2596 // Caller has to make sure that idle sleep is allowed at the time of calling
2598 //******************************************************************************
2601 IOPMrootDomain::getTimeToIdleSleep( void )
2603 AbsoluteTime now
, lastActivityTime
;
2605 uint32_t minutesSinceUserInactive
= 0;
2606 uint32_t sleepDelay
= 0;
2608 if (!idleSleepEnabled
) {
2612 if (userActivityTime
) {
2613 lastActivityTime
= userActivityTime
;
2615 lastActivityTime
= userBecameInactiveTime
;
2618 // Ignore any lastActivityTime that predates the last system wake.
2619 // The goal is to avoid a sudden idle sleep right after a dark wake
2620 // due to sleepDelay=0 computed below. The alternative 60s minimum
2621 // timeout should be large enough to allow dark wake to complete,
2622 // at which point the idle timer will be promptly cancelled.
2623 clock_get_uptime(&now
);
2624 if ((CMP_ABSOLUTETIME(&lastActivityTime
, &gIOLastWakeAbsTime
) >= 0) &&
2625 (CMP_ABSOLUTETIME(&now
, &lastActivityTime
) > 0)) {
2626 SUB_ABSOLUTETIME(&now
, &lastActivityTime
);
2627 absolutetime_to_nanoseconds(now
, &nanos
);
2628 minutesSinceUserInactive
= nanos
/ (60000000000ULL);
2630 if (minutesSinceUserInactive
>= sleepSlider
) {
2633 sleepDelay
= sleepSlider
- minutesSinceUserInactive
;
2636 DLOG("ignoring lastActivityTime 0x%qx, now 0x%qx, wake 0x%qx\n",
2637 lastActivityTime
, now
, gIOLastWakeAbsTime
);
2638 sleepDelay
= sleepSlider
;
2641 DLOG("user inactive %u min, time to idle sleep %u min\n",
2642 minutesSinceUserInactive
, sleepDelay
);
2644 return sleepDelay
* 60;
2647 //******************************************************************************
2648 // setQuickSpinDownTimeout
2650 //******************************************************************************
2653 IOPMrootDomain::setQuickSpinDownTimeout( void )
2657 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
2660 //******************************************************************************
2661 // restoreUserSpinDownTimeout
2663 //******************************************************************************
2666 IOPMrootDomain::restoreUserSpinDownTimeout( void )
2670 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
2673 //******************************************************************************
2676 //******************************************************************************
2680 IOPMrootDomain::sleepSystem( void )
2682 return sleepSystemOptions(NULL
);
2687 IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
2689 OSObject
*obj
= NULL
;
2690 OSString
*reason
= NULL
;
2691 /* sleepSystem is a public function, and may be called by any kernel driver.
2692 * And that's bad - drivers should sleep the system by calling
2693 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2695 * Note that user space app calls to IOPMSleepSystem() will also travel
2696 * this code path and thus be correctly identified as software sleeps.
2699 if (options
&& options
->getObject("OSSwitch")) {
2700 // Log specific sleep cause for OS Switch hibernation
2701 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate
);
2704 if (options
&& (obj
= options
->getObject("Sleep Reason"))) {
2705 reason
= OSDynamicCast(OSString
, obj
);
2706 if (reason
&& reason
->isEqualTo(kIOPMDarkWakeThermalEmergencyKey
)) {
2707 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
2709 if (reason
&& reason
->isEqualTo(kIOPMNotificationWakeExitKey
)) {
2710 return privateSleepSystem(kIOPMSleepReasonNotificationWakeExit
);
2714 return privateSleepSystem( kIOPMSleepReasonSoftware
);
2719 IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
2721 /* Called from both gated and non-gated context */
2723 if (!checkSystemSleepEnabled() || !pmPowerStateQueue
) {
2724 return kIOReturnNotPermitted
;
2727 pmPowerStateQueue
->submitPowerEvent(
2728 kPowerEventPolicyStimulus
,
2729 (void *) kStimulusDemandSystemSleep
,
2732 return kIOReturnSuccess
;
2735 //******************************************************************************
2738 // This overrides powerChangeDone in IOService.
2739 //******************************************************************************
2741 IOPMrootDomain::powerChangeDone( unsigned long previousPowerState
)
2743 #if !__i386__ && !__x86_64__
2744 uint64_t timeSinceReset
= 0;
2747 unsigned long newState
;
2749 clock_usec_t microsecs
;
2750 uint32_t lastDebugWakeSeconds
;
2751 clock_sec_t adjWakeTime
;
2752 IOPMCalendarStruct nowCalendar
;
2755 newState
= getPowerState();
2756 DLOG("PowerChangeDone: %s->%s\n",
2757 getPowerStateString((uint32_t) previousPowerState
), getPowerStateString((uint32_t) getPowerState()));
2759 if (previousPowerState
== newState
) {
2763 notifierThread
= current_thread();
2764 switch (getPowerState()) {
2766 if (kPMCalendarTypeInvalid
!= _aotWakeTimeCalendar
.selector
) {
2769 PEGetUTCTimeOfDay(&secs
, µsecs
);
2772 if ((kIOPMAOTModeRespectTimers
& _aotMode
) && (_calendarWakeAlarmUTC
< _aotWakeTimeUTC
)) {
2773 IOLog("use _calendarWakeAlarmUTC\n");
2774 adjWakeTime
= _calendarWakeAlarmUTC
;
2775 } else if (_aotExit
|| (kIOPMWakeEventAOTExitFlags
& _aotPendingFlags
)) {
2776 IOLog("accelerate _aotWakeTime for exit\n");
2778 } else if (kIOPMDriverAssertionLevelOn
== getPMAssertionLevel(kIOPMDriverAssertionCPUBit
)) {
2779 IOLog("accelerate _aotWakeTime for assertion\n");
2783 IOPMConvertSecondsToCalendar(adjWakeTime
, &_aotWakeTimeCalendar
);
2786 IOPMConvertSecondsToCalendar(secs
, &nowCalendar
);
2787 IOLog("aotSleep at " YMDTF
" sched: " YMDTF
"\n", YMDT(&nowCalendar
), YMDT(&_aotWakeTimeCalendar
));
2789 IOReturn __unused ret
= setMaintenanceWakeCalendar(&_aotWakeTimeCalendar
);
2790 assert(kIOReturnSuccess
== ret
);
2792 if (_aotLastWakeTime
) {
2793 _aotMetrics
->totalTime
+= mach_absolute_time() - _aotLastWakeTime
;
2794 if (_aotMetrics
->sleepCount
&& (_aotMetrics
->sleepCount
<= kIOPMAOTMetricsKernelWakeCountMax
)) {
2795 strlcpy(&_aotMetrics
->kernelWakeReason
[_aotMetrics
->sleepCount
- 1][0],
2797 sizeof(_aotMetrics
->kernelWakeReason
[_aotMetrics
->sleepCount
]));
2800 _aotPendingFlags
&= ~kIOPMWakeEventAOTPerCycleFlags
;
2801 if (_aotTimerScheduled
) {
2802 _aotTimerES
->cancelTimeout();
2803 _aotTimerScheduled
= false;
2805 acceptSystemWakeEvents(kAcceptSystemWakeEvents_Enable
);
2807 // re-enable this timer for next sleep
2808 cancelIdleSleepTimer();
2810 if (clamshellExists
) {
2811 #if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
2812 if (gClamshellFlags
& kClamshell_WAR_58009435
) {
2813 // Disable clamshell sleep until system has completed full wake.
2814 // This prevents a system sleep request (due to a clamshell close)
2815 // from being queued until the end of system full wake - even if
2816 // other clamshell disable bits outside of our control is wrong.
2817 setClamShellSleepDisable(true, kClamshellSleepDisableInternal
);
2821 // Log the last known clamshell state before system sleep
2822 DLOG("clamshell closed %d, disabled %d/%x, desktopMode %d, ac %d\n",
2823 clamshellClosed
, clamshellDisabled
, clamshellSleepDisableMask
,
2824 desktopMode
, acAdaptorConnected
);
2827 clock_get_calendar_absolute_and_microtime(&secs
, µsecs
, &now
);
2829 gIOLastSleepTime
.tv_sec
= secs
;
2830 gIOLastSleepTime
.tv_usec
= microsecs
;
2831 if (!_aotLastWakeTime
) {
2832 gIOLastUserSleepTime
= gIOLastSleepTime
;
2835 gIOLastWakeTime
.tv_sec
= 0;
2836 gIOLastWakeTime
.tv_usec
= 0;
2837 gIOLastSleepAbsTime
= now
;
2839 if (wake2DarkwakeDelay
&& sleepDelaysReport
) {
2840 clock_sec_t wake2DarkwakeSecs
, darkwake2SleepSecs
;
2841 // Update 'wake2DarkwakeDelay' histogram if this is a fullwake->sleep transition
2843 SUB_ABSOLUTETIME(&now
, &ts_sleepStart
);
2844 absolutetime_to_microtime(now
, &darkwake2SleepSecs
, µsecs
);
2845 absolutetime_to_microtime(wake2DarkwakeDelay
, &wake2DarkwakeSecs
, µsecs
);
2846 HISTREPORT_TALLYVALUE(sleepDelaysReport
,
2847 (int64_t)(wake2DarkwakeSecs
+ darkwake2SleepSecs
));
2849 DLOG("Updated sleepDelaysReport %lu %lu\n", (unsigned long)wake2DarkwakeSecs
, (unsigned long)darkwake2SleepSecs
);
2850 wake2DarkwakeDelay
= 0;
2853 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
2855 IOHibernateSystemHasSlept();
2857 evaluateSystemSleepPolicyFinal();
2859 LOG("System Sleep\n");
2861 if (thermalWarningState
) {
2862 OSSharedPtr
<const OSSymbol
> event
= OSSymbol::withCString(kIOPMThermalLevelWarningKey
);
2864 systemPowerEventOccurred(event
.get(), kIOPMThermalLevelUnknown
);
2867 assertOnWakeSecs
= 0;
2868 lowBatteryCondition
= false;
2869 thermalEmergencyState
= false;
2871 #if DEVELOPMENT || DEBUG
2872 extern int g_should_log_clock_adjustments
;
2873 if (g_should_log_clock_adjustments
) {
2874 clock_sec_t secs
= 0;
2875 clock_usec_t microsecs
= 0;
2876 uint64_t now_b
= mach_absolute_time();
2880 PEGetUTCTimeOfDay(&secs
, µsecs
);
2882 uint64_t now_a
= mach_absolute_time();
2883 os_log(OS_LOG_DEFAULT
, "%s PMU before going to sleep %lu s %d u %llu abs_b_PEG %llu abs_a_PEG \n",
2884 __func__
, (unsigned long)secs
, microsecs
, now_b
, now_a
);
2888 getPlatform()->sleepKernel();
2890 // The CPU(s) are off at this point,
2891 // Code will resume execution here upon wake.
2893 clock_get_uptime(&gIOLastWakeAbsTime
);
2894 IOLog("gIOLastWakeAbsTime: %lld\n", gIOLastWakeAbsTime
);
2895 _highestCapability
= 0;
2898 IOHibernateSystemWake();
2901 // sleep transition complete
2902 gSleepOrShutdownPending
= 0;
2904 // trip the reset of the calendar clock
2905 clock_wakeup_calendar();
2906 clock_get_calendar_microtime(&secs
, µsecs
);
2907 gIOLastWakeTime
.tv_sec
= secs
;
2908 gIOLastWakeTime
.tv_usec
= microsecs
;
2911 if (_aotWakeTimeCalendar
.selector
!= kPMCalendarTypeInvalid
) {
2912 _aotWakeTimeCalendar
.selector
= kPMCalendarTypeInvalid
;
2915 PEGetUTCTimeOfDay(&secs
, µsecs
);
2916 IOPMConvertSecondsToCalendar(secs
, &nowCalendar
);
2917 IOLog("aotWake at " YMDTF
" sched: " YMDTF
"\n", YMDT(&nowCalendar
), YMDT(&_aotWakeTimeCalendar
));
2918 _aotMetrics
->sleepCount
++;
2919 _aotLastWakeTime
= gIOLastWakeAbsTime
;
2920 if (_aotMetrics
->sleepCount
<= kIOPMAOTMetricsKernelWakeCountMax
) {
2921 _aotMetrics
->kernelSleepTime
[_aotMetrics
->sleepCount
- 1]
2922 = (((uint64_t) gIOLastSleepTime
.tv_sec
) << 10) + (gIOLastSleepTime
.tv_usec
/ 1000);
2923 _aotMetrics
->kernelWakeTime
[_aotMetrics
->sleepCount
- 1]
2924 = (((uint64_t) gIOLastWakeTime
.tv_sec
) << 10) + (gIOLastWakeTime
.tv_usec
/ 1000);
2928 if (_aotWakeTimeUTC
<= secs
) {
2929 _aotTestTime
= _aotTestTime
+ _aotTestInterval
;
2931 setWakeTime(_aotTestTime
);
2936 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
2939 lastSleepReason
= 0;
2941 lastDebugWakeSeconds
= _debugWakeSeconds
;
2942 _debugWakeSeconds
= 0;
2943 _scheduledAlarmMask
= 0;
2944 _nextScheduledAlarmType
= NULL
;
2946 darkWakeExit
= false;
2947 darkWakePowerClamped
= false;
2948 darkWakePostTickle
= false;
2949 darkWakeHibernateError
= false;
2950 darkWakeToSleepASAP
= true;
2951 darkWakeLogClamp
= true;
2952 sleepTimerMaintenance
= false;
2953 sleepToStandby
= false;
2954 wranglerTickled
= false;
2955 userWasActive
= false;
2956 isRTCAlarmWake
= false;
2957 clamshellIgnoreClose
= false;
2958 fullWakeReason
= kFullWakeReasonNone
;
2960 #if defined(__i386__) || defined(__x86_64__)
2961 kdebugTrace(kPMLogSystemWake
, 0, 0, 0);
2963 OSSharedPtr
<OSObject
> wakeTypeProp
= copyProperty(kIOPMRootDomainWakeTypeKey
);
2964 OSSharedPtr
<OSObject
> wakeReasonProp
= copyProperty(kIOPMRootDomainWakeReasonKey
);
2965 OSString
* wakeType
= OSDynamicCast(OSString
, wakeTypeProp
.get());
2966 OSString
* wakeReason
= OSDynamicCast(OSString
, wakeReasonProp
.get());
2968 if (wakeReason
&& (wakeReason
->getLength() >= 2) &&
2969 gWakeReasonString
[0] == '\0') {
2971 // Until the platform driver can claim its wake reasons
2972 strlcat(gWakeReasonString
, wakeReason
->getCStringNoCopy(),
2973 sizeof(gWakeReasonString
));
2977 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
)) {
2978 lowBatteryCondition
= true;
2979 darkWakeMaintenance
= true;
2982 OSSharedPtr
<OSObject
> hibOptionsProp
= copyProperty(kIOHibernateOptionsKey
);
2983 OSNumber
* hibOptions
= OSDynamicCast( OSNumber
, hibOptionsProp
.get());
2984 if (hibernateAborted
|| ((hibOptions
&&
2985 !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
)))) {
2986 // Hibernate aborted, or EFI brought up graphics
2987 darkWakeExit
= true;
2988 if (hibernateAborted
) {
2989 DLOG("Hibernation aborted\n");
2991 DLOG("EFI brought up graphics. Going to full wake. HibOptions: 0x%x\n", hibOptions
->unsigned32BitValue());
2996 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeUser
) ||
2997 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
))) {
2998 // User wake or RTC alarm
2999 darkWakeExit
= true;
3000 if (wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
)) {
3001 isRTCAlarmWake
= true;
3003 } else if (wakeType
&&
3004 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
)) {
3005 // SMC standby timer trumps SleepX
3006 darkWakeMaintenance
= true;
3007 sleepTimerMaintenance
= true;
3008 } else if ((lastDebugWakeSeconds
!= 0) &&
3009 ((gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
) == 0)) {
3010 // SleepX before maintenance
3011 darkWakeExit
= true;
3012 } else if (wakeType
&&
3013 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
)) {
3014 darkWakeMaintenance
= true;
3015 } else if (wakeType
&&
3016 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepService
)) {
3017 darkWakeMaintenance
= true;
3018 darkWakeSleepService
= true;
3020 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) {
3021 sleepToStandby
= true;
3024 } else if (wakeType
&&
3025 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeHibernateError
)) {
3026 darkWakeMaintenance
= true;
3027 darkWakeHibernateError
= true;
3029 // Unidentified wake source, resume to full wake if debug
3030 // alarm is pending.
3032 if (lastDebugWakeSeconds
&&
3033 (!wakeReason
|| wakeReason
->isEqualTo(""))) {
3034 darkWakeExit
= true;
3040 darkWakeToSleepASAP
= false;
3041 fullWakeReason
= kFullWakeReasonLocalUser
;
3043 } else if (displayPowerOnRequested
&& checkSystemCanSustainFullWake()) {
3044 handleSetDisplayPowerOn(true);
3045 } else if (!darkWakeMaintenance
) {
3046 // Early/late tickle for non-maintenance wake.
3047 if ((gDarkWakeFlags
& kDarkWakeFlagPromotionMask
) != kDarkWakeFlagPromotionNone
) {
3048 darkWakePostTickle
= true;
3051 #else /* !__i386__ && !__x86_64__ */
3052 timeSinceReset
= ml_get_time_since_reset();
3053 kdebugTrace(kPMLogSystemWake
, 0, (uintptr_t)(timeSinceReset
>> 32), (uintptr_t) timeSinceReset
);
3055 if ((gDarkWakeFlags
& kDarkWakeFlagPromotionMask
) == kDarkWakeFlagPromotionEarly
) {
3056 wranglerTickled
= true;
3057 fullWakeReason
= kFullWakeReasonLocalUser
;
3058 requestUserActive(this, "Full wake on dark wake promotion boot-arg");
3059 } else if ((lastDebugWakeSeconds
!= 0) && !(gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
)) {
3060 isRTCAlarmWake
= true;
3061 fullWakeReason
= kFullWakeReasonLocalUser
;
3062 requestUserActive(this, "RTC debug alarm");
3065 OSSharedPtr
<OSObject
> hibOptionsProp
= copyProperty(kIOHibernateOptionsKey
);
3066 OSNumber
* hibOptions
= OSDynamicCast(OSNumber
, hibOptionsProp
.get());
3067 if (hibOptions
&& !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
)) {
3068 fullWakeReason
= kFullWakeReasonLocalUser
;
3069 requestUserActive(this, "hibernate user wake");
3074 // stay awake for at least 30 seconds
3075 startIdleSleepTimer(30);
3079 thread_call_enter(updateConsoleUsersEntry
);
3081 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonWake
);
3084 #if !__i386__ && !__x86_64__
3088 DLOG("Force re-evaluating aggressiveness\n");
3089 /* Force re-evaluate the aggressiveness values to set appropriate idle sleep timer */
3090 pmPowerStateQueue
->submitPowerEvent(
3091 kPowerEventPolicyStimulus
,
3092 (void *) kStimulusNoIdleSleepPreventers
);
3094 // After changing to ON_STATE, invalidate any previously queued
3095 // request to change to a state less than ON_STATE. This isn't
3096 // necessary for AOT_STATE or if the device has only one running
3097 // state since the changePowerStateToPriv() issued at the tail
3098 // end of SLEEP_STATE case should take care of that.
3099 if (getPowerState() == ON_STATE
) {
3100 changePowerStateWithTagToPriv(ON_STATE
, kCPSReasonWake
);
3104 #endif /* !__i386__ && !__x86_64__ */
3106 notifierThread
= NULL
;
3109 //******************************************************************************
3110 // requestPowerDomainState
3112 // Extend implementation in IOService. Running on PM work loop thread.
3113 //******************************************************************************
3116 IOPMrootDomain::requestPowerDomainState(
3117 IOPMPowerFlags childDesire
,
3118 IOPowerConnection
* childConnection
,
3119 unsigned long specification
)
3121 // Idle and system sleep prevention flags affects driver desire.
3122 // Children desire are irrelevant so they are cleared.
3124 return super::requestPowerDomainState(0, childConnection
, specification
);
3129 makeSleepPreventersListLog(const OSSharedPtr
<OSSet
> &preventers
, char *buf
, size_t buf_size
)
3131 if (!preventers
->getCount()) {
3135 char *buf_iter
= buf
+ strlen(buf
);
3136 char *buf_end
= buf
+ buf_size
;
3138 OSSharedPtr
<OSCollectionIterator
> iterator
= OSCollectionIterator::withCollection(preventers
.get());
3139 OSObject
*obj
= NULL
;
3141 while ((obj
= iterator
->getNextObject())) {
3142 IOService
*srv
= OSDynamicCast(IOService
, obj
);
3143 if (buf_iter
< buf_end
) {
3144 buf_iter
+= snprintf(buf_iter
, buf_end
- buf_iter
, " %s", srv
->getName());
3146 DLOG("Print buffer exhausted for sleep preventers list\n");
3152 //******************************************************************************
3153 // updatePreventIdleSleepList
3155 // Called by IOService on PM work loop.
3156 // Returns true if PM policy recognized the driver's desire to prevent idle
3157 // sleep and updated the list of idle sleep preventers. Returns false otherwise
3158 //******************************************************************************
3161 IOPMrootDomain::updatePreventIdleSleepList(
3162 IOService
* service
, bool addNotRemove
)
3164 unsigned int oldCount
;
3166 oldCount
= idleSleepPreventersCount();
3167 return updatePreventIdleSleepListInternal(service
, addNotRemove
, oldCount
);
3171 IOPMrootDomain::updatePreventIdleSleepListInternal(
3172 IOService
* service
, bool addNotRemove
, unsigned int oldCount
)
3174 unsigned int newCount
;
3178 #if defined(XNU_TARGET_OS_OSX)
3179 // Only the display wrangler and no-idle-sleep kernel assertions
3180 // can prevent idle sleep. The kIOPMPreventIdleSleep capability flag
3181 // reported by drivers in their power state table is ignored.
3182 if (service
&& (service
!= wrangler
) && (service
!= this)) {
3189 preventIdleSleepList
->setObject(service
);
3190 DLOG("Added %s to idle sleep preventers list (Total %u)\n",
3191 service
->getName(), preventIdleSleepList
->getCount());
3192 } else if (preventIdleSleepList
->member(service
)) {
3193 preventIdleSleepList
->removeObject(service
);
3194 DLOG("Removed %s from idle sleep preventers list (Total %u)\n",
3195 service
->getName(), preventIdleSleepList
->getCount());
3198 if (preventIdleSleepList
->getCount()) {
3199 char buf
[256] = "Idle Sleep Preventers:";
3200 makeSleepPreventersListLog(preventIdleSleepList
, buf
, sizeof(buf
));
3205 newCount
= idleSleepPreventersCount();
3207 if ((oldCount
== 0) && (newCount
!= 0)) {
3208 // Driver added to empty prevent list.
3209 // Update the driver desire to prevent idle sleep.
3210 // Driver desire does not prevent demand sleep.
3212 changePowerStateWithTagTo(getRUN_STATE(), kCPSReasonIdleSleepPrevent
);
3213 } else if ((oldCount
!= 0) && (newCount
== 0)) {
3214 // Last driver removed from prevent list.
3215 // Drop the driver clamp to allow idle sleep.
3217 changePowerStateWithTagTo(SLEEP_STATE
, kCPSReasonIdleSleepAllow
);
3218 evaluatePolicy( kStimulusNoIdleSleepPreventers
);
3220 messageClient(kIOPMMessageIdleSleepPreventers
, systemCapabilityNotifier
.get(),
3221 &newCount
, sizeof(newCount
));
3223 #if defined(XNU_TARGET_OS_OSX)
3224 if (addNotRemove
&& (service
== wrangler
) && !checkSystemCanSustainFullWake()) {
3225 DLOG("Cannot cancel idle sleep\n");
3226 return false; // do not idle-cancel
3233 //******************************************************************************
3235 //******************************************************************************
3238 IOPMrootDomain::startSpinDump(uint32_t spindumpKind
)
3240 messageClients(kIOPMMessageLaunchBootSpinDump
, (void *)(uintptr_t)spindumpKind
);
3243 //******************************************************************************
3244 // preventSystemSleepListUpdate
3246 // Called by IOService on PM work loop.
3247 //******************************************************************************
3250 IOPMrootDomain::updatePreventSystemSleepList(
3251 IOService
* service
, bool addNotRemove
)
3253 unsigned int oldCount
, newCount
;
3256 if (this == service
) {
3260 oldCount
= preventSystemSleepList
->getCount();
3262 preventSystemSleepList
->setObject(service
);
3263 DLOG("Added %s to system sleep preventers list (Total %u)\n",
3264 service
->getName(), preventSystemSleepList
->getCount());
3265 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
3267 clock_usec_t microsecs
;
3268 clock_get_uptime(&now
);
3269 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
3270 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
3271 if (assertOnWakeReport
) {
3272 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
3273 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
3276 } else if (preventSystemSleepList
->member(service
)) {
3277 preventSystemSleepList
->removeObject(service
);
3278 DLOG("Removed %s from system sleep preventers list (Total %u)\n",
3279 service
->getName(), preventSystemSleepList
->getCount());
3281 if ((oldCount
!= 0) && (preventSystemSleepList
->getCount() == 0)) {
3282 // Lost all system sleep preventers.
3283 // Send stimulus if system sleep was blocked, and is in dark wake.
3284 evaluatePolicy( kStimulusDarkWakeEvaluate
);
3288 newCount
= preventSystemSleepList
->getCount();
3290 char buf
[256] = "System Sleep Preventers:";
3291 makeSleepPreventersListLog(preventSystemSleepList
, buf
, sizeof(buf
));
3295 messageClient(kIOPMMessageSystemSleepPreventers
, systemCapabilityNotifier
.get(),
3296 &newCount
, sizeof(newCount
));
3300 IOPMrootDomain::copySleepPreventersList(OSArray
**idleSleepList
, OSArray
**systemSleepList
)
3302 OSSharedPtr
<OSCollectionIterator
> iterator
;
3303 OSObject
*object
= NULL
;
3304 OSSharedPtr
<OSArray
> array
;
3306 if (!gIOPMWorkLoop
->inGate()) {
3307 gIOPMWorkLoop
->runAction(
3308 OSMemberFunctionCast(IOWorkLoop::Action
, this,
3309 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersList
),
3310 this, (void *)idleSleepList
, (void *)systemSleepList
);
3314 if (idleSleepList
&& preventIdleSleepList
&& (preventIdleSleepList
->getCount() != 0)) {
3315 iterator
= OSCollectionIterator::withCollection(preventIdleSleepList
.get());
3316 array
= OSArray::withCapacity(5);
3318 if (iterator
&& array
) {
3319 while ((object
= iterator
->getNextObject())) {
3320 IOService
*service
= OSDynamicCast(IOService
, object
);
3322 OSSharedPtr
<const OSSymbol
> name
= service
->copyName();
3324 array
->setObject(name
.get());
3329 *idleSleepList
= array
.detach();
3332 if (systemSleepList
&& preventSystemSleepList
&& (preventSystemSleepList
->getCount() != 0)) {
3333 iterator
= OSCollectionIterator::withCollection(preventSystemSleepList
.get());
3334 array
= OSArray::withCapacity(5);
3336 if (iterator
&& array
) {
3337 while ((object
= iterator
->getNextObject())) {
3338 IOService
*service
= OSDynamicCast(IOService
, object
);
3340 OSSharedPtr
<const OSSymbol
> name
= service
->copyName();
3342 array
->setObject(name
.get());
3347 *systemSleepList
= array
.detach();
3352 IOPMrootDomain::copySleepPreventersListWithID(OSArray
**idleSleepList
, OSArray
**systemSleepList
)
3354 OSSharedPtr
<OSCollectionIterator
> iterator
;
3355 OSObject
*object
= NULL
;
3356 OSSharedPtr
<OSArray
> array
;
3358 if (!gIOPMWorkLoop
->inGate()) {
3359 gIOPMWorkLoop
->runAction(
3360 OSMemberFunctionCast(IOWorkLoop::Action
, this,
3361 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersListWithID
),
3362 this, (void *)idleSleepList
, (void *)systemSleepList
);
3366 if (idleSleepList
&& preventIdleSleepList
&& (preventIdleSleepList
->getCount() != 0)) {
3367 iterator
= OSCollectionIterator::withCollection(preventIdleSleepList
.get());
3368 array
= OSArray::withCapacity(5);
3370 if (iterator
&& array
) {
3371 while ((object
= iterator
->getNextObject())) {
3372 IOService
*service
= OSDynamicCast(IOService
, object
);
3374 OSSharedPtr
<OSDictionary
> dict
= OSDictionary::withCapacity(2);
3375 OSSharedPtr
<const OSSymbol
> name
= service
->copyName();
3376 OSSharedPtr
<OSNumber
> id
= OSNumber::withNumber(service
->getRegistryEntryID(), 64);
3377 if (dict
&& name
&& id
) {
3378 dict
->setObject(kIOPMDriverAssertionRegistryEntryIDKey
, id
.get());
3379 dict
->setObject(kIOPMDriverAssertionOwnerStringKey
, name
.get());
3380 array
->setObject(dict
.get());
3385 *idleSleepList
= array
.detach();
3388 if (systemSleepList
&& preventSystemSleepList
&& (preventSystemSleepList
->getCount() != 0)) {
3389 iterator
= OSCollectionIterator::withCollection(preventSystemSleepList
.get());
3390 array
= OSArray::withCapacity(5);
3392 if (iterator
&& array
) {
3393 while ((object
= iterator
->getNextObject())) {
3394 IOService
*service
= OSDynamicCast(IOService
, object
);
3396 OSSharedPtr
<OSDictionary
> dict
= OSDictionary::withCapacity(2);
3397 OSSharedPtr
<const OSSymbol
> name
= service
->copyName();
3398 OSSharedPtr
<OSNumber
> id
= OSNumber::withNumber(service
->getRegistryEntryID(), 64);
3399 if (dict
&& name
&& id
) {
3400 dict
->setObject(kIOPMDriverAssertionRegistryEntryIDKey
, id
.get());
3401 dict
->setObject(kIOPMDriverAssertionOwnerStringKey
, name
.get());
3402 array
->setObject(dict
.get());
3407 *systemSleepList
= array
.detach();
3411 //******************************************************************************
3414 // Override the superclass implementation to send a different message type.
3415 //******************************************************************************
3418 IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
3420 DLOG("tellChangeDown %s->%s\n",
3421 getPowerStateString((uint32_t) getPowerState()), getPowerStateString((uint32_t) stateNum
));
3423 if (SLEEP_STATE
== stateNum
) {
3424 // Legacy apps were already told in the full->dark transition
3425 if (!ignoreTellChangeDown
) {
3426 tracePoint( kIOPMTracePointSleepApplications
);
3428 tracePoint( kIOPMTracePointSleepPriorityClients
);
3432 if (!ignoreTellChangeDown
) {
3433 userActivityAtSleep
= userActivityCount
;
3434 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
3436 if (SLEEP_STATE
== stateNum
) {
3437 hibernateAborted
= false;
3439 // Direct callout into OSKext so it can disable kext unloads
3440 // during sleep/wake to prevent deadlocks.
3441 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
3443 IOService::updateConsoleUsers(NULL
, kIOMessageSystemWillSleep
);
3445 // Two change downs are sent by IOServicePM. Ignore the 2nd.
3446 // But tellClientsWithResponse() must be called for both.
3447 ignoreTellChangeDown
= true;
3451 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
3454 //******************************************************************************
3457 // Override the superclass implementation to send a different message type.
3458 // This must be idle sleep since we don't ask during any other power change.
3459 //******************************************************************************
3462 IOPMrootDomain::askChangeDown( unsigned long stateNum
)
3464 DLOG("askChangeDown %s->%s\n",
3465 getPowerStateString((uint32_t) getPowerState()), getPowerStateString((uint32_t) stateNum
));
3467 // Don't log for dark wake entry
3468 if (kSystemTransitionSleep
== _systemTransitionType
) {
3469 tracePoint( kIOPMTracePointSleepApplications
);
3472 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
3475 //******************************************************************************
3476 // askChangeDownDone
3478 // An opportunity for root domain to cancel the power transition,
3479 // possibily due to an assertion created by powerd in response to
3480 // kIOMessageCanSystemSleep.
3483 // full -> dark wake transition
3484 // 1. Notify apps and powerd with kIOMessageCanSystemSleep
3485 // 2. askChangeDownDone()
3486 // dark -> sleep transition
3487 // 1. Notify powerd with kIOMessageCanSystemSleep
3488 // 2. askChangeDownDone()
3491 // full -> dark wake transition
3492 // 1. Notify powerd with kIOMessageCanSystemSleep
3493 // 2. askChangeDownDone()
3494 // dark -> sleep transition
3495 // 1. Notify powerd with kIOMessageCanSystemSleep
3496 // 2. askChangeDownDone()
3497 //******************************************************************************
3500 IOPMrootDomain::askChangeDownDone(
3501 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
3503 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
3504 *inOutChangeFlags
, *cancel
,
3505 _systemTransitionType
,
3506 _currentCapability
, _pendingCapability
);
3508 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
)) {
3509 // Dark->Sleep transition.
3510 // Check if there are any deny sleep assertions.
3511 // lastSleepReason already set by handleOurPowerChangeStart()
3513 if (!checkSystemCanSleep(lastSleepReason
)) {
3514 // Cancel dark wake to sleep transition.
3515 // Must re-scan assertions upon entering dark wake.
3518 DLOG("cancel dark->sleep\n");
3520 if (_aotMode
&& (kPMCalendarTypeInvalid
!= _aotWakeTimeCalendar
.selector
)) {
3521 uint64_t now
= mach_continuous_time();
3522 if (((now
+ _aotWakePreWindow
) >= _aotWakeTimeContinuous
)
3523 && (now
< (_aotWakeTimeContinuous
+ _aotWakePostWindow
))) {
3525 IOLog("AOT wake window cancel: %qd, %qd\n", now
, _aotWakeTimeContinuous
);
3531 //******************************************************************************
3532 // systemDidNotSleep
3534 // Work common to both canceled or aborted sleep.
3535 //******************************************************************************
3538 IOPMrootDomain::systemDidNotSleep( void )
3540 // reset console lock state
3541 thread_call_enter(updateConsoleUsersEntry
);
3543 if (idleSleepEnabled
) {
3545 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
3546 startIdleSleepTimer(kIdleSleepRetryInterval
);
3548 startIdleSleepTimer(idleSeconds
);
3550 } else if (!userIsActive
) {
3551 // Manually start the idle sleep timer besides waiting for
3552 // the user to become inactive.
3553 startIdleSleepTimer(kIdleSleepRetryInterval
);
3557 preventTransitionToUserActive(false);
3558 IOService::setAdvisoryTickleEnable( true );
3560 // After idle revert and cancel, send a did-change message to powerd
3561 // to balance the previous will-change message. Kernel clients do not
3562 // need this since sleep cannot be canceled once they are notified.
3564 if (toldPowerdCapWillChange
&& systemCapabilityNotifier
&&
3565 (_pendingCapability
!= _currentCapability
) &&
3566 ((_systemMessageClientMask
& kSystemMessageClientPowerd
) != 0)) {
3567 // Differs from a real capability gain change where notifyRef != 0,
3568 // but it is zero here since no response is expected.
3570 IOPMSystemCapabilityChangeParameters params
;
3572 bzero(¶ms
, sizeof(params
));
3573 params
.fromCapabilities
= _pendingCapability
;
3574 params
.toCapabilities
= _currentCapability
;
3575 params
.changeFlags
= kIOPMSystemCapabilityDidChange
;
3577 DLOG("MESG cap %x->%x did change\n",
3578 params
.fromCapabilities
, params
.toCapabilities
);
3579 messageClient(kIOMessageSystemCapabilityChange
, systemCapabilityNotifier
.get(),
3580 ¶ms
, sizeof(params
));
3584 //******************************************************************************
3587 // Notify registered applications and kernel clients that we are not dropping
3590 // We override the superclass implementation so we can send a different message
3591 // type to the client or application being notified.
3593 // This must be a vetoed idle sleep, since no other power change can be vetoed.
3594 //******************************************************************************
3597 IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
3599 DLOG("tellNoChangeDown %s->%s\n",
3600 getPowerStateString((uint32_t) getPowerState()), getPowerStateString((uint32_t) stateNum
));
3602 // Sleep canceled, clear the sleep trace point.
3603 tracePoint(kIOPMTracePointSystemUp
);
3605 systemDidNotSleep();
3606 return tellClients( kIOMessageSystemWillNotSleep
);
3609 //******************************************************************************
3612 // Notify registered applications and kernel clients that we are raising power.
3614 // We override the superclass implementation so we can send a different message
3615 // type to the client or application being notified.
3616 //******************************************************************************
3619 IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
3621 DLOG("tellChangeUp %s->%s\n",
3622 getPowerStateString((uint32_t) getPowerState()), getPowerStateString((uint32_t) stateNum
));
3624 ignoreTellChangeDown
= false;
3626 if (stateNum
== ON_STATE
) {
3627 // Direct callout into OSKext so it can disable kext unloads
3628 // during sleep/wake to prevent deadlocks.
3629 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
3631 // Notify platform that sleep was cancelled or resumed.
3632 getPlatform()->callPlatformFunction(
3633 sleepMessagePEFunction
.get(), false,
3634 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
3637 if (getPowerState() == ON_STATE
) {
3638 // Sleep was cancelled by idle cancel or revert
3639 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
)) {
3640 // rdar://problem/50363791
3641 // If system is in dark wake and sleep is cancelled, do not
3642 // send SystemWillPowerOn/HasPoweredOn messages to kernel
3643 // priority clients. They haven't yet seen a SystemWillSleep
3644 // message before the cancellation. So make sure the kernel
3645 // client bit is cleared in _systemMessageClientMask before
3646 // invoking the tellClients() below. This bit may have been
3647 // set by handleOurPowerChangeStart() anticipating a successful
3648 // sleep and setting the filter mask ahead of time allows the
3649 // SystemWillSleep message to go through.
3650 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
3653 systemDidNotSleep();
3654 tellClients( kIOMessageSystemWillPowerOn
);
3657 tracePoint( kIOPMTracePointWakeApplications
);
3658 tellClients( kIOMessageSystemHasPoweredOn
);
3662 #define CAP_WILL_CHANGE_TO_OFF(params, flag) \
3663 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
3664 ((params)->fromCapabilities & (flag)) && \
3665 (((params)->toCapabilities & (flag)) == 0))
3667 #define CAP_DID_CHANGE_TO_ON(params, flag) \
3668 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
3669 ((params)->toCapabilities & (flag)) && \
3670 (((params)->fromCapabilities & (flag)) == 0))
3672 #define CAP_DID_CHANGE_TO_OFF(params, flag) \
3673 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
3674 ((params)->fromCapabilities & (flag)) && \
3675 (((params)->toCapabilities & (flag)) == 0))
3677 #define CAP_WILL_CHANGE_TO_ON(params, flag) \
3678 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
3679 ((params)->toCapabilities & (flag)) && \
3680 (((params)->fromCapabilities & (flag)) == 0))
3682 //******************************************************************************
3683 // sysPowerDownHandler
3685 // Perform a vfs sync before system sleep.
3686 //******************************************************************************
3689 IOPMrootDomain::sysPowerDownHandler(
3690 void * target
, void * refCon
,
3691 UInt32 messageType
, IOService
* service
,
3692 void * messageArgs
, vm_size_t argSize
)
3694 static UInt32 lastSystemMessageType
= 0;
3697 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
3699 // rdar://problem/50363791
3700 // Sanity check to make sure the SystemWill/Has message types are
3701 // received in the expected order for all kernel priority clients.
3702 if (messageType
== kIOMessageSystemWillSleep
||
3703 messageType
== kIOMessageSystemWillPowerOn
||
3704 messageType
== kIOMessageSystemHasPoweredOn
) {
3705 switch (messageType
) {
3706 case kIOMessageSystemWillPowerOn
:
3707 assert(lastSystemMessageType
== kIOMessageSystemWillSleep
);
3709 case kIOMessageSystemHasPoweredOn
:
3710 assert(lastSystemMessageType
== kIOMessageSystemWillPowerOn
);
3714 lastSystemMessageType
= messageType
;
3718 return kIOReturnUnsupported
;
3721 if (messageType
== kIOMessageSystemCapabilityChange
) {
3722 IOPMSystemCapabilityChangeParameters
* params
=
3723 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
3725 // Interested applications have been notified of an impending power
3726 // change and have acked (when applicable).
3727 // This is our chance to save whatever state we can before powering
3729 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
3732 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
3733 params
->fromCapabilities
, params
->toCapabilities
,
3734 params
->changeFlags
);
3736 if (CAP_WILL_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityCPU
)) {
3737 // We will ack within 20 seconds
3738 params
->maxWaitForReply
= 20 * 1000 * 1000;
3741 gRootDomain
->evaluateSystemSleepPolicyEarly();
3743 // add in time we could spend freeing pages
3744 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
) {
3745 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
3747 DLOG("sysPowerDownHandler max wait %d s\n",
3748 (int) (params
->maxWaitForReply
/ 1000 / 1000));
3751 // Notify platform that sleep has begun, after the early
3752 // sleep policy evaluation.
3753 getPlatform()->callPlatformFunction(
3754 sleepMessagePEFunction
.get(), false,
3755 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
3758 if (!OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
)) {
3759 // Purposely delay the ack and hope that shutdown occurs quickly.
3760 // Another option is not to schedule the thread and wait for
3762 AbsoluteTime deadline
;
3763 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
3764 thread_call_enter1_delayed(
3765 gRootDomain
->diskSyncCalloutEntry
,
3766 (thread_call_param_t
)(uintptr_t) params
->notifyRef
,
3770 gRootDomain
->diskSyncCalloutEntry
,
3771 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3775 else if (CAP_DID_CHANGE_TO_ON(params
, kIOPMSystemCapabilityCPU
)) {
3776 // We will ack within 110 seconds
3777 params
->maxWaitForReply
= 110 * 1000 * 1000;
3780 gRootDomain
->diskSyncCalloutEntry
,
3781 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3784 ret
= kIOReturnSuccess
;
3790 //******************************************************************************
3791 // handleQueueSleepWakeUUID
3793 // Called from IOPMrootDomain when we're initiating a sleep,
3794 // or indirectly from PM configd when PM decides to clear the UUID.
3795 // PM clears the UUID several minutes after successful wake from sleep,
3796 // so that we might associate App spindumps with the immediately previous
3799 // @param obj has a retain on it. We're responsible for releasing that retain.
3800 //******************************************************************************
3803 IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
3805 OSSharedPtr
<OSString
> str
;
3807 if (kOSBooleanFalse
== obj
) {
3808 handlePublishSleepWakeUUID(false);
3810 str
.reset(OSDynamicCast(OSString
, obj
), OSNoRetain
);
3812 // This branch caches the UUID for an upcoming sleep/wake
3813 queuedSleepWakeUUIDString
= str
;
3814 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
3818 //******************************************************************************
3819 // handlePublishSleepWakeUUID
3821 // Called from IOPMrootDomain when we're initiating a sleep,
3822 // or indirectly from PM configd when PM decides to clear the UUID.
3823 // PM clears the UUID several minutes after successful wake from sleep,
3824 // so that we might associate App spindumps with the immediately previous
3826 //******************************************************************************
3829 IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
3834 * Clear the current UUID
3836 if (gSleepWakeUUIDIsSet
) {
3837 DLOG("SleepWake UUID cleared\n");
3839 gSleepWakeUUIDIsSet
= false;
3841 removeProperty(kIOPMSleepWakeUUIDKey
);
3842 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
3846 * Optionally, publish a new UUID
3848 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
3849 OSSharedPtr
<OSString
> publishThisUUID
;
3851 publishThisUUID
= queuedSleepWakeUUIDString
;
3853 if (publishThisUUID
) {
3854 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
.get());
3857 gSleepWakeUUIDIsSet
= true;
3858 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
3860 queuedSleepWakeUUIDString
.reset();
3864 //******************************************************************************
3865 // IOPMGetSleepWakeUUIDKey
3867 // Return the truth value of gSleepWakeUUIDIsSet and optionally copy the key.
3868 // To get the full key -- a C string -- the buffer must large enough for
3869 // the end-of-string character.
3870 // The key is expected to be an UUID string
3871 //******************************************************************************
3874 IOPMCopySleepWakeUUIDKey(char *buffer
, size_t buf_len
)
3876 if (!gSleepWakeUUIDIsSet
) {
3880 if (buffer
!= NULL
) {
3881 OSSharedPtr
<OSString
> string
=
3882 OSDynamicPtrCast
<OSString
>(gRootDomain
->copyProperty(kIOPMSleepWakeUUIDKey
));
3887 strlcpy(buffer
, string
->getCStringNoCopy(), buf_len
);
3894 //******************************************************************************
3895 // lowLatencyAudioNotify
3897 // Used to send an update about low latency audio activity to interested
3898 // clients. To keep the overhead minimal the OSDictionary used here
3899 // is initialized at boot.
3900 //******************************************************************************
3903 IOPMrootDomain::lowLatencyAudioNotify(uint64_t time
, boolean_t state
)
3905 if (lowLatencyAudioNotifierDict
&& lowLatencyAudioNotifyStateSym
&& lowLatencyAudioNotifyTimestampSym
&&
3906 lowLatencyAudioNotifyStateVal
&& lowLatencyAudioNotifyTimestampVal
) {
3907 lowLatencyAudioNotifyTimestampVal
->setValue(time
);
3908 lowLatencyAudioNotifyStateVal
->setValue(state
);
3909 setPMSetting(gIOPMSettingLowLatencyAudioModeKey
.get(), lowLatencyAudioNotifierDict
.get());
3911 DLOG("LowLatencyAudioNotify error\n");
3916 //******************************************************************************
3917 // IOPMrootDomainRTNotifier
3919 // Used by performance controller to update the timestamp and state associated
3920 // with low latency audio activity in the system.
3921 //******************************************************************************
3924 IOPMrootDomainRTNotifier(uint64_t time
, boolean_t state
)
3926 gRootDomain
->lowLatencyAudioNotify(time
, state
);
3930 //******************************************************************************
3931 // initializeBootSessionUUID
3933 // Initialize the boot session uuid at boot up and sets it into registry.
3934 //******************************************************************************
3937 IOPMrootDomain::initializeBootSessionUUID(void)
3940 uuid_string_t new_uuid_string
;
3942 uuid_generate(new_uuid
);
3943 uuid_unparse_upper(new_uuid
, new_uuid_string
);
3944 memcpy(bootsessionuuid_string
, new_uuid_string
, sizeof(uuid_string_t
));
3946 setProperty(kIOPMBootSessionUUIDKey
, new_uuid_string
);
3949 //******************************************************************************
3950 // Root domain uses the private and tagged changePowerState methods for
3951 // tracking and logging purposes.
3952 //******************************************************************************
3954 #define REQUEST_TAG_TO_REASON(x) ((uint16_t)x)
3957 nextRequestTag( IOPMRequestTag tag
)
3959 static SInt16 msb16
= 1;
3960 uint16_t id
= OSAddAtomic16(1, &msb16
);
3961 return ((uint32_t)id
<< 16) | REQUEST_TAG_TO_REASON(tag
);
3964 // TODO: remove this shim function and exported symbol
3966 IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
3968 return changePowerStateWithTagTo(ordinal
, kCPSReasonNone
);
3971 // TODO: remove this shim function and exported symbol
3973 IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
3975 return changePowerStateWithTagToPriv(ordinal
, kCPSReasonNone
);
3979 IOPMrootDomain::changePowerStateWithOverrideTo(
3980 IOPMPowerStateIndex ordinal
, IOPMRequestTag reason
)
3982 uint32_t tag
= nextRequestTag(reason
);
3983 DLOG("%s(%s, %x)\n", __FUNCTION__
, getPowerStateString((uint32_t) ordinal
), tag
);
3985 if ((ordinal
!= ON_STATE
) && (ordinal
!= AOT_STATE
) && (ordinal
!= SLEEP_STATE
)) {
3986 return kIOReturnUnsupported
;
3989 return super::changePowerStateWithOverrideTo(ordinal
, tag
);
3993 IOPMrootDomain::changePowerStateWithTagTo(
3994 IOPMPowerStateIndex ordinal
, IOPMRequestTag reason
)
3996 uint32_t tag
= nextRequestTag(reason
);
3997 DLOG("%s(%s, %x)\n", __FUNCTION__
, getPowerStateString((uint32_t) ordinal
), tag
);
3999 if ((ordinal
!= ON_STATE
) && (ordinal
!= AOT_STATE
) && (ordinal
!= SLEEP_STATE
)) {
4000 return kIOReturnUnsupported
;
4003 return super::changePowerStateWithTagTo(ordinal
, tag
);
4007 IOPMrootDomain::changePowerStateWithTagToPriv(
4008 IOPMPowerStateIndex ordinal
, IOPMRequestTag reason
)
4010 uint32_t tag
= nextRequestTag(reason
);
4011 DLOG("%s(%s, %x)\n", __FUNCTION__
, getPowerStateString((uint32_t) ordinal
), tag
);
4013 if ((ordinal
!= ON_STATE
) && (ordinal
!= AOT_STATE
) && (ordinal
!= SLEEP_STATE
)) {
4014 return kIOReturnUnsupported
;
4017 return super::changePowerStateWithTagToPriv(ordinal
, tag
);
4020 //******************************************************************************
4023 //******************************************************************************
4026 IOPMrootDomain::activitySinceSleep(void)
4028 return userActivityCount
!= userActivityAtSleep
;
4032 IOPMrootDomain::abortHibernation(void)
4035 // don't allow hibernation to be aborted on ARM due to user activity
4036 // since once ApplePMGR decides we're hibernating, we can't turn back
4037 // see: <rdar://problem/63848862> Tonga ApplePMGR diff quiesce path support
4040 bool ret
= activitySinceSleep();
4042 if (ret
&& !hibernateAborted
&& checkSystemCanSustainFullWake()) {
4043 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
4044 hibernateAborted
= true;
4051 hibernate_should_abort(void)
4054 return gRootDomain
->abortHibernation();
4060 //******************************************************************************
4061 // willNotifyPowerChildren
4063 // Called after all interested drivers have all acknowledged the power change,
4064 // but before any power children is informed. Dispatched though a thread call,
4065 // so it is safe to perform work that might block on a sleeping disk. PM state
4066 // machine (not thread) will block w/o timeout until this function returns.
4067 //******************************************************************************
4070 IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState
)
4072 OSSharedPtr
<OSDictionary
> dict
;
4073 OSSharedPtr
<OSNumber
> secs
;
4075 if (SLEEP_STATE
== newPowerState
) {
4076 notifierThread
= current_thread();
4077 if (!tasksSuspended
) {
4078 AbsoluteTime deadline
;
4079 tasksSuspended
= TRUE
;
4080 updateTasksSuspend();
4082 clock_interval_to_deadline(10, kSecondScale
, &deadline
);
4083 #if defined(XNU_TARGET_OS_OSX)
4084 vm_pageout_wait(AbsoluteTime_to_scalar(&deadline
));
4085 #endif /* defined(XNU_TARGET_OS_OSX) */
4088 _aotReadyToFullWake
= false;
4090 if (_aotLingerTime
) {
4092 IOLog("aot linger no return\n");
4093 clock_absolutetime_interval_to_deadline(_aotLingerTime
, &deadline
);
4094 clock_delay_until(deadline
);
4099 _aotWakeTimeCalendar
.selector
= kPMCalendarTypeInvalid
;
4101 bzero(_aotMetrics
, sizeof(IOPMAOTMetrics
));
4103 } else if (!_aotNow
&& !_debugWakeSeconds
) {
4106 _aotPendingFlags
= 0;
4107 _aotTasksSuspended
= true;
4108 _aotLastWakeTime
= 0;
4109 bzero(_aotMetrics
, sizeof(IOPMAOTMetrics
));
4110 if (kIOPMAOTModeCycle
& _aotMode
) {
4111 clock_interval_to_absolutetime_interval(60, kSecondScale
, &_aotTestInterval
);
4112 _aotTestTime
= mach_continuous_time() + _aotTestInterval
;
4113 setWakeTime(_aotTestTime
);
4115 uint32_t lingerSecs
;
4116 if (!PE_parse_boot_argn("aotlinger", &lingerSecs
, sizeof(lingerSecs
))) {
4119 clock_interval_to_absolutetime_interval(lingerSecs
, kSecondScale
, &_aotLingerTime
);
4120 clock_interval_to_absolutetime_interval(2000, kMillisecondScale
, &_aotWakePreWindow
);
4121 clock_interval_to_absolutetime_interval(1100, kMillisecondScale
, &_aotWakePostWindow
);
4125 IOHibernateSystemSleep();
4126 IOHibernateIOKitSleep();
4128 if (gRootDomain
->activitySinceSleep()) {
4129 dict
= OSDictionary::withCapacity(1);
4130 secs
= OSNumber::withNumber(1, 32);
4133 dict
->setObject(gIOPMSettingDebugWakeRelativeKey
.get(), secs
.get());
4134 gRootDomain
->setProperties(dict
.get());
4135 MSG("Reverting sleep with relative wake\n");
4139 notifierThread
= NULL
;
4143 //******************************************************************************
4144 // willTellSystemCapabilityDidChange
4146 // IOServicePM calls this from OurChangeTellCapabilityDidChange() when root
4147 // domain is raising its power state, immediately after notifying interested
4148 // drivers and power children.
4149 //******************************************************************************
4152 IOPMrootDomain::willTellSystemCapabilityDidChange( void )
4154 if ((_systemTransitionType
== kSystemTransitionWake
) &&
4155 !CAP_GAIN(kIOPMSystemCapabilityGraphics
)) {
4156 // After powering up drivers, dark->full promotion on the current wake
4157 // transition is no longer possible. That is because the next machine
4158 // state will issue the system capability change messages.
4159 // The darkWakePowerClamped flag may already be set if the system has
4160 // at least one driver that was power clamped due to dark wake.
4161 // This function sets the darkWakePowerClamped flag in case there
4162 // is no power-clamped driver in the system.
4164 // Last opportunity to exit dark wake using:
4165 // requestFullWake( kFullWakeReasonLocalUser );
4167 if (!darkWakePowerClamped
) {
4168 if (darkWakeLogClamp
) {
4172 clock_get_uptime(&now
);
4173 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
4174 absolutetime_to_nanoseconds(now
, &nsec
);
4175 DLOG("dark wake promotion disabled at %u ms\n",
4176 ((int)((nsec
) / NSEC_PER_MSEC
)));
4178 darkWakePowerClamped
= true;
4183 //******************************************************************************
4184 // sleepOnClamshellClosed
4186 // contains the logic to determine if the system should sleep when the clamshell
4188 //******************************************************************************
4191 IOPMrootDomain::shouldSleepOnClamshellClosed( void )
4193 if (!clamshellExists
) {
4197 DLOG("clamshell closed %d, disabled %d/%x, desktopMode %d, ac %d\n",
4198 clamshellClosed
, clamshellDisabled
, clamshellSleepDisableMask
, desktopMode
, acAdaptorConnected
);
4200 return !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) && !clamshellSleepDisableMask
;
4204 IOPMrootDomain::shouldSleepOnRTCAlarmWake( void )
4206 // Called once every RTC/Alarm wake. Device should go to sleep if on clamshell
4207 // closed && battery
4208 if (!clamshellExists
) {
4212 DLOG("shouldSleepOnRTCAlarmWake: clamshell closed %d, disabled %d/%x, desktopMode %d, ac %d\n",
4213 clamshellClosed
, clamshellDisabled
, clamshellSleepDisableMask
, desktopMode
, acAdaptorConnected
);
4215 return !acAdaptorConnected
&& !clamshellSleepDisableMask
;
4219 IOPMrootDomain::sendClientClamshellNotification( void )
4221 /* Only broadcast clamshell alert if clamshell exists. */
4222 if (!clamshellExists
) {
4226 setProperty(kAppleClamshellStateKey
,
4227 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
4229 setProperty(kAppleClamshellCausesSleepKey
,
4230 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
4232 /* Argument to message is a bitfiel of
4233 * ( kClamshellStateBit | kClamshellSleepBit )
4235 messageClients(kIOPMMessageClamshellStateChange
,
4236 (void *)(uintptr_t) ((clamshellClosed
? kClamshellStateBit
: 0)
4237 | (shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)));
4240 //******************************************************************************
4241 // getSleepSupported
4244 //******************************************************************************
4247 IOPMrootDomain::getSleepSupported( void )
4249 return platformSleepSupport
;
4252 //******************************************************************************
4253 // setSleepSupported
4256 //******************************************************************************
4259 IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
4261 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
4262 OSBitOrAtomic(flags
, &platformSleepSupport
);
4265 //******************************************************************************
4266 // setClamShellSleepDisable
4268 //******************************************************************************
4271 IOPMrootDomain::setClamShellSleepDisable( bool disable
, uint32_t bitmask
)
4275 // User client calls this in non-gated context
4276 if (gIOPMWorkLoop
->inGate() == false) {
4277 gIOPMWorkLoop
->runAction(
4278 OSMemberFunctionCast(IOWorkLoop::Action
, this,
4279 &IOPMrootDomain::setClamShellSleepDisable
),
4281 (void *) disable
, (void *)(uintptr_t) bitmask
);
4285 oldMask
= clamshellSleepDisableMask
;
4287 clamshellSleepDisableMask
|= bitmask
;
4289 clamshellSleepDisableMask
&= ~bitmask
;
4291 DLOG("setClamShellSleepDisable(%x->%x)\n", oldMask
, clamshellSleepDisableMask
);
4293 if (clamshellExists
&& clamshellClosed
&&
4294 (clamshellSleepDisableMask
!= oldMask
) &&
4295 (clamshellSleepDisableMask
== 0)) {
4296 handlePowerNotification(kLocalEvalClamshellCommand
);
4300 //******************************************************************************
4304 //******************************************************************************
4307 IOPMrootDomain::wakeFromDoze( void )
4309 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
4312 //******************************************************************************
4315 // Record the earliest scheduled RTC alarm to determine whether a RTC wake
4316 // should be a dark wake or a full wake. Both Maintenance and SleepService
4317 // alarms are dark wake, while AutoWake (WakeByCalendarDate) and DebugWake
4318 // (WakeRelativeToSleep) should trigger a full wake. Scheduled power-on
4319 // PMSettings are ignored.
4321 // Caller serialized using settingsCtrlLock.
4322 //******************************************************************************
4325 IOPMrootDomain::recordRTCAlarm(
4326 const OSSymbol
*type
,
4329 uint32_t previousAlarmMask
= _scheduledAlarmMask
;
4331 if (type
== gIOPMSettingDebugWakeRelativeKey
) {
4332 OSNumber
* n
= OSDynamicCast(OSNumber
, object
);
4334 // Debug wake has highest scheduling priority so it overrides any
4335 // pre-existing alarm.
4336 uint32_t debugSecs
= n
->unsigned32BitValue();
4337 _nextScheduledAlarmType
.reset(type
, OSRetain
);
4338 _nextScheduledAlarmUTC
= debugSecs
;
4340 _debugWakeSeconds
= debugSecs
;
4341 OSBitOrAtomic(kIOPMAlarmBitDebugWake
, &_scheduledAlarmMask
);
4342 DLOG("next alarm (%s) in %u secs\n",
4343 type
->getCStringNoCopy(), debugSecs
);
4345 } else if ((type
== gIOPMSettingAutoWakeCalendarKey
.get()) ||
4346 (type
== gIOPMSettingMaintenanceWakeCalendarKey
.get()) ||
4347 (type
== gIOPMSettingSleepServiceWakeCalendarKey
.get())) {
4348 OSData
* data
= OSDynamicCast(OSData
, object
);
4349 if (data
&& (data
->getLength() == sizeof(IOPMCalendarStruct
))) {
4350 const IOPMCalendarStruct
* cs
;
4351 bool replaceNextAlarm
= false;
4354 cs
= (const IOPMCalendarStruct
*) data
->getBytesNoCopy();
4355 secs
= IOPMConvertCalendarToSeconds(cs
);
4356 DLOG("%s " YMDTF
"\n", type
->getCStringNoCopy(), YMDT(cs
));
4358 // Update the next scheduled alarm type
4359 if ((_nextScheduledAlarmType
== NULL
) ||
4360 ((_nextScheduledAlarmType
!= gIOPMSettingDebugWakeRelativeKey
) &&
4361 (secs
< _nextScheduledAlarmUTC
))) {
4362 replaceNextAlarm
= true;
4365 if (type
== gIOPMSettingAutoWakeCalendarKey
.get()) {
4367 _calendarWakeAlarmUTC
= IOPMConvertCalendarToSeconds(cs
);
4368 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_scheduledAlarmMask
);
4370 // TODO: can this else-block be removed?
4371 _calendarWakeAlarmUTC
= 0;
4372 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_scheduledAlarmMask
);
4375 if (type
== gIOPMSettingMaintenanceWakeCalendarKey
.get()) {
4376 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake
, &_scheduledAlarmMask
);
4378 if (type
== gIOPMSettingSleepServiceWakeCalendarKey
.get()) {
4379 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake
, &_scheduledAlarmMask
);
4382 if (replaceNextAlarm
) {
4383 _nextScheduledAlarmType
.reset(type
, OSRetain
);
4384 _nextScheduledAlarmUTC
= secs
;
4385 DLOG("next alarm (%s) " YMDTF
"\n", type
->getCStringNoCopy(), YMDT(cs
));
4390 if (_scheduledAlarmMask
!= previousAlarmMask
) {
4391 DLOG("scheduled alarm mask 0x%x\n", (uint32_t) _scheduledAlarmMask
);
4398 //******************************************************************************
4401 // Adds a new feature to the supported features dictionary
4402 //******************************************************************************
4405 IOPMrootDomain::publishFeature( const char * feature
)
4407 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
4410 //******************************************************************************
4411 // publishFeature (with supported power source specified)
4413 // Adds a new feature to the supported features dictionary
4414 //******************************************************************************
4417 IOPMrootDomain::publishFeature(
4418 const char *feature
,
4419 uint32_t supportedWhere
,
4420 uint32_t *uniqueFeatureID
)
4422 static uint16_t next_feature_id
= 500;
4424 OSSharedPtr
<OSNumber
> new_feature_data
;
4425 OSNumber
*existing_feature
= NULL
;
4426 OSArray
*existing_feature_arr_raw
= NULL
;
4427 OSSharedPtr
<OSArray
> existing_feature_arr
;
4428 OSObject
*osObj
= NULL
;
4429 uint32_t feature_value
= 0;
4431 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
4433 if (!supportedWhere
) {
4434 // Feature isn't supported anywhere!
4438 if (next_feature_id
> 5000) {
4439 // Far, far too many features!
4443 if (featuresDictLock
) {
4444 IOLockLock(featuresDictLock
);
4447 OSSharedPtr
<OSObject
> origFeaturesProp
= copyProperty(kRootDomainSupportedFeatures
);
4448 OSDictionary
*origFeatures
= OSDynamicCast(OSDictionary
, origFeaturesProp
.get());
4449 OSSharedPtr
<OSDictionary
> features
;
4451 // Create new features dict if necessary
4453 features
= OSDictionary::withDictionary(origFeatures
);
4455 features
= OSDictionary::withCapacity(1);
4458 // Create OSNumber to track new feature
4460 next_feature_id
+= 1;
4461 if (uniqueFeatureID
) {
4462 // We don't really mind if the calling kext didn't give us a place
4463 // to stash their unique id. Many kexts don't plan to unload, and thus
4464 // have no need to remove themselves later.
4465 *uniqueFeatureID
= next_feature_id
;
4468 feature_value
= (uint32_t)next_feature_id
;
4469 feature_value
<<= 16;
4470 feature_value
+= supportedWhere
;
4472 new_feature_data
= OSNumber::withNumber(
4473 (unsigned long long)feature_value
, 32);
4475 // Does features object already exist?
4476 if ((osObj
= features
->getObject(feature
))) {
4477 if ((existing_feature
= OSDynamicCast(OSNumber
, osObj
))) {
4478 // We need to create an OSArray to hold the now 2 elements.
4479 existing_feature_arr
= OSArray::withObjects(
4480 (const OSObject
**)&existing_feature
, 1, 2);
4481 } else if ((existing_feature_arr_raw
= OSDynamicCast(OSArray
, osObj
))) {
4482 // Add object to existing array
4483 existing_feature_arr
= OSArray::withArray(
4484 existing_feature_arr_raw
,
4485 existing_feature_arr_raw
->getCount() + 1);
4488 if (existing_feature_arr
) {
4489 existing_feature_arr
->setObject(new_feature_data
.get());
4490 features
->setObject(feature
, existing_feature_arr
.get());
4493 // The easy case: no previously existing features listed. We simply
4494 // set the OSNumber at key 'feature' and we're on our way.
4495 features
->setObject(feature
, new_feature_data
.get());
4498 setProperty(kRootDomainSupportedFeatures
, features
.get());
4500 if (featuresDictLock
) {
4501 IOLockUnlock(featuresDictLock
);
4504 // Notify EnergySaver and all those in user space so they might
4505 // re-populate their feature specific UI
4506 if (pmPowerStateQueue
) {
4507 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
4511 //******************************************************************************
4512 // removePublishedFeature
4514 // Removes previously published feature
4515 //******************************************************************************
4518 IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
4520 IOReturn ret
= kIOReturnError
;
4521 uint32_t feature_value
= 0;
4522 uint16_t feature_id
= 0;
4523 bool madeAChange
= false;
4525 OSSymbol
*dictKey
= NULL
;
4526 OSSharedPtr
<OSCollectionIterator
> dictIterator
;
4527 OSArray
*arrayMember
= NULL
;
4528 OSNumber
*numberMember
= NULL
;
4529 OSObject
*osObj
= NULL
;
4530 OSNumber
*osNum
= NULL
;
4531 OSSharedPtr
<OSArray
> arrayMemberCopy
;
4533 if (kBadPMFeatureID
== removeFeatureID
) {
4534 return kIOReturnNotFound
;
4537 if (featuresDictLock
) {
4538 IOLockLock(featuresDictLock
);
4541 OSSharedPtr
<OSObject
> origFeaturesProp
= copyProperty(kRootDomainSupportedFeatures
);
4542 OSDictionary
*origFeatures
= OSDynamicCast(OSDictionary
, origFeaturesProp
.get());
4543 OSSharedPtr
<OSDictionary
> features
;
4546 // Any modifications to the dictionary are made to the copy to prevent
4547 // races & crashes with userland clients. Dictionary updated
4548 // automically later.
4549 features
= OSDictionary::withDictionary(origFeatures
);
4552 ret
= kIOReturnNotFound
;
4556 // We iterate 'features' dictionary looking for an entry tagged
4557 // with 'removeFeatureID'. If found, we remove it from our tracking
4558 // structures and notify the OS via a general interest message.
4560 dictIterator
= OSCollectionIterator::withCollection(features
.get());
4561 if (!dictIterator
) {
4565 while ((dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject()))) {
4566 osObj
= features
->getObject(dictKey
);
4568 // Each Feature is either tracked by an OSNumber
4569 if (osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
))) {
4570 feature_value
= numberMember
->unsigned32BitValue();
4571 feature_id
= (uint16_t)(feature_value
>> 16);
4573 if (feature_id
== (uint16_t)removeFeatureID
) {
4575 features
->removeObject(dictKey
);
4580 // Or tracked by an OSArray of OSNumbers
4581 } else if (osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
))) {
4582 unsigned int arrayCount
= arrayMember
->getCount();
4584 for (unsigned int i
= 0; i
< arrayCount
; i
++) {
4585 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
4590 feature_value
= osNum
->unsigned32BitValue();
4591 feature_id
= (uint16_t)(feature_value
>> 16);
4593 if (feature_id
== (uint16_t)removeFeatureID
) {
4595 if (1 == arrayCount
) {
4596 // If the array only contains one element, remove
4598 features
->removeObject(dictKey
);
4600 // Otherwise remove the element from a copy of the array.
4601 arrayMemberCopy
= OSArray::withArray(arrayMember
);
4602 if (arrayMemberCopy
) {
4603 arrayMemberCopy
->removeObject(i
);
4604 features
->setObject(dictKey
, arrayMemberCopy
.get());
4616 ret
= kIOReturnSuccess
;
4618 setProperty(kRootDomainSupportedFeatures
, features
.get());
4620 // Notify EnergySaver and all those in user space so they might
4621 // re-populate their feature specific UI
4622 if (pmPowerStateQueue
) {
4623 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
4626 ret
= kIOReturnNotFound
;
4630 if (featuresDictLock
) {
4631 IOLockUnlock(featuresDictLock
);
4636 //******************************************************************************
4637 // publishPMSetting (private)
4639 // Should only be called by PMSettingObject to publish a PM Setting as a
4640 // supported feature.
4641 //******************************************************************************
4644 IOPMrootDomain::publishPMSetting(
4645 const OSSymbol
* feature
, uint32_t where
, uint32_t * featureID
)
4647 if (noPublishPMSettings
&&
4648 (noPublishPMSettings
->getNextIndexOfObject(feature
, 0) != (unsigned int)-1)) {
4649 // Setting found in noPublishPMSettings array
4650 *featureID
= kBadPMFeatureID
;
4655 feature
->getCStringNoCopy(), where
, featureID
);
4658 //******************************************************************************
4659 // setPMSetting (private)
4661 // Internal helper to relay PM settings changes from user space to individual
4662 // drivers. Should be called only by IOPMrootDomain::setProperties.
4663 //******************************************************************************
4666 IOPMrootDomain::setPMSetting(
4667 const OSSymbol
*type
,
4670 PMSettingCallEntry
*entries
= NULL
;
4671 OSSharedPtr
<OSArray
> chosen
;
4672 const OSArray
*array
;
4673 PMSettingObject
*pmso
;
4674 thread_t thisThread
;
4675 int i
, j
, count
, capacity
;
4680 return kIOReturnBadArgument
;
4685 // Update settings dict so changes are visible from copyPMSetting().
4686 fPMSettingsDict
->setObject(type
, object
);
4688 // Prep all PMSetting objects with the given 'type' for callout.
4689 array
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(type
));
4690 if (!array
|| ((capacity
= array
->getCount()) == 0)) {
4694 // Array to retain PMSetting objects targeted for callout.
4695 chosen
= OSArray::withCapacity(capacity
);
4697 goto unlock_exit
; // error
4699 entries
= IONew(PMSettingCallEntry
, capacity
);
4701 goto unlock_exit
; // error
4703 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
4705 thisThread
= current_thread();
4707 for (i
= 0, j
= 0; i
< capacity
; i
++) {
4708 pmso
= (PMSettingObject
*) array
->getObject(i
);
4709 if (pmso
->disabled
) {
4712 entries
[j
].thread
= thisThread
;
4713 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
4714 chosen
->setObject(pmso
);
4724 // Call each pmso in the chosen array.
4725 for (i
= 0; i
< count
; i
++) {
4726 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
4727 ret
= pmso
->dispatchPMSetting(type
, object
);
4728 if (ret
== kIOReturnSuccess
) {
4729 // At least one setting handler was successful
4731 #if DEVELOPMENT || DEBUG
4733 // Log the handler and kext that failed
4734 OSSharedPtr
<const OSSymbol
> kextName
= copyKextIdentifierWithAddress((vm_address_t
) pmso
->func
);
4736 DLOG("PMSetting(%s) error 0x%x from %s\n",
4737 type
->getCStringNoCopy(), ret
, kextName
->getCStringNoCopy());
4744 for (i
= 0; i
< count
; i
++) {
4745 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
4746 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
4747 if (pmso
->waitThread
) {
4748 PMSETTING_WAKEUP(pmso
);
4753 recordRTCAlarm(type
, object
);
4759 IODelete(entries
, PMSettingCallEntry
, capacity
);
4762 return kIOReturnSuccess
;
4765 //******************************************************************************
4766 // copyPMSetting (public)
4768 // Allows kexts to safely read setting values, without being subscribed to
4770 //******************************************************************************
4772 OSSharedPtr
<OSObject
>
4773 IOPMrootDomain::copyPMSetting(
4774 OSSymbol
*whichSetting
)
4776 OSSharedPtr
<OSObject
> obj
;
4778 if (!whichSetting
) {
4783 obj
.reset(fPMSettingsDict
->getObject(whichSetting
), OSRetain
);
4789 //******************************************************************************
4790 // registerPMSettingController (public)
4792 // direct wrapper to registerPMSettingController with uint32_t power source arg
4793 //******************************************************************************
4796 IOPMrootDomain::registerPMSettingController(
4797 const OSSymbol
* settings
[],
4798 IOPMSettingControllerCallback func
,
4803 return registerPMSettingController(
4805 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
4806 func
, target
, refcon
, handle
);
4809 //******************************************************************************
4810 // registerPMSettingController (public)
4812 // Kexts may register for notifications when a particular setting is changed.
4813 // A list of settings is available in IOPM.h.
4815 // * settings - An OSArray containing OSSymbols. Caller should populate this
4816 // array with a list of settings caller wants notifications from.
4817 // * func - A C function callback of the type IOPMSettingControllerCallback
4818 // * target - caller may provide an OSObject *, which PM will pass as an
4819 // target to calls to "func"
4820 // * refcon - caller may provide an void *, which PM will pass as an
4821 // argument to calls to "func"
4822 // * handle - This is a return argument. We will populate this pointer upon
4823 // call success. Hold onto this and pass this argument to
4824 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
4826 // kIOReturnSuccess on success
4827 //******************************************************************************
4830 IOPMrootDomain::registerPMSettingController(
4831 const OSSymbol
* settings
[],
4832 uint32_t supportedPowerSources
,
4833 IOPMSettingControllerCallback func
,
4838 PMSettingObject
*pmso
= NULL
;
4839 OSObject
*pmsh
= NULL
;
4842 if (NULL
== settings
||
4845 return kIOReturnBadArgument
;
4848 pmso
= PMSettingObject::pmSettingObject(
4849 (IOPMrootDomain
*) this, func
, target
,
4850 refcon
, supportedPowerSources
, settings
, &pmsh
);
4854 return kIOReturnInternalError
;
4858 for (i
= 0; settings
[i
]; i
++) {
4859 OSSharedPtr
<OSArray
> newList
;
4860 OSArray
*list
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(settings
[i
]));
4862 // New array of callbacks for this setting
4863 newList
= OSArray::withCapacity(1);
4864 settingsCallbacks
->setObject(settings
[i
], newList
.get());
4865 list
= newList
.get();
4868 // Add caller to the callback list
4869 list
->setObject(pmso
);
4873 // Return handle to the caller, the setting object is private.
4876 return kIOReturnSuccess
;
4879 //******************************************************************************
4880 // deregisterPMSettingObject (private)
4882 // Only called from PMSettingObject.
4883 //******************************************************************************
4886 IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
4888 thread_t thisThread
= current_thread();
4889 PMSettingCallEntry
*callEntry
;
4890 OSSharedPtr
<OSCollectionIterator
> iter
;
4898 pmso
->disabled
= true;
4900 // Wait for all callout threads to finish.
4903 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
4905 if (callEntry
->thread
!= thisThread
) {
4911 assert(NULL
== pmso
->waitThread
);
4912 pmso
->waitThread
= thisThread
;
4913 PMSETTING_WAIT(pmso
);
4914 pmso
->waitThread
= NULL
;
4918 // Search each PM settings array in the kernel.
4919 iter
= OSCollectionIterator::withCollection(settingsCallbacks
.get());
4921 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject()))) {
4922 array
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(sym
));
4923 index
= array
->getNextIndexOfObject(pmso
, 0);
4925 array
->removeObject(index
);
4935 //******************************************************************************
4936 // informCPUStateChange
4938 // Call into PM CPU code so that CPU power savings may dynamically adjust for
4939 // running on battery, with the lid closed, etc.
4941 // informCPUStateChange is a no-op on non x86 systems
4942 // only x86 has explicit support in the IntelCPUPowerManagement kext
4943 //******************************************************************************
4946 IOPMrootDomain::informCPUStateChange(
4950 #if defined(__i386__) || defined(__x86_64__)
4952 pmioctlVariableInfo_t varInfoStruct
;
4954 const char *varNameStr
= NULL
;
4955 int32_t *varIndex
= NULL
;
4957 if (kInformAC
== type
) {
4958 varNameStr
= kIOPMRootDomainBatPowerCString
;
4959 varIndex
= &idxPMCPULimitedPower
;
4960 } else if (kInformLid
== type
) {
4961 varNameStr
= kIOPMRootDomainLidCloseCString
;
4962 varIndex
= &idxPMCPUClamshell
;
4967 // Set the new value!
4968 // pmCPUControl will assign us a new ID if one doesn't exist yet
4969 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
4970 varInfoStruct
.varID
= *varIndex
;
4971 varInfoStruct
.varType
= vBool
;
4972 varInfoStruct
.varInitValue
= value
;
4973 varInfoStruct
.varCurValue
= value
;
4974 strlcpy((char *)varInfoStruct
.varName
,
4975 (const char *)varNameStr
,
4976 sizeof(varInfoStruct
.varName
));
4979 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
4981 // pmCPU only assigns numerical id's when a new varName is specified
4983 && (*varIndex
== kCPUUnknownIndex
)) {
4984 // pmCPUControl has assigned us a new variable ID.
4985 // Let's re-read the structure we just SET to learn that ID.
4986 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
4988 if (0 == pmCPUret
) {
4989 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
4990 *varIndex
= varInfoStruct
.varID
;
4996 #endif /* __i386__ || __x86_64__ */
5000 // MARK: Deep Sleep Policy
5004 //******************************************************************************
5005 // evaluateSystemSleepPolicy
5006 //******************************************************************************
5008 #define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
5012 kIOPMSleepFlagHibernate
= 0x00000001,
5013 kIOPMSleepFlagSleepTimerEnable
= 0x00000002
5016 struct IOPMSystemSleepPolicyEntry
{
5017 uint32_t factorMask
;
5018 uint32_t factorBits
;
5019 uint32_t sleepFlags
;
5020 uint32_t wakeEvents
;
5021 } __attribute__((packed
));
5023 struct IOPMSystemSleepPolicyTable
{
5026 uint16_t entryCount
;
5027 IOPMSystemSleepPolicyEntry entries
[];
5028 } __attribute__((packed
));
5031 kIOPMSleepAttributeHibernateSetup
= 0x00000001,
5032 kIOPMSleepAttributeHibernateSleep
= 0x00000002
5036 getSleepTypeAttributes( uint32_t sleepType
)
5038 static const uint32_t sleepTypeAttributes
[kIOPMSleepTypeLast
] =
5043 /* safesleep */ kIOPMSleepAttributeHibernateSetup
,
5044 /* hibernate */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
5045 /* standby */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
5046 /* poweroff */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
5050 if (sleepType
>= kIOPMSleepTypeLast
) {
5054 return sleepTypeAttributes
[sleepType
];
5058 IOPMrootDomain::evaluateSystemSleepPolicy(
5059 IOPMSystemSleepParameters
* params
, int sleepPhase
, uint32_t * hibMode
)
5061 #define SLEEP_FACTOR(x) {(uint32_t) kIOPMSleepFactor ## x, #x}
5063 static const IONamedValue factorValues
[] = {
5064 SLEEP_FACTOR( SleepTimerWake
),
5065 SLEEP_FACTOR( LidOpen
),
5066 SLEEP_FACTOR( ACPower
),
5067 SLEEP_FACTOR( BatteryLow
),
5068 SLEEP_FACTOR( StandbyNoDelay
),
5069 SLEEP_FACTOR( StandbyForced
),
5070 SLEEP_FACTOR( StandbyDisabled
),
5071 SLEEP_FACTOR( USBExternalDevice
),
5072 SLEEP_FACTOR( BluetoothHIDDevice
),
5073 SLEEP_FACTOR( ExternalMediaMounted
),
5074 SLEEP_FACTOR( ThunderboltDevice
),
5075 SLEEP_FACTOR( RTCAlarmScheduled
),
5076 SLEEP_FACTOR( MagicPacketWakeEnabled
),
5077 SLEEP_FACTOR( HibernateForced
),
5078 SLEEP_FACTOR( AutoPowerOffDisabled
),
5079 SLEEP_FACTOR( AutoPowerOffForced
),
5080 SLEEP_FACTOR( ExternalDisplay
),
5081 SLEEP_FACTOR( NetworkKeepAliveActive
),
5082 SLEEP_FACTOR( LocalUserActivity
),
5083 SLEEP_FACTOR( HibernateFailed
),
5084 SLEEP_FACTOR( ThermalWarning
),
5085 SLEEP_FACTOR( DisplayCaptured
),
5089 const IOPMSystemSleepPolicyTable
* pt
;
5090 OSSharedPtr
<OSObject
> prop
;
5091 OSData
* policyData
;
5092 uint64_t currentFactors
= 0;
5093 char currentFactorsBuf
[512];
5094 uint32_t standbyDelay
= 0;
5095 uint32_t powerOffDelay
= 0;
5096 uint32_t powerOffTimer
= 0;
5097 uint32_t standbyTimer
= 0;
5099 bool standbyEnabled
;
5100 bool powerOffEnabled
;
5103 // Get platform's sleep policy table
5104 if (!gSleepPolicyHandler
) {
5105 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
5111 // Fetch additional settings
5112 standbyEnabled
= (getSleepOption(kIOPMDeepSleepDelayKey
, &standbyDelay
)
5113 && propertyHasValue(kIOPMDeepSleepEnabledKey
, kOSBooleanTrue
));
5114 powerOffEnabled
= (getSleepOption(kIOPMAutoPowerOffDelayKey
, &powerOffDelay
)
5115 && propertyHasValue(kIOPMAutoPowerOffEnabledKey
, kOSBooleanTrue
));
5116 if (!getSleepOption(kIOPMAutoPowerOffTimerKey
, &powerOffTimer
)) {
5117 powerOffTimer
= powerOffDelay
;
5119 if (!getSleepOption(kIOPMDeepSleepTimerKey
, &standbyTimer
)) {
5120 standbyTimer
= standbyDelay
;
5123 DLOG("phase %d, standby %d delay %u timer %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
5124 sleepPhase
, standbyEnabled
, standbyDelay
, standbyTimer
,
5125 powerOffEnabled
, powerOffDelay
, powerOffTimer
, *hibMode
);
5127 currentFactorsBuf
[0] = 0;
5128 // pmset level overrides
5129 if ((*hibMode
& kIOHibernateModeOn
) == 0) {
5130 if (!gSleepPolicyHandler
) {
5131 standbyEnabled
= false;
5132 powerOffEnabled
= false;
5134 } else if (!(*hibMode
& kIOHibernateModeSleep
)) {
5135 // Force hibernate (i.e. mode 25)
5136 // If standby is enabled, force standy.
5137 // If poweroff is enabled, force poweroff.
5138 if (standbyEnabled
) {
5139 currentFactors
|= kIOPMSleepFactorStandbyForced
;
5140 } else if (powerOffEnabled
) {
5141 currentFactors
|= kIOPMSleepFactorAutoPowerOffForced
;
5143 currentFactors
|= kIOPMSleepFactorHibernateForced
;
5147 // Current factors based on environment and assertions
5148 if (sleepTimerMaintenance
) {
5149 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
5151 if (standbyEnabled
&& sleepToStandby
&& !gSleepPolicyHandler
) {
5152 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
5154 if (!clamshellClosed
) {
5155 currentFactors
|= kIOPMSleepFactorLidOpen
;
5157 if (acAdaptorConnected
) {
5158 currentFactors
|= kIOPMSleepFactorACPower
;
5160 if (lowBatteryCondition
) {
5162 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
5163 if ((hibernateMode
& kIOHibernateModeOn
) == 0) {
5164 DLOG("HibernateMode is 0. Not sending LowBattery factor to IOPPF\n");
5166 currentFactors
|= kIOPMSleepFactorBatteryLow
;
5169 if (!standbyDelay
|| !standbyTimer
) {
5170 currentFactors
|= kIOPMSleepFactorStandbyNoDelay
;
5172 if (standbyNixed
|| !standbyEnabled
) {
5173 currentFactors
|= kIOPMSleepFactorStandbyDisabled
;
5176 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
5177 currentFactors
&= ~kIOPMSleepFactorSleepTimerWake
;
5179 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
5180 kIOPMDriverAssertionLevelOff
) {
5181 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
5183 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
5184 kIOPMDriverAssertionLevelOff
) {
5185 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
5187 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
5188 kIOPMDriverAssertionLevelOff
) {
5189 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
5191 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) !=
5192 kIOPMDriverAssertionLevelOff
) {
5193 currentFactors
|= kIOPMSleepFactorThunderboltDevice
;
5195 if (_scheduledAlarmMask
!= 0) {
5196 currentFactors
|= kIOPMSleepFactorRTCAlarmScheduled
;
5198 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit
) !=
5199 kIOPMDriverAssertionLevelOff
) {
5200 currentFactors
|= kIOPMSleepFactorMagicPacketWakeEnabled
;
5202 #define TCPKEEPALIVE 1
5204 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit
) !=
5205 kIOPMDriverAssertionLevelOff
) {
5206 currentFactors
|= kIOPMSleepFactorNetworkKeepAliveActive
;
5209 if (!powerOffEnabled
) {
5210 currentFactors
|= kIOPMSleepFactorAutoPowerOffDisabled
;
5213 currentFactors
|= kIOPMSleepFactorExternalDisplay
;
5215 if (userWasActive
) {
5216 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
5218 if (darkWakeHibernateError
&& !CAP_HIGHEST(kIOPMSystemCapabilityGraphics
)) {
5219 currentFactors
|= kIOPMSleepFactorHibernateFailed
;
5221 if (thermalWarningState
) {
5222 currentFactors
|= kIOPMSleepFactorThermalWarning
;
5225 for (int factorBit
= 0; factorBit
< (8 * sizeof(uint32_t)); factorBit
++) {
5226 uint32_t factor
= 1 << factorBit
;
5227 if (factor
& currentFactors
) {
5228 strlcat(currentFactorsBuf
, ", ", sizeof(currentFactorsBuf
));
5229 strlcat(currentFactorsBuf
, IOFindNameForValue(factor
, factorValues
), sizeof(currentFactorsBuf
));
5232 DLOG("sleep factors 0x%llx%s\n", currentFactors
, currentFactorsBuf
);
5234 if (gSleepPolicyHandler
) {
5235 uint32_t savedHibernateMode
;
5238 if (!gSleepPolicyVars
) {
5239 gSleepPolicyVars
= IONew(IOPMSystemSleepPolicyVariables
, 1);
5240 if (!gSleepPolicyVars
) {
5243 bzero(gSleepPolicyVars
, sizeof(*gSleepPolicyVars
));
5245 gSleepPolicyVars
->signature
= kIOPMSystemSleepPolicySignature
;
5246 gSleepPolicyVars
->version
= kIOPMSystemSleepPolicyVersion
;
5247 gSleepPolicyVars
->currentCapability
= _currentCapability
;
5248 gSleepPolicyVars
->highestCapability
= _highestCapability
;
5249 gSleepPolicyVars
->sleepFactors
= currentFactors
;
5250 gSleepPolicyVars
->sleepReason
= lastSleepReason
;
5251 gSleepPolicyVars
->sleepPhase
= sleepPhase
;
5252 gSleepPolicyVars
->standbyDelay
= standbyDelay
;
5253 gSleepPolicyVars
->standbyTimer
= standbyTimer
;
5254 gSleepPolicyVars
->poweroffDelay
= powerOffDelay
;
5255 gSleepPolicyVars
->scheduledAlarms
= _scheduledAlarmMask
| _userScheduledAlarmMask
;
5256 gSleepPolicyVars
->poweroffTimer
= powerOffTimer
;
5258 if (kIOPMSleepPhase0
== sleepPhase
) {
5259 // preserve hibernateMode
5260 savedHibernateMode
= gSleepPolicyVars
->hibernateMode
;
5261 gSleepPolicyVars
->hibernateMode
= *hibMode
;
5262 } else if (kIOPMSleepPhase1
== sleepPhase
) {
5263 // use original hibernateMode for phase2
5264 gSleepPolicyVars
->hibernateMode
= *hibMode
;
5267 result
= gSleepPolicyHandler(gSleepPolicyTarget
, gSleepPolicyVars
, params
);
5269 if (kIOPMSleepPhase0
== sleepPhase
) {
5270 // restore hibernateMode
5271 gSleepPolicyVars
->hibernateMode
= savedHibernateMode
;
5274 if ((result
!= kIOReturnSuccess
) ||
5275 (kIOPMSleepTypeInvalid
== params
->sleepType
) ||
5276 (params
->sleepType
>= kIOPMSleepTypeLast
) ||
5277 (kIOPMSystemSleepParametersVersion
!= params
->version
)) {
5278 MSG("sleep policy handler error\n");
5282 if ((getSleepTypeAttributes(params
->sleepType
) &
5283 kIOPMSleepAttributeHibernateSetup
) &&
5284 ((*hibMode
& kIOHibernateModeOn
) == 0)) {
5285 *hibMode
|= (kIOHibernateModeOn
| kIOHibernateModeSleep
);
5288 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
5289 params
->version
, params
->sleepType
, params
->sleepFlags
,
5290 params
->ecWakeEvents
, params
->ecWakeTimer
, params
->ecPoweroffTimer
);
5295 // Policy table is meaningless without standby enabled
5296 if (!standbyEnabled
) {
5300 // Validate the sleep policy table
5301 policyData
= OSDynamicCast(OSData
, prop
.get());
5302 if (!policyData
|| (policyData
->getLength() <= sizeof(IOPMSystemSleepPolicyTable
))) {
5306 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
5307 if ((pt
->signature
!= kIOPMSystemSleepPolicySignature
) ||
5308 (pt
->version
!= 1) || (0 == pt
->entryCount
)) {
5312 if (((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
5313 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
))) {
5317 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++) {
5318 const IOPMSystemSleepPolicyEntry
* entry
= &pt
->entries
[i
];
5319 mismatch
= (((uint32_t)currentFactors
^ entry
->factorBits
) & entry
->factorMask
);
5321 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
5322 entry
->factorMask
, entry
->factorBits
,
5323 entry
->sleepFlags
, entry
->wakeEvents
, mismatch
);
5328 DLOG("^ found match\n");
5331 params
->version
= kIOPMSystemSleepParametersVersion
;
5332 params
->reserved1
= 1;
5333 if (entry
->sleepFlags
& kIOPMSleepFlagHibernate
) {
5334 params
->sleepType
= kIOPMSleepTypeStandby
;
5336 params
->sleepType
= kIOPMSleepTypeNormalSleep
;
5339 params
->ecWakeEvents
= entry
->wakeEvents
;
5340 if (entry
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
) {
5341 if (kIOPMSleepPhase2
== sleepPhase
) {
5342 clock_sec_t now_secs
= gIOLastSleepTime
.tv_sec
;
5344 if (!_standbyTimerResetSeconds
||
5345 (now_secs
<= _standbyTimerResetSeconds
)) {
5346 // Reset standby timer adjustment
5347 _standbyTimerResetSeconds
= now_secs
;
5348 DLOG("standby delay %u, reset %u\n",
5349 standbyDelay
, (uint32_t) _standbyTimerResetSeconds
);
5350 } else if (standbyDelay
) {
5351 // Shorten the standby delay timer
5352 clock_sec_t elapsed
= now_secs
- _standbyTimerResetSeconds
;
5353 if (standbyDelay
> elapsed
) {
5354 standbyDelay
-= elapsed
;
5356 standbyDelay
= 1; // must be > 0
5358 DLOG("standby delay %u, elapsed %u\n",
5359 standbyDelay
, (uint32_t) elapsed
);
5362 params
->ecWakeTimer
= standbyDelay
;
5363 } else if (kIOPMSleepPhase2
== sleepPhase
) {
5364 // A sleep that does not enable the sleep timer will reset
5365 // the standby delay adjustment.
5366 _standbyTimerResetSeconds
= 0;
5375 static IOPMSystemSleepParameters gEarlySystemSleepParams
;
5378 IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
5380 // Evaluate early (priority interest phase), before drivers sleep.
5382 DLOG("%s\n", __FUNCTION__
);
5383 removeProperty(kIOPMSystemSleepParametersKey
);
5385 // Full wake resets the standby timer delay adjustment
5386 if (_highestCapability
& kIOPMSystemCapabilityGraphics
) {
5387 _standbyTimerResetSeconds
= 0;
5390 hibernateDisabled
= false;
5392 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
5394 // Save for late evaluation if sleep is aborted
5395 bzero(&gEarlySystemSleepParams
, sizeof(gEarlySystemSleepParams
));
5397 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams
, kIOPMSleepPhase1
,
5399 if (!hibernateRetry
&&
5400 ((getSleepTypeAttributes(gEarlySystemSleepParams
.sleepType
) &
5401 kIOPMSleepAttributeHibernateSetup
) == 0)) {
5402 // skip hibernate setup
5403 hibernateDisabled
= true;
5407 // Publish IOPMSystemSleepType
5408 uint32_t sleepType
= gEarlySystemSleepParams
.sleepType
;
5409 if (sleepType
== kIOPMSleepTypeInvalid
) {
5411 sleepType
= kIOPMSleepTypeNormalSleep
;
5412 if (hibernateMode
& kIOHibernateModeOn
) {
5413 sleepType
= (hibernateMode
& kIOHibernateModeSleep
) ?
5414 kIOPMSleepTypeSafeSleep
: kIOPMSleepTypeHibernate
;
5416 } else if ((sleepType
== kIOPMSleepTypeStandby
) &&
5417 (gEarlySystemSleepParams
.ecPoweroffTimer
)) {
5418 // report the lowest possible sleep state
5419 sleepType
= kIOPMSleepTypePowerOff
;
5422 setProperty(kIOPMSystemSleepTypeKey
, sleepType
, 32);
5426 IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
5428 IOPMSystemSleepParameters params
;
5429 OSSharedPtr
<OSData
> paramsData
;
5431 // Evaluate sleep policy after sleeping drivers but before platform sleep.
5433 DLOG("%s\n", __FUNCTION__
);
5435 bzero(¶ms
, sizeof(params
));
5437 if (evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase2
, &hibernateMode
)) {
5438 if ((kIOPMSleepTypeStandby
== params
.sleepType
)
5439 && gIOHibernateStandbyDisabled
&& gSleepPolicyVars
5440 && (!((kIOPMSleepFactorStandbyForced
| kIOPMSleepFactorAutoPowerOffForced
| kIOPMSleepFactorHibernateForced
)
5441 & gSleepPolicyVars
->sleepFactors
))) {
5442 standbyNixed
= true;
5446 || ((hibernateDisabled
|| hibernateAborted
) &&
5447 (getSleepTypeAttributes(params
.sleepType
) &
5448 kIOPMSleepAttributeHibernateSetup
))) {
5449 // Final evaluation picked a state requiring hibernation,
5450 // but hibernate isn't going to proceed. Arm a short sleep using
5451 // the early non-hibernate sleep parameters.
5452 bcopy(&gEarlySystemSleepParams
, ¶ms
, sizeof(params
));
5453 params
.sleepType
= kIOPMSleepTypeAbortedSleep
;
5454 params
.ecWakeTimer
= 1;
5458 // Set hibernateRetry flag to force hibernate setup on the
5460 hibernateRetry
= true;
5462 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d, standbyNixed %d\n",
5463 params
.ecWakeTimer
, hibernateDisabled
, hibernateAborted
, standbyNixed
);
5465 hibernateRetry
= false;
5468 if (kIOPMSleepTypeAbortedSleep
!= params
.sleepType
) {
5469 resetTimers
= false;
5472 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
5474 setProperty(kIOPMSystemSleepParametersKey
, paramsData
.get());
5477 if (getSleepTypeAttributes(params
.sleepType
) &
5478 kIOPMSleepAttributeHibernateSleep
) {
5479 // Disable sleep to force hibernation
5480 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
5486 IOPMrootDomain::getHibernateSettings(
5487 uint32_t * hibernateModePtr
,
5488 uint32_t * hibernateFreeRatio
,
5489 uint32_t * hibernateFreeTime
)
5491 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
5492 // has updated the hibernateDisabled flag.
5494 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateModePtr
);
5495 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
5496 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
5497 if (hibernateDisabled
) {
5498 *hibernateModePtr
= 0;
5499 } else if (gSleepPolicyHandler
) {
5500 *hibernateModePtr
= hibernateMode
;
5502 DLOG("hibernateMode 0x%x\n", *hibernateModePtr
);
5507 IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
5509 OSSharedPtr
<OSObject
> optionsProp
;
5510 OSDictionary
* optionsDict
;
5511 OSSharedPtr
<OSObject
> obj
;
5515 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
5516 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
.get());
5519 obj
.reset(optionsDict
->getObject(key
), OSRetain
);
5522 obj
= copyProperty(key
);
5525 if ((num
= OSDynamicCast(OSNumber
, obj
.get()))) {
5526 *option
= num
->unsigned32BitValue();
5528 } else if (OSDynamicCast(OSBoolean
, obj
.get())) {
5529 *option
= (obj
== kOSBooleanTrue
) ? 1 : 0;
5536 #endif /* HIBERNATION */
5539 IOPMrootDomain::getSystemSleepType( uint32_t * sleepType
, uint32_t * standbyTimer
)
5542 IOPMSystemSleepParameters params
;
5543 uint32_t hibMode
= 0;
5546 if (gIOPMWorkLoop
->inGate() == false) {
5547 IOReturn ret
= gIOPMWorkLoop
->runAction(
5548 OSMemberFunctionCast(IOWorkLoop::Action
, this,
5549 &IOPMrootDomain::getSystemSleepType
),
5551 (void *) sleepType
, (void *) standbyTimer
);
5555 getSleepOption(kIOHibernateModeKey
, &hibMode
);
5556 bzero(¶ms
, sizeof(params
));
5558 ok
= evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase0
, &hibMode
);
5560 *sleepType
= params
.sleepType
;
5561 if (!getSleepOption(kIOPMDeepSleepTimerKey
, standbyTimer
) &&
5562 !getSleepOption(kIOPMDeepSleepDelayKey
, standbyTimer
)) {
5563 DLOG("Standby delay is not set\n");
5566 return kIOReturnSuccess
;
5570 return kIOReturnUnsupported
;
5574 // MARK: Shutdown and Restart
5576 //******************************************************************************
5577 // handlePlatformHaltRestart
5579 //******************************************************************************
5581 // Phases while performing shutdown/restart
5584 kNotifyPriorityClients
= 0x10,
5585 kNotifyPowerPlaneDrivers
= 0x20,
5586 kNotifyHaltRestartAction
= 0x30,
5591 struct HaltRestartApplierContext
{
5592 IOPMrootDomain
* RootDomain
;
5593 unsigned long PowerState
;
5594 IOPMPowerFlags PowerFlags
;
5597 const char * LogString
;
5598 shutdownPhase_t phase
;
5600 IOServiceInterestHandler handler
;
5604 shutdownPhase2String(shutdownPhase_t phase
)
5608 return "Notifications completed";
5609 case kNotifyPriorityClients
:
5610 return "Notifying priority clients";
5611 case kNotifyPowerPlaneDrivers
:
5612 return "Notifying power plane drivers";
5613 case kNotifyHaltRestartAction
:
5614 return "Notifying HaltRestart action handlers";
5616 return "Quiescing PM";
5623 platformHaltRestartApplier( OSObject
* object
, void * context
)
5625 IOPowerStateChangeNotification notify
;
5626 HaltRestartApplierContext
* ctx
;
5627 AbsoluteTime startTime
, elapsedTime
;
5630 ctx
= (HaltRestartApplierContext
*) context
;
5632 _IOServiceInterestNotifier
* notifier
;
5633 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
5634 memset(¬ify
, 0, sizeof(notify
));
5635 notify
.powerRef
= (void *)(uintptr_t)ctx
->Counter
;
5636 notify
.returnValue
= 0;
5637 notify
.stateNumber
= ctx
->PowerState
;
5638 notify
.stateFlags
= ctx
->PowerFlags
;
5641 ctx
->handler
= notifier
->handler
;
5644 clock_get_uptime(&startTime
);
5645 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
5646 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
5648 if ((deltaTime
> kPMHaltTimeoutMS
) && notifier
) {
5649 LOG("%s handler %p took %u ms\n",
5650 ctx
->LogString
, OBFUSCATE(notifier
->handler
), deltaTime
);
5651 halt_log_enter("PowerOff/Restart message to priority client", (const void *) notifier
->handler
, elapsedTime
);
5654 ctx
->handler
= NULL
;
5659 quiescePowerTreeCallback( void * target
, void * param
)
5661 IOLockLock(gPMHaltLock
);
5663 thread_wakeup(param
);
5664 IOLockUnlock(gPMHaltLock
);
5668 IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
5670 AbsoluteTime startTime
, elapsedTime
;
5673 memset(&gHaltRestartCtx
, 0, sizeof(gHaltRestartCtx
));
5674 gHaltRestartCtx
.RootDomain
= this;
5676 clock_get_uptime(&startTime
);
5679 case kPEUPSDelayHaltCPU
:
5680 gHaltRestartCtx
.PowerState
= OFF_STATE
;
5681 gHaltRestartCtx
.MessageType
= kIOMessageSystemWillPowerOff
;
5682 gHaltRestartCtx
.LogString
= "PowerOff";
5686 gHaltRestartCtx
.PowerState
= RESTART_STATE
;
5687 gHaltRestartCtx
.MessageType
= kIOMessageSystemWillRestart
;
5688 gHaltRestartCtx
.LogString
= "Restart";
5692 gHaltRestartCtx
.PowerState
= ON_STATE
;
5693 gHaltRestartCtx
.MessageType
= kIOMessageSystemPagingOff
;
5694 gHaltRestartCtx
.LogString
= "PagingOff";
5695 IOService::updateConsoleUsers(NULL
, kIOMessageSystemPagingOff
);
5697 IOHibernateSystemRestart();
5705 gHaltRestartCtx
.phase
= kNotifyPriorityClients
;
5706 // Notify legacy clients
5707 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &gHaltRestartCtx
);
5709 // For normal shutdown, turn off File Server Mode.
5710 if (kPEHaltCPU
== pe_type
) {
5711 OSSharedPtr
<const OSSymbol
> setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
5712 OSSharedPtr
<OSNumber
> num
= OSNumber::withNumber((unsigned long long) 0, 32);
5713 if (setting
&& num
) {
5714 setPMSetting(setting
.get(), num
.get());
5718 if (kPEPagingOff
!= pe_type
) {
5719 gHaltRestartCtx
.phase
= kNotifyPowerPlaneDrivers
;
5720 // Notify in power tree order
5721 notifySystemShutdown(this, gHaltRestartCtx
.MessageType
);
5724 gHaltRestartCtx
.phase
= kNotifyHaltRestartAction
;
5725 #if defined(XNU_TARGET_OS_OSX)
5726 IOCPURunPlatformHaltRestartActions(pe_type
);
5727 #else /* !defined(XNU_TARGET_OS_OSX) */
5728 if (kPEPagingOff
!= pe_type
) {
5729 IOCPURunPlatformHaltRestartActions(pe_type
);
5731 #endif /* !defined(XNU_TARGET_OS_OSX) */
5733 // Wait for PM to quiesce
5734 if ((kPEPagingOff
!= pe_type
) && gPMHaltLock
) {
5735 gHaltRestartCtx
.phase
= kQuiescePM
;
5736 AbsoluteTime quiesceTime
= mach_absolute_time();
5738 IOLockLock(gPMHaltLock
);
5739 gPMQuiesced
= false;
5740 if (quiescePowerTree(this, &quiescePowerTreeCallback
, &gPMQuiesced
) ==
5742 while (!gPMQuiesced
) {
5743 IOLockSleep(gPMHaltLock
, &gPMQuiesced
, THREAD_UNINT
);
5746 IOLockUnlock(gPMHaltLock
);
5747 deltaTime
= computeDeltaTimeMS(&quiesceTime
, &elapsedTime
);
5748 DLOG("PM quiesce took %u ms\n", deltaTime
);
5749 halt_log_enter("Quiesce", NULL
, elapsedTime
);
5751 gHaltRestartCtx
.phase
= kNotifyDone
;
5753 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
5754 LOG("%s all drivers took %u ms\n", gHaltRestartCtx
.LogString
, deltaTime
);
5756 halt_log_enter(gHaltRestartCtx
.LogString
, NULL
, elapsedTime
);
5758 deltaTime
= computeDeltaTimeMS(&gHaltStartTime
, &elapsedTime
);
5759 LOG("%s total %u ms\n", gHaltRestartCtx
.LogString
, deltaTime
);
5761 if (gHaltLog
&& gHaltTimeMaxLog
&& (deltaTime
>= gHaltTimeMaxLog
)) {
5762 printf("%s total %d ms:%s\n", gHaltRestartCtx
.LogString
, deltaTime
, gHaltLog
);
5765 checkShutdownTimeout();
5769 IOPMrootDomain::checkShutdownTimeout()
5771 AbsoluteTime elapsedTime
;
5772 uint32_t deltaTime
= computeDeltaTimeMS(&gHaltStartTime
, &elapsedTime
);
5774 if (gHaltTimeMaxPanic
&& (deltaTime
>= gHaltTimeMaxPanic
)) {
5781 IOPMrootDomain::panicWithShutdownLog(uint32_t timeoutInMs
)
5784 if ((gHaltRestartCtx
.phase
== kNotifyPriorityClients
) && gHaltRestartCtx
.handler
) {
5785 halt_log_enter("Blocked on priority client", (void *)gHaltRestartCtx
.handler
, mach_absolute_time() - gHaltStartTime
);
5787 panic("%s timed out in phase '%s'. Total %d ms:%s",
5788 gHaltRestartCtx
.LogString
, shutdownPhase2String(gHaltRestartCtx
.phase
), timeoutInMs
, gHaltLog
);
5790 panic("%s timed out in phase \'%s\'. Total %d ms",
5791 gHaltRestartCtx
.LogString
, shutdownPhase2String(gHaltRestartCtx
.phase
), timeoutInMs
);
5795 //******************************************************************************
5798 //******************************************************************************
5801 IOPMrootDomain::shutdownSystem( void )
5803 return kIOReturnUnsupported
;
5806 //******************************************************************************
5809 //******************************************************************************
5812 IOPMrootDomain::restartSystem( void )
5814 return kIOReturnUnsupported
;
5818 // MARK: System Capability
5820 //******************************************************************************
5821 // tagPowerPlaneService
5823 // Running on PM work loop thread.
5824 //******************************************************************************
5827 IOPMrootDomain::tagPowerPlaneService(
5828 IOService
* service
,
5829 IOPMActions
* actions
,
5830 IOPMPowerStateIndex maxPowerState
)
5834 memset(actions
, 0, sizeof(*actions
));
5835 actions
->target
= this;
5837 if (service
== this) {
5838 actions
->actionPowerChangeStart
=
5839 OSMemberFunctionCast(
5840 IOPMActionPowerChangeStart
, this,
5841 &IOPMrootDomain::handleOurPowerChangeStart
);
5843 actions
->actionPowerChangeDone
=
5844 OSMemberFunctionCast(
5845 IOPMActionPowerChangeDone
, this,
5846 &IOPMrootDomain::handleOurPowerChangeDone
);
5848 actions
->actionPowerChangeOverride
=
5849 OSMemberFunctionCast(
5850 IOPMActionPowerChangeOverride
, this,
5851 &IOPMrootDomain::overrideOurPowerChange
);
5855 #if DISPLAY_WRANGLER_PRESENT
5856 if (NULL
!= service
->metaCast("IODisplayWrangler")) {
5857 // XXX should this really retain?
5858 wrangler
.reset(service
, OSRetain
);
5859 wrangler
->registerInterest(gIOGeneralInterest
,
5860 &displayWranglerNotification
, this, NULL
);
5862 // found the display wrangler, check for any display assertions already created
5863 if (pmAssertions
->getActivatedAssertions() & kIOPMDriverAssertionPreventDisplaySleepBit
) {
5864 DLOG("wrangler setIgnoreIdleTimer\(1) due to pre-existing assertion\n");
5865 wrangler
->setIgnoreIdleTimer( true );
5867 flags
|= kPMActionsFlagIsDisplayWrangler
;
5869 #endif /* DISPLAY_WRANGLER_PRESENT */
5871 if (service
->propertyExists("IOPMStrictTreeOrder")) {
5872 flags
|= kPMActionsFlagIsGraphicsDriver
;
5874 if (service
->propertyExists("IOPMUnattendedWakePowerState")) {
5875 flags
|= kPMActionsFlagIsAudioDriver
;
5878 OSSharedPtr
<OSObject
> prop
= service
->copyProperty(kIOPMDarkWakeMaxPowerStateKey
);
5880 OSNumber
* num
= OSDynamicCast(OSNumber
, prop
.get());
5882 actions
->darkWakePowerState
= num
->unsigned32BitValue();
5883 if (actions
->darkWakePowerState
< maxPowerState
) {
5884 flags
|= kPMActionsFlagHasDarkWakePowerState
;
5889 // Find the power connection object that is a child of the PCI host
5890 // bridge, and has a graphics/audio device attached below. Mark the
5891 // power branch for delayed child notifications.
5894 IORegistryEntry
* child
= service
;
5895 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
5897 while (child
!= this) {
5898 if (child
->propertyHasValue("IOPCITunnelled", kOSBooleanTrue
)) {
5899 // Skip delaying notifications and clamping power on external graphics and audio devices.
5900 DLOG("Avoiding delayChildNotification on object 0x%llx. flags: 0x%x\n", service
->getRegistryEntryID(), flags
);
5904 if ((parent
== pciHostBridgeDriver
) ||
5906 if (OSDynamicCast(IOPowerConnection
, child
)) {
5907 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
5908 conn
->delayChildNotification
= true;
5909 DLOG("delayChildNotification for 0x%llx\n", conn
->getRegistryEntryID());
5914 parent
= child
->getParentEntry(gIOPowerPlane
);
5919 DLOG("%s tag flags %x\n", service
->getName(), flags
);
5920 actions
->flags
|= flags
;
5921 actions
->actionPowerChangeOverride
=
5922 OSMemberFunctionCast(
5923 IOPMActionPowerChangeOverride
, this,
5924 &IOPMrootDomain::overridePowerChangeForService
);
5926 if (flags
& kPMActionsFlagIsDisplayWrangler
) {
5927 actions
->actionActivityTickle
=
5928 OSMemberFunctionCast(
5929 IOPMActionActivityTickle
, this,
5930 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
5932 actions
->actionUpdatePowerClient
=
5933 OSMemberFunctionCast(
5934 IOPMActionUpdatePowerClient
, this,
5935 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler
);
5940 // Locate the first PCI host bridge for PMTrace.
5941 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge")) {
5942 IOService
* provider
= service
->getProvider();
5943 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
5944 provider
->inPlane(gIODTPlane
)) {
5945 pciHostBridgeDevice
.reset(provider
, OSNoRetain
);
5946 pciHostBridgeDriver
.reset(service
, OSNoRetain
);
5947 DLOG("PMTrace found PCI host bridge %s->%s\n",
5948 provider
->getName(), service
->getName());
5952 // Tag top-level PCI devices. The order of PMinit() call does not
5953 // change across boots and is used as the PCI bit number.
5954 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice")) {
5955 // Would prefer to check built-in property, but tagPowerPlaneService()
5956 // is called before pciDevice->registerService().
5957 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
5958 if ((parent
== pciHostBridgeDevice
) && service
->propertyExists("acpi-device")) {
5959 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
5961 // Save the assigned bit for fast lookup.
5962 actions
->flags
|= (bit
& kPMActionsPCIBitNumberMask
);
5964 actions
->actionPowerChangeStart
=
5965 OSMemberFunctionCast(
5966 IOPMActionPowerChangeStart
, this,
5967 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
5969 actions
->actionPowerChangeDone
=
5970 OSMemberFunctionCast(
5971 IOPMActionPowerChangeDone
, this,
5972 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
5978 //******************************************************************************
5979 // PM actions for root domain
5980 //******************************************************************************
5983 IOPMrootDomain::overrideOurPowerChange(
5984 IOService
* service
,
5985 IOPMActions
* actions
,
5986 const IOPMRequest
* request
,
5987 IOPMPowerStateIndex
* inOutPowerState
,
5988 IOPMPowerChangeFlags
* inOutChangeFlags
)
5990 uint32_t changeFlags
= *inOutChangeFlags
;
5991 uint32_t desiredPowerState
= (uint32_t) *inOutPowerState
;
5992 uint32_t currentPowerState
= (uint32_t) getPowerState();
5994 if (request
->getTag() == 0) {
5995 // Set a tag for any request that originates from IOServicePM
5996 (const_cast<IOPMRequest
*>(request
))->fTag
= nextRequestTag(kCPSReasonPMInternals
);
5999 DLOG("PowerChangeOverride (%s->%s, %x, 0x%x) tag 0x%x\n",
6000 getPowerStateString(currentPowerState
),
6001 getPowerStateString(desiredPowerState
),
6002 _currentCapability
, changeFlags
,
6005 if ((AOT_STATE
== desiredPowerState
) && (ON_STATE
== currentPowerState
)) {
6006 // Assertion may have been taken in AOT leading to changePowerStateTo(AOT)
6007 *inOutChangeFlags
|= kIOPMNotDone
;
6011 if (changeFlags
& kIOPMParentInitiated
) {
6012 // Root parent is permanently pegged at max power,
6013 // a parent initiated power change is unexpected.
6014 *inOutChangeFlags
|= kIOPMNotDone
;
6018 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
6019 if (lowBatteryCondition
&& (desiredPowerState
< currentPowerState
)) {
6020 // Reject sleep requests when lowBatteryCondition is TRUE to
6021 // avoid racing with the impending system shutdown.
6022 *inOutChangeFlags
|= kIOPMNotDone
;
6027 if (desiredPowerState
< currentPowerState
) {
6028 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
)) {
6029 // Root domain is dropping power state from ON->SLEEP.
6030 // If system is in full wake, first enter dark wake by
6031 // converting the power drop to a capability change.
6032 // Once in dark wake, transition to sleep state ASAP.
6034 darkWakeToSleepASAP
= true;
6036 // Drop graphics and audio capability
6037 _desiredCapability
&= ~(
6038 kIOPMSystemCapabilityGraphics
|
6039 kIOPMSystemCapabilityAudio
);
6041 // Convert to capability change (ON->ON)
6042 *inOutPowerState
= getRUN_STATE();
6043 *inOutChangeFlags
|= kIOPMSynchronize
;
6045 // Revert device desire from SLEEP to ON
6046 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonPowerOverride
);
6048 // System is already in dark wake, ok to drop power state.
6049 // Broadcast root power down to entire tree.
6050 *inOutChangeFlags
|= kIOPMRootChangeDown
;
6052 } else if (desiredPowerState
> currentPowerState
) {
6053 if ((_currentCapability
& kIOPMSystemCapabilityCPU
) == 0) {
6054 // Broadcast power up when waking from sleep, but not for the
6055 // initial power change at boot by checking for cpu capability.
6056 *inOutChangeFlags
|= kIOPMRootChangeUp
;
6062 IOPMrootDomain::handleOurPowerChangeStart(
6063 IOService
* service
,
6064 IOPMActions
* actions
,
6065 const IOPMRequest
* request
,
6066 IOPMPowerStateIndex newPowerState
,
6067 IOPMPowerChangeFlags
* inOutChangeFlags
)
6069 IOPMRequestTag requestTag
= request
->getTag();
6070 IOPMRequestTag sleepReason
;
6072 uint32_t changeFlags
= *inOutChangeFlags
;
6073 uint32_t currentPowerState
= (uint32_t) getPowerState();
6074 bool publishSleepReason
= false;
6076 // Check if request has a valid sleep reason
6077 sleepReason
= REQUEST_TAG_TO_REASON(requestTag
);
6078 if (sleepReason
< kIOPMSleepReasonClamshell
) {
6079 sleepReason
= kIOPMSleepReasonIdle
;
6082 _systemTransitionType
= kSystemTransitionNone
;
6083 _systemMessageClientMask
= 0;
6084 capabilityLoss
= false;
6085 toldPowerdCapWillChange
= false;
6087 // Emergency notifications may arrive after the initial sleep request
6088 // has been queued. Override the sleep reason so powerd and others can
6089 // treat this as an emergency sleep.
6090 if (lowBatteryCondition
) {
6091 sleepReason
= kIOPMSleepReasonLowPower
;
6092 } else if (thermalEmergencyState
) {
6093 sleepReason
= kIOPMSleepReasonThermalEmergency
;
6096 // 1. Explicit capability change.
6097 if (changeFlags
& kIOPMSynchronize
) {
6098 if (newPowerState
== ON_STATE
) {
6099 if (changeFlags
& kIOPMSyncNoChildNotify
) {
6100 _systemTransitionType
= kSystemTransitionNewCapClient
;
6102 _systemTransitionType
= kSystemTransitionCapability
;
6106 // 2. Going to sleep (cancellation still possible).
6107 else if (newPowerState
< currentPowerState
) {
6108 _systemTransitionType
= kSystemTransitionSleep
;
6110 // 3. Woke from (idle or demand) sleep.
6111 else if (!systemBooting
&&
6112 (changeFlags
& kIOPMSelfInitiated
) &&
6113 (newPowerState
> currentPowerState
)) {
6114 _systemTransitionType
= kSystemTransitionWake
;
6115 _desiredCapability
= kIOPMSystemCapabilityCPU
| kIOPMSystemCapabilityNetwork
;
6117 // Early exit from dark wake to full (e.g. LID open)
6118 if (kFullWakeReasonNone
!= fullWakeReason
) {
6119 _desiredCapability
|= (
6120 kIOPMSystemCapabilityGraphics
|
6121 kIOPMSystemCapabilityAudio
);
6123 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
6124 if (fullWakeReason
== kFullWakeReasonLocalUser
) {
6125 darkWakeExit
= true;
6126 darkWakeToSleepASAP
= false;
6127 setProperty(kIOPMRootDomainWakeTypeKey
, isRTCAlarmWake
?
6128 kIOPMRootDomainWakeTypeAlarm
: kIOPMRootDomainWakeTypeUser
);
6133 IOHibernateSetWakeCapabilities(_desiredCapability
);
6137 // Update pending wake capability at the beginning of every
6138 // state transition (including synchronize). This will become
6139 // the current capability at the end of the transition.
6141 if (kSystemTransitionSleep
== _systemTransitionType
) {
6142 _pendingCapability
= 0;
6143 capabilityLoss
= true;
6144 } else if (kSystemTransitionNewCapClient
!= _systemTransitionType
) {
6145 _pendingCapability
= _desiredCapability
|
6146 kIOPMSystemCapabilityCPU
|
6147 kIOPMSystemCapabilityNetwork
;
6149 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
) {
6150 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
6153 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
6154 (_pendingCapability
== _currentCapability
)) {
6155 // Cancel the PM state change.
6156 _systemTransitionType
= kSystemTransitionNone
;
6157 *inOutChangeFlags
|= kIOPMNotDone
;
6159 if (__builtin_popcount(_pendingCapability
) <
6160 __builtin_popcount(_currentCapability
)) {
6161 capabilityLoss
= true;
6165 // 1. Capability change.
6166 if (kSystemTransitionCapability
== _systemTransitionType
) {
6167 // Dark to Full transition.
6168 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
)) {
6169 tracePoint( kIOPMTracePointDarkWakeExit
);
6171 #if defined(XNU_TARGET_OS_OSX)
6172 // rdar://problem/65627936
6173 // When a dark->full wake promotion is scheduled before an ON->SLEEP
6174 // power state drop, invalidate any request to drop power state already
6175 // in the queue, including the override variant, unless full wake cannot
6176 // be sustained. Any power state drop queued after this SustainFullWake
6177 // request will not be affected.
6178 if (checkSystemCanSustainFullWake()) {
6179 changePowerStateWithOverrideTo(getRUN_STATE(), kCPSReasonSustainFullWake
);
6183 willEnterFullWake();
6186 // Full to Dark transition.
6187 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
)) {
6188 // Clear previous stats
6189 IOLockLock(pmStatsLock
);
6190 if (pmStatsAppResponses
) {
6191 pmStatsAppResponses
= OSArray::withCapacity(5);
6193 IOLockUnlock(pmStatsLock
);
6195 tracePoint( kIOPMTracePointDarkWakeEntry
);
6196 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
6197 _systemMessageClientMask
= kSystemMessageClientPowerd
|
6198 kSystemMessageClientLegacyApp
;
6201 // Prevent user active transitions before notifying clients
6202 // that system will sleep.
6203 preventTransitionToUserActive(true);
6205 IOService::setAdvisoryTickleEnable( false );
6207 // Publish the sleep reason for full to dark wake
6208 publishSleepReason
= true;
6209 lastSleepReason
= fullToDarkReason
= sleepReason
;
6211 // Publish a UUID for the Sleep --> Wake cycle
6212 handlePublishSleepWakeUUID(true);
6213 if (sleepDelaysReport
) {
6214 clock_get_uptime(&ts_sleepStart
);
6215 DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart
);
6218 darkWakeExit
= false;
6222 else if (kSystemTransitionSleep
== _systemTransitionType
) {
6223 // Beginning of a system sleep transition.
6224 // Cancellation is still possible.
6225 tracePoint( kIOPMTracePointSleepStarted
);
6227 _systemMessageClientMask
= kSystemMessageClientAll
;
6228 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0) {
6229 _systemMessageClientMask
&= ~kSystemMessageClientLegacyApp
;
6231 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0) {
6232 // Kernel priority clients are only notified on the initial
6233 // transition to full wake, so don't notify them unless system
6234 // has gained graphics capability since the last system wake.
6235 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
6237 // System was in full wake, but the downwards power transition is driven
6238 // by a request that originates from IOServicePM, so it isn't tagged with
6239 // a valid system sleep reason.
6240 if (REQUEST_TAG_TO_REASON(requestTag
) == kCPSReasonPMInternals
) {
6241 // Publish the same reason for full to dark
6242 sleepReason
= fullToDarkReason
;
6246 gIOHibernateState
= 0;
6249 // Record the reason for dark wake back to sleep
6250 // System may not have ever achieved full wake
6252 publishSleepReason
= true;
6253 lastSleepReason
= sleepReason
;
6254 if (sleepDelaysReport
) {
6255 clock_get_uptime(&ts_sleepStart
);
6256 DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart
);
6260 else if (kSystemTransitionWake
== _systemTransitionType
) {
6261 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
6262 // Clear stats about sleep
6264 if (AOT_STATE
== newPowerState
) {
6265 _pendingCapability
= 0;
6268 if (AOT_STATE
== currentPowerState
) {
6269 // Wake events are no longer accepted after waking to AOT_STATE.
6270 // Re-enable wake event acceptance to append wake events claimed
6271 // during the AOT to ON_STATE transition.
6272 acceptSystemWakeEvents(kAcceptSystemWakeEvents_Reenable
);
6275 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
) {
6276 willEnterFullWake();
6280 // The only location where the sleep reason is published. At this point
6281 // sleep can still be cancelled, but sleep reason should be published
6282 // early for logging purposes.
6284 if (publishSleepReason
) {
6285 static const char * IOPMSleepReasons
[] =
6287 kIOPMClamshellSleepKey
,
6288 kIOPMPowerButtonSleepKey
,
6289 kIOPMSoftwareSleepKey
,
6290 kIOPMOSSwitchHibernationKey
,
6292 kIOPMLowPowerSleepKey
,
6293 kIOPMThermalEmergencySleepKey
,
6294 kIOPMMaintenanceSleepKey
,
6295 kIOPMSleepServiceExitKey
,
6296 kIOPMDarkWakeThermalEmergencyKey
,
6297 kIOPMNotificationWakeExitKey
6300 // Record sleep cause in IORegistry
6301 uint32_t reasonIndex
= sleepReason
- kIOPMSleepReasonClamshell
;
6302 if (reasonIndex
< sizeof(IOPMSleepReasons
) / sizeof(IOPMSleepReasons
[0])) {
6303 DLOG("sleep reason %s\n", IOPMSleepReasons
[reasonIndex
]);
6304 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[reasonIndex
]);
6308 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
6309 (kSystemTransitionNewCapClient
!= _systemTransitionType
)) {
6310 _systemStateGeneration
++;
6311 systemDarkWake
= false;
6313 DLOG("=== START (%s->%s, %x->%x, 0x%x) gen %u, msg %x, tag %x\n",
6314 getPowerStateString(currentPowerState
),
6315 getPowerStateString((uint32_t) newPowerState
),
6316 _currentCapability
, _pendingCapability
,
6317 *inOutChangeFlags
, _systemStateGeneration
, _systemMessageClientMask
,
6321 if ((AOT_STATE
== newPowerState
) && (SLEEP_STATE
!= currentPowerState
)) {
6322 panic("illegal AOT entry from %s", getPowerStateString(currentPowerState
));
6324 if (_aotNow
&& (ON_STATE
== newPowerState
)) {
6326 aotShouldExit(false, true);
6333 IOPMrootDomain::handleOurPowerChangeDone(
6334 IOService
* service
,
6335 IOPMActions
* actions
,
6336 const IOPMRequest
* request
,
6337 IOPMPowerStateIndex oldPowerState
,
6338 IOPMPowerChangeFlags changeFlags
)
6340 if (kSystemTransitionNewCapClient
== _systemTransitionType
) {
6341 _systemTransitionType
= kSystemTransitionNone
;
6345 if (_systemTransitionType
!= kSystemTransitionNone
) {
6346 uint32_t currentPowerState
= (uint32_t) getPowerState();
6348 if (changeFlags
& kIOPMNotDone
) {
6349 // Power down was cancelled or vetoed.
6350 _pendingCapability
= _currentCapability
;
6351 lastSleepReason
= 0;
6353 // When sleep is cancelled or reverted, don't report
6354 // the target (lower) power state as the previous state.
6355 oldPowerState
= currentPowerState
;
6357 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
) &&
6358 CAP_CURRENT(kIOPMSystemCapabilityCPU
)) {
6359 #if defined(XNU_TARGET_OS_OSX)
6360 pmPowerStateQueue
->submitPowerEvent(
6361 kPowerEventPolicyStimulus
,
6362 (void *) kStimulusDarkWakeReentry
,
6363 _systemStateGeneration
);
6364 #else /* !defined(XNU_TARGET_OS_OSX) */
6365 // On embedded, there are no factors that can prolong a
6366 // "darkWake" when a power down is vetoed. We need to
6367 // promote to "fullWake" at least once so that factors
6368 // that prevent idle sleep can assert themselves if required
6369 pmPowerStateQueue
->submitPowerEvent(
6370 kPowerEventPolicyStimulus
,
6371 (void *) kStimulusDarkWakeActivityTickle
);
6372 #endif /* !defined(XNU_TARGET_OS_OSX) */
6375 // Revert device desire to max.
6376 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonPowerDownCancel
);
6378 // Send message on dark wake to full wake promotion.
6379 // tellChangeUp() handles the normal SLEEP->ON case.
6381 if (kSystemTransitionCapability
== _systemTransitionType
) {
6382 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
)) {
6383 lastSleepReason
= 0; // stop logging wrangler tickles
6384 tellClients(kIOMessageSystemHasPoweredOn
);
6386 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
)) {
6387 // Going dark, reset full wake state
6388 // userIsActive will be cleared by wrangler powering down
6389 fullWakeReason
= kFullWakeReasonNone
;
6391 if (ts_sleepStart
) {
6392 clock_get_uptime(&wake2DarkwakeDelay
);
6393 SUB_ABSOLUTETIME(&wake2DarkwakeDelay
, &ts_sleepStart
);
6394 DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay
);
6400 // Reset state after exiting from dark wake.
6402 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
6403 CAP_LOSS(kIOPMSystemCapabilityCPU
)) {
6404 darkWakeMaintenance
= false;
6405 darkWakeToSleepASAP
= false;
6406 pciCantSleepValid
= false;
6407 darkWakeSleepService
= false;
6409 if (CAP_LOSS(kIOPMSystemCapabilityCPU
)) {
6410 // Remove the influence of display power assertion
6411 // before next system wake.
6413 wrangler
->changePowerStateForRootDomain(
6414 kWranglerPowerStateMin
);
6416 removeProperty(gIOPMUserTriggeredFullWakeKey
.get());
6420 // Entered dark mode.
6422 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
6423 (_pendingCapability
& kIOPMSystemCapabilityCPU
)) {
6424 // Queue an evaluation of whether to remain in dark wake,
6425 // and for how long. This serves the purpose of draining
6426 // any assertions from the queue.
6428 pmPowerStateQueue
->submitPowerEvent(
6429 kPowerEventPolicyStimulus
,
6430 (void *) kStimulusDarkWakeEntry
,
6431 _systemStateGeneration
);
6435 DLOG("=== FINISH (%s->%s, %x->%x, 0x%x) gen %u, msg %x, tag %x\n",
6436 getPowerStateString((uint32_t) oldPowerState
), getPowerStateString(currentPowerState
),
6437 _currentCapability
, _pendingCapability
,
6438 changeFlags
, _systemStateGeneration
, _systemMessageClientMask
,
6441 if ((currentPowerState
== ON_STATE
) && pmAssertions
) {
6442 pmAssertions
->reportCPUBitAccounting();
6445 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
) {
6447 #if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
6448 if (clamshellExists
&& fullWakeThreadCall
) {
6449 AbsoluteTime deadline
;
6450 clock_interval_to_deadline(DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
, kSecondScale
, &deadline
);
6451 thread_call_enter_delayed(fullWakeThreadCall
, deadline
);
6454 } else if (CAP_GAIN(kIOPMSystemCapabilityCPU
)) {
6458 // Update current system capability.
6459 if (_currentCapability
!= _pendingCapability
) {
6460 _currentCapability
= _pendingCapability
;
6463 // Update highest system capability.
6465 _highestCapability
|= _currentCapability
;
6467 if (darkWakePostTickle
&&
6468 (kSystemTransitionWake
== _systemTransitionType
) &&
6469 (gDarkWakeFlags
& kDarkWakeFlagPromotionMask
) ==
6470 kDarkWakeFlagPromotionLate
) {
6471 darkWakePostTickle
= false;
6473 } else if (darkWakeExit
) {
6474 requestFullWake( kFullWakeReasonLocalUser
);
6477 // Reset tracepoint at completion of capability change,
6478 // completion of wake transition, and aborted sleep transition.
6480 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
6481 (_systemTransitionType
== kSystemTransitionWake
) ||
6482 ((_systemTransitionType
== kSystemTransitionSleep
) &&
6483 (changeFlags
& kIOPMNotDone
))) {
6484 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
6485 tracePoint( kIOPMTracePointSystemUp
);
6488 _systemTransitionType
= kSystemTransitionNone
;
6489 _systemMessageClientMask
= 0;
6490 toldPowerdCapWillChange
= false;
6492 darkWakeLogClamp
= false;
6494 if (lowBatteryCondition
) {
6495 privateSleepSystem(kIOPMSleepReasonLowPower
);
6496 } else if (thermalEmergencyState
) {
6497 privateSleepSystem(kIOPMSleepReasonThermalEmergency
);
6498 } else if ((fullWakeReason
== kFullWakeReasonDisplayOn
) && !displayPowerOnRequested
) {
6499 // Request for full wake is removed while system is waking up to full wake
6500 DLOG("DisplayOn fullwake request is removed\n");
6501 handleSetDisplayPowerOn(false);
6504 if ((gClamshellFlags
& kClamshell_WAR_47715679
) && isRTCAlarmWake
) {
6505 pmPowerStateQueue
->submitPowerEvent(
6506 kPowerEventReceivedPowerNotification
, (void *)(uintptr_t) kLocalEvalClamshellCommand
);
6511 //******************************************************************************
6512 // PM actions for graphics and audio.
6513 //******************************************************************************
6516 IOPMrootDomain::overridePowerChangeForService(
6517 IOService
* service
,
6518 IOPMActions
* actions
,
6519 const IOPMRequest
* request
,
6520 IOPMPowerStateIndex
* inOutPowerState
,
6521 IOPMPowerChangeFlags
* inOutChangeFlags
)
6523 uint32_t powerState
= (uint32_t) *inOutPowerState
;
6524 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
6525 const uint32_t actionFlags
= actions
->flags
;
6527 if (kSystemTransitionNone
== _systemTransitionType
) {
6528 // Not in midst of a system transition.
6529 // Do not set kPMActionsStatePowerClamped.
6530 } else if ((actions
->state
& kPMActionsStatePowerClamped
) == 0) {
6531 bool enableClamp
= false;
6533 // For most drivers, enable the clamp during ON->Dark transition
6534 // which has the kIOPMSynchronize flag set in changeFlags.
6535 if ((actionFlags
& kPMActionsFlagIsDisplayWrangler
) &&
6536 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
6537 (changeFlags
& kIOPMSynchronize
)) {
6539 } else if ((actionFlags
& kPMActionsFlagIsAudioDriver
) &&
6540 ((gDarkWakeFlags
& kDarkWakeFlagAudioNotSuppressed
) == 0) &&
6541 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0) &&
6542 (changeFlags
& kIOPMSynchronize
)) {
6544 } else if ((actionFlags
& kPMActionsFlagHasDarkWakePowerState
) &&
6545 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
6546 (changeFlags
& kIOPMSynchronize
)) {
6548 } else if ((actionFlags
& kPMActionsFlagIsGraphicsDriver
) &&
6549 (_systemTransitionType
== kSystemTransitionSleep
)) {
6550 // For graphics drivers, clamp power when entering
6551 // system sleep. Not when dropping to dark wake.
6556 actions
->state
|= kPMActionsStatePowerClamped
;
6557 DLOG("power clamp enabled %s %qx, pendingCap 0x%x, ps %d, cflags 0x%x\n",
6558 service
->getName(), service
->getRegistryEntryID(),
6559 _pendingCapability
, powerState
, changeFlags
);
6561 } else if ((actions
->state
& kPMActionsStatePowerClamped
) != 0) {
6562 bool disableClamp
= false;
6564 if ((actionFlags
& (
6565 kPMActionsFlagIsDisplayWrangler
|
6566 kPMActionsFlagIsGraphicsDriver
)) &&
6567 (_pendingCapability
& kIOPMSystemCapabilityGraphics
)) {
6568 disableClamp
= true;
6569 } else if ((actionFlags
& kPMActionsFlagIsAudioDriver
) &&
6570 (_pendingCapability
& kIOPMSystemCapabilityAudio
)) {
6571 disableClamp
= true;
6572 } else if ((actionFlags
& kPMActionsFlagHasDarkWakePowerState
) &&
6573 (_pendingCapability
& kIOPMSystemCapabilityGraphics
)) {
6574 disableClamp
= true;
6578 actions
->state
&= ~kPMActionsStatePowerClamped
;
6579 DLOG("power clamp removed %s %qx, pendingCap 0x%x, ps %d, cflags 0x%x\n",
6580 service
->getName(), service
->getRegistryEntryID(),
6581 _pendingCapability
, powerState
, changeFlags
);
6585 if (actions
->state
& kPMActionsStatePowerClamped
) {
6586 uint32_t maxPowerState
= 0;
6588 // Determine the max power state allowed when clamp is enabled
6589 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
)) {
6590 // Parent intiated power state changes
6591 if ((service
->getPowerState() > maxPowerState
) &&
6592 (actionFlags
& kPMActionsFlagIsDisplayWrangler
)) {
6595 // Remove lingering effects of any tickle before entering
6596 // dark wake. It will take a new tickle to return to full
6597 // wake, so the existing tickle state is useless.
6599 if (changeFlags
& kIOPMDomainDidChange
) {
6600 *inOutChangeFlags
|= kIOPMExpireIdleTimer
;
6602 } else if (actionFlags
& kPMActionsFlagIsGraphicsDriver
) {
6604 } else if (actionFlags
& kPMActionsFlagHasDarkWakePowerState
) {
6605 maxPowerState
= actions
->darkWakePowerState
;
6608 // Deny all self-initiated changes when power is limited.
6609 // Wrangler tickle should never defeat the limiter.
6610 maxPowerState
= service
->getPowerState();
6613 if (powerState
> maxPowerState
) {
6614 DLOG("power clamped %s %qx, ps %u->%u, cflags 0x%x)\n",
6615 service
->getName(), service
->getRegistryEntryID(),
6616 powerState
, maxPowerState
, changeFlags
);
6617 *inOutPowerState
= maxPowerState
;
6619 if (darkWakePostTickle
&&
6620 (actionFlags
& kPMActionsFlagIsDisplayWrangler
) &&
6621 (changeFlags
& kIOPMDomainWillChange
) &&
6622 ((gDarkWakeFlags
& kDarkWakeFlagPromotionMask
) ==
6623 kDarkWakeFlagPromotionEarly
)) {
6624 darkWakePostTickle
= false;
6629 if (!darkWakePowerClamped
&& (changeFlags
& kIOPMDomainDidChange
)) {
6630 if (darkWakeLogClamp
) {
6634 clock_get_uptime(&now
);
6635 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
6636 absolutetime_to_nanoseconds(now
, &nsec
);
6637 DLOG("dark wake power clamped after %u ms\n",
6638 ((int)((nsec
) / NSEC_PER_MSEC
)));
6640 darkWakePowerClamped
= true;
6646 IOPMrootDomain::handleActivityTickleForDisplayWrangler(
6647 IOService
* service
,
6648 IOPMActions
* actions
)
6650 #if DISPLAY_WRANGLER_PRESENT
6651 // Warning: Not running in PM work loop context - don't modify state !!!
6652 // Trap tickle directed to IODisplayWrangler while running with graphics
6653 // capability suppressed.
6655 assert(service
== wrangler
);
6657 clock_get_uptime(&userActivityTime
);
6658 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
6659 || (lastSleepReason
== kIOPMSleepReasonMaintenance
)
6660 || (lastSleepReason
== kIOPMSleepReasonSoftware
));
6662 userActivityCount
++;
6663 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
6664 userActivityCount
, lastSleepReason
);
6667 if (!darkWakeExit
&& ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0)) {
6668 DLOG("display wrangler tickled\n");
6669 if (kIOLogPMRootDomain
& gIOKitDebug
) {
6670 OSReportWithBacktrace("Dark wake display tickle");
6672 if (pmPowerStateQueue
) {
6673 pmPowerStateQueue
->submitPowerEvent(
6674 kPowerEventPolicyStimulus
,
6675 (void *) kStimulusDarkWakeActivityTickle
,
6676 true /* set wake type */ );
6679 #endif /* DISPLAY_WRANGLER_PRESENT */
6683 IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
6684 IOService
* service
,
6685 IOPMActions
* actions
,
6686 const OSSymbol
* powerClient
,
6687 IOPMPowerStateIndex oldPowerState
,
6688 IOPMPowerStateIndex newPowerState
)
6690 #if DISPLAY_WRANGLER_PRESENT
6691 assert(service
== wrangler
);
6693 // This function implements half of the user active detection
6694 // by monitoring changes to the display wrangler's device desire.
6696 // User becomes active when either:
6697 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
6698 // in max power state. This desire change in absence of a power state
6699 // change is detected within. This handles the case when user becomes
6700 // active while the display is already lit by setDisplayPowerOn().
6702 // 2. Power state change to max, and DeviceDesire is also at max.
6703 // Handled by displayWranglerNotification().
6705 // User becomes inactive when DeviceDesire drops to sleep state or below.
6707 DLOG("wrangler %s (ps %u, %u->%u)\n",
6708 powerClient
->getCStringNoCopy(),
6709 (uint32_t) service
->getPowerState(),
6710 (uint32_t) oldPowerState
, (uint32_t) newPowerState
);
6712 if (powerClient
== gIOPMPowerClientDevice
) {
6713 if ((newPowerState
> oldPowerState
) &&
6714 (newPowerState
== kWranglerPowerStateMax
) &&
6715 (service
->getPowerState() == kWranglerPowerStateMax
)) {
6716 evaluatePolicy( kStimulusEnterUserActiveState
);
6717 } else if ((newPowerState
< oldPowerState
) &&
6718 (newPowerState
<= kWranglerPowerStateSleep
)) {
6719 evaluatePolicy( kStimulusLeaveUserActiveState
);
6723 if (newPowerState
<= kWranglerPowerStateSleep
) {
6724 evaluatePolicy( kStimulusDisplayWranglerSleep
);
6725 } else if (newPowerState
== kWranglerPowerStateMax
) {
6726 evaluatePolicy( kStimulusDisplayWranglerWake
);
6728 #endif /* DISPLAY_WRANGLER_PRESENT */
6731 //******************************************************************************
6732 // User active state management
6733 //******************************************************************************
6736 IOPMrootDomain::preventTransitionToUserActive( bool prevent
)
6738 #if DISPLAY_WRANGLER_PRESENT
6739 _preventUserActive
= prevent
;
6740 if (wrangler
&& !_preventUserActive
) {
6741 // Allowing transition to user active, but the wrangler may have
6742 // already powered ON in case of sleep cancel/revert. Poll the
6743 // same conditions checked for in displayWranglerNotification()
6744 // to bring the user active state up to date.
6746 if ((wrangler
->getPowerState() == kWranglerPowerStateMax
) &&
6747 (wrangler
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
6748 kWranglerPowerStateMax
)) {
6749 evaluatePolicy( kStimulusEnterUserActiveState
);
6752 #endif /* DISPLAY_WRANGLER_PRESENT */
6755 //******************************************************************************
6756 // Approve usage of delayed child notification by PM.
6757 //******************************************************************************
6760 IOPMrootDomain::shouldDelayChildNotification(
6761 IOService
* service
)
6763 if ((kFullWakeReasonNone
== fullWakeReason
) &&
6764 (kSystemTransitionWake
== _systemTransitionType
)) {
6765 DLOG("%s: delay child notify\n", service
->getName());
6771 //******************************************************************************
6772 // PM actions for PCI device.
6773 //******************************************************************************
6776 IOPMrootDomain::handlePowerChangeStartForPCIDevice(
6777 IOService
* service
,
6778 IOPMActions
* actions
,
6779 const IOPMRequest
* request
,
6780 IOPMPowerStateIndex powerState
,
6781 IOPMPowerChangeFlags
* inOutChangeFlags
)
6783 pmTracer
->tracePCIPowerChange(
6784 PMTraceWorker::kPowerChangeStart
,
6785 service
, *inOutChangeFlags
,
6786 (actions
->flags
& kPMActionsPCIBitNumberMask
));
6790 IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
6791 IOService
* service
,
6792 IOPMActions
* actions
,
6793 const IOPMRequest
* request
,
6794 IOPMPowerStateIndex powerState
,
6795 IOPMPowerChangeFlags changeFlags
)
6797 pmTracer
->tracePCIPowerChange(
6798 PMTraceWorker::kPowerChangeCompleted
,
6799 service
, changeFlags
,
6800 (actions
->flags
& kPMActionsPCIBitNumberMask
));
6803 //******************************************************************************
6806 // Override IOService::registerInterest() for root domain clients.
6807 //******************************************************************************
6809 class IOPMServiceInterestNotifier
: public _IOServiceInterestNotifier
6811 friend class IOPMrootDomain
;
6812 OSDeclareDefaultStructors(IOPMServiceInterestNotifier
);
6815 uint32_t ackTimeoutCnt
;
6816 uint32_t msgType
; // Message pending ack
6818 uint32_t maxMsgDelayMS
;
6819 uint32_t maxAckDelayMS
;
6820 uint64_t msgAbsTime
;
6823 OSSharedPtr
<const OSSymbol
> identifier
;
6824 OSSharedPtr
<const OSSymbol
> clientName
;
6827 OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier
, _IOServiceInterestNotifier
)
6829 OSSharedPtr
<IONotifier
>
6830 IOPMrootDomain::registerInterest(
6831 const OSSymbol
* typeOfInterest
,
6832 IOServiceInterestHandler handler
,
6833 void * target
, void * ref
)
6835 IOPMServiceInterestNotifier
* notifier
;
6836 bool isSystemCapabilityClient
;
6837 bool isKernelCapabilityClient
;
6838 IOReturn rc
= kIOReturnError
;
6840 isSystemCapabilityClient
= typeOfInterest
&&
6841 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
6843 isKernelCapabilityClient
= typeOfInterest
&&
6844 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
6846 if (isSystemCapabilityClient
) {
6847 typeOfInterest
= gIOAppPowerStateInterest
;
6850 notifier
= new IOPMServiceInterestNotifier
;
6855 if (notifier
->init()) {
6856 rc
= super::registerInterestForNotifier(notifier
, typeOfInterest
, handler
, target
, ref
);
6858 if (rc
!= kIOReturnSuccess
) {
6862 notifier
->ackTimeoutCnt
= 0;
6864 if (pmPowerStateQueue
) {
6865 if (isSystemCapabilityClient
) {
6867 if (pmPowerStateQueue
->submitPowerEvent(
6868 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false) {
6869 notifier
->release();
6873 if (isKernelCapabilityClient
) {
6875 if (pmPowerStateQueue
->submitPowerEvent(
6876 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false) {
6877 notifier
->release();
6882 OSSharedPtr
<OSData
> data
;
6883 uint8_t *uuid
= NULL
;
6884 OSSharedPtr
<OSKext
> kext
= OSKext::lookupKextWithAddress((vm_address_t
)handler
);
6886 data
= kext
->copyUUID();
6888 if (data
&& (data
->getLength() == sizeof(uuid_t
))) {
6889 uuid
= (uint8_t *)(data
->getBytesNoCopy());
6891 notifier
->uuid0
= ((uint64_t)(uuid
[0]) << 56) | ((uint64_t)(uuid
[1]) << 48) | ((uint64_t)(uuid
[2]) << 40) |
6892 ((uint64_t)(uuid
[3]) << 32) | ((uint64_t)(uuid
[4]) << 24) | ((uint64_t)(uuid
[5]) << 16) |
6893 ((uint64_t)(uuid
[6]) << 8) | (uuid
[7]);
6894 notifier
->uuid1
= ((uint64_t)(uuid
[8]) << 56) | ((uint64_t)(uuid
[9]) << 48) | ((uint64_t)(uuid
[10]) << 40) |
6895 ((uint64_t)(uuid
[11]) << 32) | ((uint64_t)(uuid
[12]) << 24) | ((uint64_t)(uuid
[13]) << 16) |
6896 ((uint64_t)(uuid
[14]) << 8) | (uuid
[15]);
6898 notifier
->identifier
= copyKextIdentifierWithAddress((vm_address_t
) handler
);
6900 return OSSharedPtr
<IOPMServiceInterestNotifier
>(notifier
, OSNoRetain
);
6903 //******************************************************************************
6904 // systemMessageFilter
6906 //******************************************************************************
6909 IOPMrootDomain::systemMessageFilter(
6910 void * object
, void * arg1
, void * arg2
, void * arg3
)
6912 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
6913 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
6914 bool isCapClient
= false;
6916 IOPMServiceInterestNotifier
*notifier
;
6918 notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, (OSObject
*)object
);
6921 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
6922 (!isCapMsg
|| !_joinedCapabilityClients
||
6923 !_joinedCapabilityClients
->containsObject((OSObject
*) object
))) {
6927 // Capability change message for app and kernel clients.
6931 if ((context
->notifyType
== kNotifyPriority
) ||
6932 (context
->notifyType
== kNotifyCapabilityChangePriority
)) {
6936 // powerd's systemCapabilityNotifier
6937 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
6938 (object
== (void *) systemCapabilityNotifier
.get())) {
6944 IOPMSystemCapabilityChangeParameters
* capArgs
=
6945 (IOPMSystemCapabilityChangeParameters
*) arg2
;
6947 if (kSystemTransitionNewCapClient
== _systemTransitionType
) {
6948 capArgs
->fromCapabilities
= 0;
6949 capArgs
->toCapabilities
= _currentCapability
;
6950 capArgs
->changeFlags
= 0;
6952 capArgs
->fromCapabilities
= _currentCapability
;
6953 capArgs
->toCapabilities
= _pendingCapability
;
6955 if (context
->isPreChange
) {
6956 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
6958 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
6961 if ((object
== (void *) systemCapabilityNotifier
.get()) &&
6962 context
->isPreChange
) {
6963 toldPowerdCapWillChange
= true;
6967 // Capability change messages only go to the PM configd plugin.
6968 // Wait for response post-change if capabilitiy is increasing.
6969 // Wait for response pre-change if capability is decreasing.
6971 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
6972 ((capabilityLoss
&& context
->isPreChange
) ||
6973 (!capabilityLoss
&& !context
->isPreChange
))) {
6974 // app has not replied yet, wait for it
6975 *((OSObject
**) arg3
) = kOSBooleanFalse
;
6982 // Capability client will always see kIOMessageCanSystemSleep,
6983 // even for demand sleep. It will also have a chance to veto
6984 // sleep one last time after all clients have responded to
6985 // kIOMessageSystemWillSleep
6987 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
6988 (kIOMessageSystemWillNotSleep
== context
->messageType
)) {
6989 if (object
== (OSObject
*) systemCapabilityNotifier
.get()) {
6994 // Not idle sleep, don't ask apps.
6995 if (context
->changeFlags
& kIOPMSkipAskPowerDown
) {
7000 if (kIOPMMessageLastCallBeforeSleep
== context
->messageType
) {
7001 if ((object
== (OSObject
*) systemCapabilityNotifier
.get()) &&
7002 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) &&
7003 (fullToDarkReason
== kIOPMSleepReasonIdle
)) {
7009 // Reject capability change messages for legacy clients.
7010 // Reject legacy system sleep messages for capability client.
7012 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
.get())) {
7016 // Filter system sleep messages.
7018 if ((context
->notifyType
== kNotifyApps
) &&
7019 (_systemMessageClientMask
& kSystemMessageClientLegacyApp
)) {
7024 if (notifier
->ackTimeoutCnt
>= 3) {
7025 *((OSObject
**) arg3
) = kOSBooleanFalse
;
7027 *((OSObject
**) arg3
) = kOSBooleanTrue
;
7031 } else if ((context
->notifyType
== kNotifyPriority
) &&
7032 (_systemMessageClientMask
& kSystemMessageClientKernel
)) {
7037 if (allow
&& isCapMsg
&& _joinedCapabilityClients
) {
7038 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
7039 if (_joinedCapabilityClients
->getCount() == 0) {
7040 DLOG("destroyed capability client set %p\n",
7041 OBFUSCATE(_joinedCapabilityClients
.get()));
7042 _joinedCapabilityClients
.reset();
7046 notifier
->msgType
= context
->messageType
;
7052 //******************************************************************************
7053 // setMaintenanceWakeCalendar
7055 //******************************************************************************
7058 IOPMrootDomain::setMaintenanceWakeCalendar(
7059 const IOPMCalendarStruct
* calendar
)
7061 OSSharedPtr
<OSData
> data
;
7065 return kIOReturnBadArgument
;
7068 data
= OSData::withBytes((void *) calendar
, sizeof(*calendar
));
7070 return kIOReturnNoMemory
;
7073 if (kPMCalendarTypeMaintenance
== calendar
->selector
) {
7074 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
.get(), data
.get());
7075 } else if (kPMCalendarTypeSleepService
== calendar
->selector
) {
7076 ret
= setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey
.get(), data
.get());
7083 // MARK: Display Wrangler
7085 //******************************************************************************
7086 // displayWranglerNotification
7088 // Handle the notification when the IODisplayWrangler changes power state.
7089 //******************************************************************************
7092 IOPMrootDomain::displayWranglerNotification(
7093 void * target
, void * refCon
,
7094 UInt32 messageType
, IOService
* service
,
7095 void * messageArgument
, vm_size_t argSize
)
7097 #if DISPLAY_WRANGLER_PRESENT
7098 IOPMPowerStateIndex displayPowerState
;
7099 IOPowerStateChangeNotification
* params
=
7100 (IOPowerStateChangeNotification
*) messageArgument
;
7102 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
7103 (messageType
!= kIOMessageDeviceHasPoweredOn
)) {
7104 return kIOReturnUnsupported
;
7109 return kIOReturnUnsupported
;
7112 displayPowerState
= params
->stateNumber
;
7113 DLOG("wrangler %s ps %d\n",
7114 getIOMessageString(messageType
), (uint32_t) displayPowerState
);
7116 switch (messageType
) {
7117 case kIOMessageDeviceWillPowerOff
:
7118 // Display wrangler has dropped power due to display idle
7119 // or force system sleep.
7121 // 4 Display ON kWranglerPowerStateMax
7122 // 3 Display Dim kWranglerPowerStateDim
7123 // 2 Display Sleep kWranglerPowerStateSleep
7124 // 1 Not visible to user
7125 // 0 Not visible to user kWranglerPowerStateMin
7127 if (displayPowerState
<= kWranglerPowerStateSleep
) {
7128 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
7132 case kIOMessageDeviceHasPoweredOn
:
7133 // Display wrangler has powered on due to user activity
7134 // or wake from sleep.
7136 if (kWranglerPowerStateMax
== displayPowerState
) {
7137 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
7139 // See comment in handleUpdatePowerClientForDisplayWrangler
7140 if (service
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
7141 kWranglerPowerStateMax
) {
7142 gRootDomain
->evaluatePolicy( kStimulusEnterUserActiveState
);
7147 #endif /* DISPLAY_WRANGLER_PRESENT */
7148 return kIOReturnUnsupported
;
7151 //******************************************************************************
7154 //******************************************************************************
7157 IOPMrootDomain::updateUserActivity( void )
7159 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
7160 clock_get_uptime(&userActivityTime
);
7161 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonSoftware
)
7162 || (lastSleepReason
== kIOPMSleepReasonIdle
)
7163 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
7165 userActivityCount
++;
7166 DLOG("user activity reported %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
7171 IOPMrootDomain::reportUserInput( void )
7174 wrangler
->activityTickle(0, 0);
7176 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
7177 // Update user activity
7178 updateUserActivity();
7180 if (!darkWakeExit
&& ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0)) {
7181 // update user active abs time
7182 clock_get_uptime(&gUserActiveAbsTime
);
7183 pmPowerStateQueue
->submitPowerEvent(
7184 kPowerEventPolicyStimulus
,
7185 (void *) kStimulusDarkWakeActivityTickle
,
7186 true /* set wake type */ );
7192 IOPMrootDomain::requestUserActive(IOService
*device
, const char *reason
)
7194 #if DISPLAY_WRANGLER_PRESENT
7196 wrangler
->activityTickle(0, 0);
7200 DLOG("requestUserActive: device is null\n");
7203 OSSharedPtr
<const OSSymbol
> deviceName
= device
->copyName();
7204 uint64_t registryID
= device
->getRegistryEntryID();
7206 if (!deviceName
|| !registryID
) {
7207 DLOG("requestUserActive: no device name or registry entry\n");
7210 const char *name
= deviceName
->getCStringNoCopy();
7212 snprintf(payload
, sizeof(payload
), "%s:%s", name
, reason
);
7213 DLOG("requestUserActive from %s (0x%llx) for %s\n", name
, registryID
, reason
);
7214 messageClient(kIOPMMessageRequestUserActive
, systemCapabilityNotifier
.get(), (void *)payload
, sizeof(payload
));
7218 //******************************************************************************
7219 // latchDisplayWranglerTickle
7220 //******************************************************************************
7223 IOPMrootDomain::latchDisplayWranglerTickle( bool latch
)
7225 #if DISPLAY_WRANGLER_PRESENT
7227 if (!(_currentCapability
& kIOPMSystemCapabilityGraphics
) &&
7228 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
7229 !checkSystemCanSustainFullWake()) {
7230 // Currently in dark wake, and not transitioning to full wake.
7231 // Full wake is unsustainable, so latch the tickle to prevent
7232 // the display from lighting up momentarily.
7233 wranglerTickled
= true;
7235 wranglerTickled
= false;
7237 } else if (wranglerTickled
&& checkSystemCanSustainFullWake()) {
7238 wranglerTickled
= false;
7240 pmPowerStateQueue
->submitPowerEvent(
7241 kPowerEventPolicyStimulus
,
7242 (void *) kStimulusDarkWakeActivityTickle
);
7245 return wranglerTickled
;
7246 #else /* ! DISPLAY_WRANGLER_PRESENT */
7248 #endif /* ! DISPLAY_WRANGLER_PRESENT */
7251 //******************************************************************************
7252 // setDisplayPowerOn
7254 // For root domain user client
7255 //******************************************************************************
7258 IOPMrootDomain::setDisplayPowerOn( uint32_t options
)
7260 pmPowerStateQueue
->submitPowerEvent( kPowerEventSetDisplayPowerOn
,
7261 (void *) NULL
, options
);
7265 // MARK: System PM Policy
7267 //******************************************************************************
7268 // checkSystemSleepAllowed
7270 //******************************************************************************
7273 IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options
,
7274 uint32_t sleepReason
)
7278 // Conditions that prevent idle and demand system sleep.
7281 if (userDisabledAllSleep
) {
7282 err
= kPMUserDisabledAllSleep
; // 1. user-space sleep kill switch
7286 if (systemBooting
|| systemShutdown
|| gWillShutdown
) {
7287 err
= kPMSystemRestartBootingInProgress
; // 2. restart or shutdown in progress
7295 // Conditions above pegs the system at full wake.
7296 // Conditions below prevent system sleep but does not prevent
7297 // dark wake, and must be called from gated context.
7300 err
= kPMConfigPreventSystemSleep
; // 3. config does not support sleep
7304 if (lowBatteryCondition
|| thermalWarningState
|| thermalEmergencyState
) {
7305 break; // always sleep on low battery or when in thermal warning/emergency state
7308 if (sleepReason
== kIOPMSleepReasonDarkWakeThermalEmergency
) {
7309 break; // always sleep on dark wake thermal emergencies
7312 if (preventSystemSleepList
->getCount() != 0) {
7313 err
= kPMChildPreventSystemSleep
; // 4. child prevent system sleep clamp
7317 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
7318 kIOPMDriverAssertionLevelOn
) {
7319 err
= kPMCPUAssertion
; // 5. CPU assertion
7323 if (pciCantSleepValid
) {
7324 if (pciCantSleepFlag
) {
7325 err
= kPMPCIUnsupported
; // 6. PCI card does not support PM (cached)
7328 } else if (sleepSupportedPEFunction
&&
7329 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
)) {
7331 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
7332 ret
= getPlatform()->callPlatformFunction(
7333 sleepSupportedPEFunction
.get(), false,
7334 NULL
, NULL
, NULL
, NULL
);
7335 pciCantSleepValid
= true;
7336 pciCantSleepFlag
= false;
7337 if ((platformSleepSupport
& kPCICantSleep
) ||
7338 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
))) {
7339 err
= 6; // 6. PCI card does not support PM
7340 pciCantSleepFlag
= true;
7347 DLOG("System sleep prevented by %s\n", getSystemSleepPreventerString(err
));
7354 IOPMrootDomain::checkSystemSleepEnabled( void )
7356 return checkSystemSleepAllowed(0, 0);
7360 IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason
)
7363 return checkSystemSleepAllowed(1, sleepReason
);
7366 //******************************************************************************
7367 // checkSystemCanSustainFullWake
7368 //******************************************************************************
7371 IOPMrootDomain::checkSystemCanSustainFullWake( void )
7373 if (lowBatteryCondition
|| thermalWarningState
|| thermalEmergencyState
) {
7374 // Low battery wake, or received a low battery notification
7375 // while system is awake. This condition will persist until
7376 // the following wake.
7380 if (clamshellExists
&& clamshellClosed
&& !clamshellSleepDisableMask
) {
7381 // Graphics state is unknown and external display might not be probed.
7382 // Do not incorporate state that requires graphics to be in max power
7383 // such as desktopMode or clamshellDisabled.
7385 if (!acAdaptorConnected
) {
7386 DLOG("full wake check: no AC\n");
7393 //******************************************************************************
7395 //******************************************************************************
7400 IOPMrootDomain::mustHibernate( void )
7402 return lowBatteryCondition
|| thermalWarningState
;
7405 #endif /* HIBERNATION */
7407 //******************************************************************************
7409 //******************************************************************************
7411 // Tables for accumulated days in year by month, latter used for leap years
7413 static const unsigned int daysbymonth
[] =
7414 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
7416 static const unsigned int lydaysbymonth
[] =
7417 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 };
7420 IOPMConvertSecondsToCalendar(clock_sec_t secs
, IOPMCalendarStruct
* dt
)
7422 const unsigned int * dbm
= daysbymonth
;
7423 clock_sec_t n
, x
, y
, z
;
7425 // Calculate seconds, minutes and hours
7427 n
= secs
% (24 * 3600);
7428 dt
->second
= n
% 60;
7430 dt
->minute
= n
% 60;
7431 dt
->hour
= (typeof(dt
->hour
))(n
/ 60);
7433 // Calculate day of week
7435 n
= secs
/ (24 * 3600);
7436 // dt->dayWeek = (n + 4) % 7;
7439 // Rebase from days since Unix epoch (1/1/1970) store in 'n',
7440 // to days since 1/1/1968 to start on 4 year cycle, beginning
7445 // Every 4 year cycle will be exactly (366 + 365 * 3) = 1461 days.
7446 // Valid before 2100, since 2100 is not a leap year.
7448 x
= n
/ 1461; // number of 4 year cycles
7449 y
= n
% 1461; // days into current 4 year cycle
7452 // Add in years in the current 4 year cycle
7455 y
-= 366; // days after the leap year
7456 n
= y
% 365; // days into the current year
7457 z
+= (1 + y
/ 365); // years after the past 4-yr cycle
7460 dbm
= lydaysbymonth
;
7466 dt
->year
= (typeof(dt
->year
))z
;
7468 // Adjust remaining days value to start at 1
7474 for (x
= 1; (n
> dbm
[x
]) && (x
< 12); x
++) {
7477 dt
->month
= (typeof(dt
->month
))x
;
7479 // Calculate day of month
7481 dt
->day
= (typeof(dt
->day
))(n
- dbm
[x
- 1]);
7487 IOPMConvertCalendarToSeconds(const IOPMCalendarStruct
* dt
)
7489 const unsigned int * dbm
= daysbymonth
;
7492 if (dt
->year
< 1970 || dt
->month
> 12) {
7496 // Seconds elapsed in the current day
7498 secs
= dt
->second
+ 60 * dt
->minute
+ 3600 * dt
->hour
;
7500 // Number of days from 1/1/70 to beginning of current year
7501 // Account for extra day every 4 years starting at 1973
7503 y
= dt
->year
- 1970;
7504 days
= (y
* 365) + ((y
+ 1) / 4);
7506 // Change table if current year is a leap year
7508 if ((dt
->year
% 4) == 0) {
7509 dbm
= lydaysbymonth
;
7512 // Add in days elapsed in the current year
7514 days
+= (dt
->day
- 1) + dbm
[dt
->month
- 1];
7516 // Add accumulated days to accumulated seconds
7518 secs
+= 24 * 3600 * days
;
7524 IOPMrootDomain::getRUN_STATE(void)
7526 return _aotNow
? AOT_STATE
: ON_STATE
;
7530 IOPMrootDomain::isAOTMode()
7536 IOPMrootDomain::setWakeTime(uint64_t wakeContinuousTime
)
7538 clock_sec_t nowsecs
, wakesecs
;
7539 clock_usec_t nowmicrosecs
, wakemicrosecs
;
7540 uint64_t nowAbs
, wakeAbs
;
7542 clock_gettimeofday_and_absolute_time(&nowsecs
, &nowmicrosecs
, &nowAbs
);
7543 wakeAbs
= continuoustime_to_absolutetime(wakeContinuousTime
);
7544 if (wakeAbs
< nowAbs
) {
7545 printf(LOG_PREFIX
"wakeAbs %qd < nowAbs %qd\n", wakeAbs
, nowAbs
);
7549 absolutetime_to_microtime(wakeAbs
, &wakesecs
, &wakemicrosecs
);
7551 wakesecs
+= nowsecs
;
7552 wakemicrosecs
+= nowmicrosecs
;
7553 if (wakemicrosecs
>= USEC_PER_SEC
) {
7555 wakemicrosecs
-= USEC_PER_SEC
;
7557 if (wakemicrosecs
>= (USEC_PER_SEC
/ 10)) {
7561 IOPMConvertSecondsToCalendar(wakesecs
, &_aotWakeTimeCalendar
);
7563 if (_aotWakeTimeContinuous
!= wakeContinuousTime
) {
7564 _aotWakeTimeContinuous
= wakeContinuousTime
;
7565 IOLog(LOG_PREFIX
"setWakeTime: " YMDTF
"\n", YMDT(&_aotWakeTimeCalendar
));
7567 _aotWakeTimeCalendar
.selector
= kPMCalendarTypeMaintenance
;
7568 _aotWakeTimeUTC
= wakesecs
;
7570 return kIOReturnSuccess
;
7573 // assumes WAKEEVENT_LOCK
7575 IOPMrootDomain::aotShouldExit(bool checkTimeSet
, bool software
)
7578 const char * reason
= "";
7582 _aotMetrics
->softwareRequestCount
++;
7583 reason
= "software request";
7584 } else if (kIOPMWakeEventAOTExitFlags
& _aotPendingFlags
) {
7586 reason
= gWakeReasonString
;
7587 } else if (checkTimeSet
&& (kPMCalendarTypeInvalid
== _aotWakeTimeCalendar
.selector
)) {
7589 _aotMetrics
->noTimeSetCount
++;
7590 reason
= "flipbook expired";
7591 } else if ((kIOPMAOTModeRespectTimers
& _aotMode
) && _calendarWakeAlarmUTC
) {
7594 clock_get_calendar_microtime(&sec
, &usec
);
7595 if (_calendarWakeAlarmUTC
<= sec
) {
7597 _aotMetrics
->rtcAlarmsCount
++;
7598 reason
= "user alarm";
7601 exitNow
= (_aotNow
&& _aotExit
);
7604 IOLog(LOG_PREFIX
"AOT exit for %s, sc %d po %d, cp %d, rj %d, ex %d, nt %d, rt %d\n",
7606 _aotMetrics
->sleepCount
,
7607 _aotMetrics
->possibleCount
,
7608 _aotMetrics
->confirmedPossibleCount
,
7609 _aotMetrics
->rejectedPossibleCount
,
7610 _aotMetrics
->expiredPossibleCount
,
7611 _aotMetrics
->noTimeSetCount
,
7612 _aotMetrics
->rtcAlarmsCount
);
7618 IOPMrootDomain::aotExit(bool cps
)
7620 uint32_t savedMessageMask
;
7623 _aotTasksSuspended
= false;
7624 _aotReadyToFullWake
= false;
7625 if (_aotTimerScheduled
) {
7626 _aotTimerES
->cancelTimeout();
7627 _aotTimerScheduled
= false;
7629 updateTasksSuspend();
7631 _aotMetrics
->totalTime
+= mach_absolute_time() - _aotLastWakeTime
;
7632 _aotLastWakeTime
= 0;
7633 if (_aotMetrics
->sleepCount
&& (_aotMetrics
->sleepCount
<= kIOPMAOTMetricsKernelWakeCountMax
)) {
7635 strlcpy(&_aotMetrics
->kernelWakeReason
[_aotMetrics
->sleepCount
- 1][0],
7637 sizeof(_aotMetrics
->kernelWakeReason
[_aotMetrics
->sleepCount
]));
7641 _aotWakeTimeCalendar
.selector
= kPMCalendarTypeInvalid
;
7643 // Preserve the message mask since a system wake transition
7644 // may have already started and initialized the mask.
7645 savedMessageMask
= _systemMessageClientMask
;
7646 _systemMessageClientMask
= kSystemMessageClientLegacyApp
;
7647 tellClients(kIOMessageSystemWillPowerOn
);
7648 _systemMessageClientMask
= savedMessageMask
| kSystemMessageClientLegacyApp
;
7651 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonAOTExit
);
7656 IOPMrootDomain::aotEvaluate(IOTimerEventSource
* timer
)
7660 IOLog("aotEvaluate(%d) 0x%x\n", (timer
!= NULL
), _aotPendingFlags
);
7663 exitNow
= aotShouldExit(false, false);
7664 if (timer
!= NULL
) {
7665 _aotTimerScheduled
= false;
7672 if (_aotLingerTime
) {
7674 IOLog("aot linger before sleep\n");
7675 clock_absolutetime_interval_to_deadline(_aotLingerTime
, &deadline
);
7676 clock_delay_until(deadline
);
7679 privateSleepSystem(kIOPMSleepReasonSoftware
);
7683 //******************************************************************************
7686 // Conditions that affect our wake/sleep decision has changed.
7687 // If conditions dictate that the system must remain awake, clamp power
7688 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
7689 // is TRUE, then remove the power clamp and allow the power state to drop
7691 //******************************************************************************
7694 IOPMrootDomain::adjustPowerState( bool sleepASAP
)
7696 DEBUG_LOG("adjustPowerState %s, asap %d, idleSleepEnabled %d\n",
7697 getPowerStateString((uint32_t) getPowerState()), sleepASAP
, idleSleepEnabled
);
7704 if (AOT_STATE
!= getPowerState()) {
7708 exitNow
= aotShouldExit(true, false);
7710 && !_aotTimerScheduled
7711 && (kIOPMWakeEventAOTPossibleExit
== (kIOPMWakeEventAOTPossibleFlags
& _aotPendingFlags
))) {
7712 _aotTimerScheduled
= true;
7713 if (_aotLingerTime
) {
7714 _aotTimerES
->setTimeout(_aotLingerTime
);
7716 _aotTimerES
->setTimeout(800, kMillisecondScale
);
7723 _aotReadyToFullWake
= true;
7724 if (!_aotTimerScheduled
) {
7725 privateSleepSystem(kIOPMSleepReasonSoftware
);
7731 if ((!idleSleepEnabled
) || !checkSystemSleepEnabled()) {
7732 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonAdjustPowerState
);
7733 } else if (sleepASAP
) {
7734 changePowerStateWithTagToPriv(SLEEP_STATE
, kCPSReasonAdjustPowerState
);
7739 IOPMrootDomain::handleSetDisplayPowerOn(bool powerOn
)
7742 if (!checkSystemCanSustainFullWake()) {
7743 DLOG("System cannot sustain full wake\n");
7747 // Force wrangler to max power state. If system is in dark wake
7748 // this alone won't raise the wrangler's power state.
7750 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMax
);
7753 // System in dark wake, always requesting full wake should
7754 // not have any bad side-effects, even if the request fails.
7756 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
)) {
7757 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeNotification
);
7758 requestFullWake( kFullWakeReasonDisplayOn
);
7761 // Relenquish desire to power up display.
7762 // Must first transition to state 1 since wrangler doesn't
7763 // power off the displays at state 0. At state 0 the root
7764 // domain is removed from the wrangler's power client list.
7766 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
+ 1);
7767 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
);
7772 //******************************************************************************
7773 // dispatchPowerEvent
7775 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
7776 //******************************************************************************
7779 IOPMrootDomain::dispatchPowerEvent(
7780 uint32_t event
, void * arg0
, uint64_t arg1
)
7785 case kPowerEventFeatureChanged
:
7786 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7787 messageClients(kIOPMMessageFeatureChange
, this);
7790 case kPowerEventReceivedPowerNotification
:
7791 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7792 handlePowerNotification((UInt32
)(uintptr_t) arg0
);
7795 case kPowerEventSystemBootCompleted
:
7796 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7797 if (systemBooting
) {
7798 systemBooting
= false;
7800 // read noidle setting from Device Tree
7801 OSSharedPtr
<IORegistryEntry
> defaults
= IORegistryEntry::fromPath("IODeviceTree:/defaults");
7802 if (defaults
!= NULL
) {
7803 OSSharedPtr
<OSObject
> noIdleProp
= defaults
->copyProperty("no-idle");
7804 OSData
*data
= OSDynamicCast(OSData
, noIdleProp
.get());
7805 if ((data
!= NULL
) && (data
->getLength() == 4)) {
7806 gNoIdleFlag
= *(uint32_t*)data
->getBytesNoCopy();
7807 DLOG("Setting gNoIdleFlag to %u from device tree\n", gNoIdleFlag
);
7810 if (lowBatteryCondition
|| thermalEmergencyState
) {
7811 if (lowBatteryCondition
) {
7812 privateSleepSystem(kIOPMSleepReasonLowPower
);
7814 privateSleepSystem(kIOPMSleepReasonThermalEmergency
);
7816 // The rest is unnecessary since the system is expected
7817 // to sleep immediately. The following wake will update
7822 sleepWakeDebugMemAlloc();
7823 saveFailureData2File();
7825 // If lid is closed, re-send lid closed notification
7826 // now that booting is complete.
7827 if (clamshellClosed
) {
7828 handlePowerNotification(kLocalEvalClamshellCommand
);
7830 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
7834 case kPowerEventSystemShutdown
:
7835 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7836 if (kOSBooleanTrue
== (OSBoolean
*) arg0
) {
7837 /* We set systemShutdown = true during shutdown
7838 * to prevent sleep at unexpected times while loginwindow is trying
7839 * to shutdown apps and while the OS is trying to transition to
7840 * complete power of.
7842 * Set to true during shutdown, as soon as loginwindow shows
7843 * the "shutdown countdown dialog", through individual app
7844 * termination, and through black screen kernel shutdown.
7846 systemShutdown
= true;
7849 * A shutdown was initiated, but then the shutdown
7850 * was cancelled, clearing systemShutdown to false here.
7852 systemShutdown
= false;
7856 case kPowerEventUserDisabledSleep
:
7857 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7858 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
7861 case kPowerEventRegisterSystemCapabilityClient
:
7862 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7864 // reset() handles the arg0 == nullptr case for us
7865 systemCapabilityNotifier
.reset((IONotifier
*) arg0
, OSRetain
);
7866 /* intentional fall-through */
7867 [[clang::fallthrough]];
7869 case kPowerEventRegisterKernelCapabilityClient
:
7870 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7871 if (!_joinedCapabilityClients
) {
7872 _joinedCapabilityClients
= OSSet::withCapacity(8);
7875 OSSharedPtr
<IONotifier
> notify((IONotifier
*) arg0
, OSNoRetain
);
7876 if (_joinedCapabilityClients
) {
7877 _joinedCapabilityClients
->setObject(notify
.get());
7878 synchronizePowerTree( kIOPMSyncNoChildNotify
);
7883 case kPowerEventPolicyStimulus
:
7884 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7886 int stimulus
= (int)(uintptr_t) arg0
;
7887 evaluatePolicy(stimulus
, (uint32_t) arg1
);
7891 case kPowerEventAssertionCreate
:
7892 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7894 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
7899 case kPowerEventAssertionRelease
:
7900 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7902 pmAssertions
->handleReleaseAssertion(arg1
);
7906 case kPowerEventAssertionSetLevel
:
7907 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7909 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
7913 case kPowerEventQueueSleepWakeUUID
:
7914 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7915 handleQueueSleepWakeUUID((OSObject
*)arg0
);
7917 case kPowerEventPublishSleepWakeUUID
:
7918 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7919 handlePublishSleepWakeUUID((bool)arg0
);
7922 case kPowerEventSetDisplayPowerOn
:
7923 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7925 displayPowerOnRequested
= true;
7927 displayPowerOnRequested
= false;
7929 handleSetDisplayPowerOn(displayPowerOnRequested
);
7932 case kPowerEventPublishWakeType
:
7933 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7935 // Don't replace wake type property if already set
7936 if ((arg0
== gIOPMWakeTypeUserKey
) ||
7937 !propertyExists(kIOPMRootDomainWakeTypeKey
)) {
7938 const char * wakeType
= NULL
;
7940 if (arg0
== gIOPMWakeTypeUserKey
) {
7941 requestUserActive(this, "WakeTypeUser");
7942 wakeType
= kIOPMRootDomainWakeTypeUser
;
7943 } else if (arg0
== gIOPMSettingDebugWakeRelativeKey
) {
7944 requestUserActive(this, "WakeTypeAlarm");
7945 wakeType
= kIOPMRootDomainWakeTypeAlarm
;
7946 } else if (arg0
== gIOPMSettingSleepServiceWakeCalendarKey
) {
7947 darkWakeSleepService
= true;
7948 wakeType
= kIOPMRootDomainWakeTypeSleepService
;
7949 } else if (arg0
== gIOPMSettingMaintenanceWakeCalendarKey
) {
7950 wakeType
= kIOPMRootDomainWakeTypeMaintenance
;
7954 setProperty(kIOPMRootDomainWakeTypeKey
, wakeType
);
7959 case kPowerEventAOTEvaluate
:
7960 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
7961 if (_aotReadyToFullWake
) {
7968 //******************************************************************************
7969 // systemPowerEventOccurred
7971 // The power controller is notifying us of a hardware-related power management
7972 // event that we must handle.
7974 // systemPowerEventOccurred covers the same functionality that
7975 // receivePowerNotification does; it simply provides a richer API for conveying
7976 // more information.
7977 //******************************************************************************
7980 IOPMrootDomain::systemPowerEventOccurred(
7981 const OSSymbol
*event
,
7984 IOReturn attempt
= kIOReturnSuccess
;
7985 OSSharedPtr
<OSNumber
> newNumber
;
7988 return kIOReturnBadArgument
;
7991 newNumber
= OSNumber::withNumber(intValue
, 8 * sizeof(intValue
));
7993 return kIOReturnInternalError
;
7996 attempt
= systemPowerEventOccurred(event
, static_cast<OSObject
*>(newNumber
.get()));
8002 IOPMrootDomain::setThermalState(OSObject
*value
)
8006 if (gIOPMWorkLoop
->inGate() == false) {
8007 gIOPMWorkLoop
->runAction(
8008 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setThermalState
),
8014 if (value
&& (num
= OSDynamicCast(OSNumber
, value
))) {
8015 thermalWarningState
= ((num
->unsigned32BitValue() == kIOPMThermalLevelWarning
) ||
8016 (num
->unsigned32BitValue() == kIOPMThermalLevelTrap
)) ? 1 : 0;
8021 IOPMrootDomain::systemPowerEventOccurred(
8022 const OSSymbol
*event
,
8025 OSSharedPtr
<OSDictionary
> thermalsDict
;
8026 bool shouldUpdate
= true;
8028 if (!event
|| !value
) {
8029 return kIOReturnBadArgument
;
8033 // We reuse featuresDict Lock because it already exists and guards
8034 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
8035 // of stepping on that lock.
8036 if (featuresDictLock
) {
8037 IOLockLock(featuresDictLock
);
8040 OSSharedPtr
<OSObject
> origThermalsProp
= copyProperty(kIOPMRootDomainPowerStatusKey
);
8041 OSDictionary
* origThermalsDict
= OSDynamicCast(OSDictionary
, origThermalsProp
.get());
8043 if (origThermalsDict
) {
8044 thermalsDict
= OSDictionary::withDictionary(origThermalsDict
);
8046 thermalsDict
= OSDictionary::withCapacity(1);
8049 if (!thermalsDict
) {
8050 shouldUpdate
= false;
8054 thermalsDict
->setObject(event
, value
);
8056 setProperty(kIOPMRootDomainPowerStatusKey
, thermalsDict
.get());
8060 if (featuresDictLock
) {
8061 IOLockUnlock(featuresDictLock
);
8066 event
->isEqualTo(kIOPMThermalLevelWarningKey
)) {
8067 setThermalState(value
);
8069 messageClients(kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
8072 return kIOReturnSuccess
;
8075 //******************************************************************************
8076 // receivePowerNotification
8078 // The power controller is notifying us of a hardware-related power management
8079 // event that we must handle. This may be a result of an 'environment' interrupt
8080 // from the power mgt micro.
8081 //******************************************************************************
8084 IOPMrootDomain::receivePowerNotification( UInt32 msg
)
8086 if (msg
& kIOPMPowerButton
) {
8087 uint32_t currentPhase
= pmTracer
->getTracePhase();
8088 if (currentPhase
!= kIOPMTracePointSystemUp
&& currentPhase
> kIOPMTracePointSystemSleep
) {
8089 DEBUG_LOG("power button pressed during wake. phase = %u\n", currentPhase
);
8090 swd_flags
|= SWD_PWR_BTN_STACKSHOT
;
8091 thread_call_enter(powerButtonDown
);
8093 DEBUG_LOG("power button pressed when system is up\n");
8095 } else if (msg
& kIOPMPowerButtonUp
) {
8096 if (swd_flags
& SWD_PWR_BTN_STACKSHOT
) {
8097 swd_flags
&= ~SWD_PWR_BTN_STACKSHOT
;
8098 thread_call_enter(powerButtonUp
);
8101 pmPowerStateQueue
->submitPowerEvent(
8102 kPowerEventReceivedPowerNotification
, (void *)(uintptr_t) msg
);
8104 return kIOReturnSuccess
;
8108 IOPMrootDomain::handlePowerNotification( UInt32 msg
)
8110 bool eval_clamshell
= false;
8111 bool eval_clamshell_alarm
= false;
8116 * Local (IOPMrootDomain only) eval clamshell command
8118 if (msg
& kLocalEvalClamshellCommand
) {
8119 if ((gClamshellFlags
& kClamshell_WAR_47715679
) && isRTCAlarmWake
) {
8120 eval_clamshell_alarm
= true;
8122 // reset isRTCAlarmWake. This evaluation should happen only once
8123 // on RTC/Alarm wake. Any clamshell events after wake should follow
8124 // the regular evaluation
8125 isRTCAlarmWake
= false;
8127 eval_clamshell
= true;
8134 if (msg
& kIOPMOverTemp
) {
8135 DLOG("Thermal overtemp message received!\n");
8136 thermalEmergencyState
= true;
8137 privateSleepSystem(kIOPMSleepReasonThermalEmergency
);
8141 * Forward DW thermal notification to client, if system is not going to sleep
8143 if ((msg
& kIOPMDWOverTemp
) && (_systemTransitionType
!= kSystemTransitionSleep
)) {
8144 DLOG("DarkWake thermal limits message received!\n");
8145 messageClients(kIOPMMessageDarkWakeThermalEmergency
);
8151 if (msg
& kIOPMSleepNow
) {
8152 privateSleepSystem(kIOPMSleepReasonSoftware
);
8158 if (msg
& kIOPMPowerEmergency
) {
8159 DLOG("Low battery notification received\n");
8160 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
8161 // Wait for the next low battery notification if the system state is
8163 if ((_systemTransitionType
== kSystemTransitionNone
) &&
8164 CAP_CURRENT(kIOPMSystemCapabilityCPU
) &&
8165 !systemBooting
&& !systemShutdown
&& !gWillShutdown
) {
8166 // Setting lowBatteryCondition will prevent system sleep
8167 lowBatteryCondition
= true;
8169 // Notify userspace to initiate system shutdown
8170 messageClients(kIOPMMessageRequestSystemShutdown
);
8173 lowBatteryCondition
= true;
8174 privateSleepSystem(kIOPMSleepReasonLowPower
);
8181 if (msg
& kIOPMClamshellOpened
) {
8182 DLOG("Clamshell opened\n");
8183 // Received clamshel open message from clamshell controlling driver
8184 // Update our internal state and tell general interest clients
8185 clamshellClosed
= false;
8186 clamshellExists
= true;
8188 // Don't issue a hid tickle when lid is open and polled on wake
8189 if (msg
& kIOPMSetValue
) {
8190 setProperty(kIOPMRootDomainWakeTypeKey
, "Lid Open");
8195 informCPUStateChange(kInformLid
, 0);
8197 // Tell general interest clients
8198 sendClientClamshellNotification();
8200 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
8201 || (lastSleepReason
== kIOPMSleepReasonIdle
)
8202 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
8204 userActivityCount
++;
8206 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
8211 * Send the clamshell interest notification since the lid is closing.
8213 if (msg
& kIOPMClamshellClosed
) {
8214 if ((clamshellIgnoreClose
|| (gClamshellFlags
& kClamshell_WAR_38378787
)) &&
8215 clamshellClosed
&& clamshellExists
) {
8216 DLOG("Ignoring redundant Clamshell close event\n");
8218 DLOG("Clamshell closed\n");
8219 // Received clamshel open message from clamshell controlling driver
8220 // Update our internal state and tell general interest clients
8221 clamshellClosed
= true;
8222 clamshellExists
= true;
8224 // Ignore all following clamshell close events until the clamshell
8225 // is opened or the system sleeps. When a clamshell close triggers
8226 // a system wake, the lid driver may send us two clamshell close
8227 // events, one for the clamshell close event itself, and a second
8228 // close event when the driver polls the lid state on wake.
8229 clamshellIgnoreClose
= true;
8232 informCPUStateChange(kInformLid
, 1);
8234 // Tell general interest clients
8235 sendClientClamshellNotification();
8237 // And set eval_clamshell = so we can attempt
8238 eval_clamshell
= true;
8243 * Set Desktop mode (sent from graphics)
8245 * -> reevaluate lid state
8247 if (msg
& kIOPMSetDesktopMode
) {
8248 desktopMode
= (0 != (msg
& kIOPMSetValue
));
8249 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
8250 DLOG("Desktop mode %d\n", desktopMode
);
8252 sendClientClamshellNotification();
8254 // Re-evaluate the lid state
8255 eval_clamshell
= true;
8259 * AC Adaptor connected
8261 * -> reevaluate lid state
8263 if (msg
& kIOPMSetACAdaptorConnected
) {
8264 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
8265 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
8268 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
8270 // Tell BSD if AC is connected
8271 // 0 == external power source; 1 == on battery
8272 post_sys_powersource(acAdaptorConnected
? 0:1);
8274 sendClientClamshellNotification();
8276 // Re-evaluate the lid state
8277 eval_clamshell
= true;
8279 // Lack of AC may have latched a display wrangler tickle.
8280 // This mirrors the hardware's USB wake event latch, where a latched
8281 // USB wake event followed by an AC attach will trigger a full wake.
8282 latchDisplayWranglerTickle( false );
8285 // AC presence will reset the standy timer delay adjustment.
8286 _standbyTimerResetSeconds
= 0;
8288 if (!userIsActive
) {
8289 // Reset userActivityTime when power supply is changed(rdr 13789330)
8290 clock_get_uptime(&userActivityTime
);
8295 * Enable Clamshell (external display disappear)
8297 * -> reevaluate lid state
8299 if (msg
& kIOPMEnableClamshell
) {
8300 DLOG("Clamshell enabled\n");
8302 // Re-evaluate the lid state
8303 // System should sleep on external display disappearance
8304 // in lid closed operation.
8305 if (true == clamshellDisabled
) {
8306 eval_clamshell
= true;
8308 #if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
8309 // Also clear kClamshellSleepDisableInternal when graphics enables
8310 // the clamshell during a full wake. When graphics is behaving as
8311 // expected, this will allow clamshell close to be honored earlier
8312 // rather than waiting for the delayed evaluation.
8313 if ((clamshellSleepDisableMask
& kClamshellSleepDisableInternal
) &&
8314 (CAP_PENDING(kIOPMSystemCapabilityGraphics
) ||
8315 CAP_CURRENT(kIOPMSystemCapabilityGraphics
))) {
8316 setClamShellSleepDisable(false, kClamshellSleepDisableInternal
);
8318 // Cancel the TC to avoid an extra kLocalEvalClamshellCommand
8319 // when timer expires which is harmless but useless.
8320 thread_call_cancel(fullWakeThreadCall
);
8325 clamshellDisabled
= false;
8326 sendClientClamshellNotification();
8330 * Disable Clamshell (external display appeared)
8331 * We don't bother re-evaluating clamshell state. If the system is awake,
8332 * the lid is probably open.
8334 if (msg
& kIOPMDisableClamshell
) {
8335 DLOG("Clamshell disabled\n");
8336 clamshellDisabled
= true;
8337 sendClientClamshellNotification();
8341 * Evaluate clamshell and SLEEP if appropriate
8343 if (eval_clamshell_alarm
&& clamshellClosed
) {
8344 if (shouldSleepOnRTCAlarmWake()) {
8345 privateSleepSystem(kIOPMSleepReasonClamshell
);
8347 } else if (eval_clamshell
&& clamshellClosed
) {
8348 if (shouldSleepOnClamshellClosed()) {
8349 privateSleepSystem(kIOPMSleepReasonClamshell
);
8351 evaluatePolicy( kStimulusDarkWakeEvaluate
);
8355 if (msg
& kIOPMProModeEngaged
) {
8357 DLOG("ProModeEngaged\n");
8358 messageClient(kIOPMMessageProModeStateChange
, systemCapabilityNotifier
.get(), &newState
, sizeof(newState
));
8361 if (msg
& kIOPMProModeDisengaged
) {
8363 DLOG("ProModeDisengaged\n");
8364 messageClient(kIOPMMessageProModeStateChange
, systemCapabilityNotifier
.get(), &newState
, sizeof(newState
));
8368 //******************************************************************************
8371 // Evaluate root-domain policy in response to external changes.
8372 //******************************************************************************
8375 IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
8379 int idleSleepEnabled
: 1;
8380 int idleSleepDisabled
: 1;
8381 int displaySleep
: 1;
8382 int sleepDelayChanged
: 1;
8383 int evaluateDarkWake
: 1;
8384 int adjustPowerState
: 1;
8385 int userBecameInactive
: 1;
8386 int displaySleepEntry
: 1;
8396 case kStimulusDisplayWranglerSleep
:
8397 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8398 if (!wranglerPowerOff
) {
8399 // wrangler is in sleep state or lower
8400 flags
.bit
.displaySleep
= true;
8402 if (!wranglerAsleep
) {
8403 // transition from wrangler wake to wrangler sleep
8404 flags
.bit
.displaySleepEntry
= true;
8405 wranglerAsleep
= true;
8409 case kStimulusDisplayWranglerWake
:
8410 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8411 displayIdleForDemandSleep
= false;
8412 wranglerPowerOff
= false;
8413 wranglerAsleep
= false;
8416 case kStimulusEnterUserActiveState
:
8417 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8418 if (_preventUserActive
) {
8419 DLOG("user active dropped\n");
8422 if (!userIsActive
) {
8423 userIsActive
= true;
8424 userWasActive
= true;
8425 clock_get_uptime(&gUserActiveAbsTime
);
8427 // Stay awake after dropping demand for display power on
8428 if (kFullWakeReasonDisplayOn
== fullWakeReason
) {
8429 fullWakeReason
= fFullWakeReasonDisplayOnAndLocalUser
;
8430 DLOG("User activity while in notification wake\n");
8431 changePowerStateWithOverrideTo( getRUN_STATE(), 0);
8434 kdebugTrace(kPMLogUserActiveState
, 0, 1, 0);
8435 setProperty(gIOPMUserIsActiveKey
.get(), kOSBooleanTrue
);
8436 messageClients(kIOPMMessageUserIsActiveChanged
);
8438 flags
.bit
.idleSleepDisabled
= true;
8441 case kStimulusLeaveUserActiveState
:
8442 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8444 clock_get_uptime(&gUserInactiveAbsTime
);
8445 userIsActive
= false;
8446 clock_get_uptime(&userBecameInactiveTime
);
8447 flags
.bit
.userBecameInactive
= true;
8449 kdebugTrace(kPMLogUserActiveState
, 0, 0, 0);
8450 setProperty(gIOPMUserIsActiveKey
.get(), kOSBooleanFalse
);
8451 messageClients(kIOPMMessageUserIsActiveChanged
);
8455 case kStimulusAggressivenessChanged
:
8457 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8458 unsigned long aggressiveValue
;
8459 uint32_t minutesToIdleSleep
= 0;
8460 uint32_t minutesToDisplayDim
= 0;
8461 uint32_t minutesDelta
= 0;
8463 // Fetch latest display and system sleep slider values.
8464 aggressiveValue
= 0;
8465 getAggressiveness(kPMMinutesToSleep
, &aggressiveValue
);
8466 minutesToIdleSleep
= (uint32_t) aggressiveValue
;
8468 aggressiveValue
= 0;
8469 getAggressiveness(kPMMinutesToDim
, &aggressiveValue
);
8470 minutesToDisplayDim
= (uint32_t) aggressiveValue
;
8471 DLOG("aggressiveness changed: system %u->%u, display %u\n",
8472 sleepSlider
, minutesToIdleSleep
, minutesToDisplayDim
);
8474 DLOG("idle time -> %d secs (ena %d)\n",
8475 idleSeconds
, (minutesToIdleSleep
!= 0));
8477 // How long to wait before sleeping the system once
8478 // the displays turns off is indicated by 'extraSleepDelay'.
8480 if (minutesToIdleSleep
> minutesToDisplayDim
) {
8481 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
8482 } else if (minutesToIdleSleep
== minutesToDisplayDim
) {
8486 if ((!idleSleepEnabled
) && (minutesToIdleSleep
!= 0)) {
8487 idleSleepEnabled
= flags
.bit
.idleSleepEnabled
= true;
8490 if ((idleSleepEnabled
) && (minutesToIdleSleep
== 0)) {
8491 flags
.bit
.idleSleepDisabled
= true;
8492 idleSleepEnabled
= false;
8494 #if !defined(XNU_TARGET_OS_OSX)
8495 if (0x7fffffff == minutesToIdleSleep
) {
8496 minutesToIdleSleep
= idleSeconds
;
8498 #endif /* !defined(XNU_TARGET_OS_OSX) */
8500 if (((minutesDelta
!= extraSleepDelay
) ||
8501 (userActivityTime
!= userActivityTime_prev
)) &&
8502 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
) {
8503 flags
.bit
.sleepDelayChanged
= true;
8506 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
8507 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
)) {
8508 // Reconsider decision to remain in dark wake
8509 flags
.bit
.evaluateDarkWake
= true;
8512 sleepSlider
= minutesToIdleSleep
;
8513 extraSleepDelay
= minutesDelta
;
8514 userActivityTime_prev
= userActivityTime
;
8517 case kStimulusDemandSystemSleep
:
8518 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8519 displayIdleForDemandSleep
= true;
8520 if (wrangler
&& wranglerIdleSettings
) {
8521 // Request wrangler idle only when demand sleep is triggered
8523 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
)) {
8524 wrangler
->setProperties(wranglerIdleSettings
.get());
8525 DLOG("Requested wrangler idle\n");
8528 // arg = sleepReason
8529 changePowerStateWithOverrideTo( SLEEP_STATE
, arg
);
8532 case kStimulusAllowSystemSleepChanged
:
8533 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8534 flags
.bit
.adjustPowerState
= true;
8537 case kStimulusDarkWakeActivityTickle
:
8538 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8539 // arg == true implies real and not self generated wrangler tickle.
8540 // Update wake type on PM work loop instead of the tickle thread to
8541 // eliminate the possibility of an early tickle clobbering the wake
8542 // type set by the platform driver.
8544 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeHIDActivity
);
8547 if (!darkWakeExit
) {
8548 if (latchDisplayWranglerTickle(true)) {
8549 DLOG("latched tickle\n");
8553 darkWakeExit
= true;
8554 DLOG("Requesting full wake due to dark wake activity tickle\n");
8555 requestFullWake( kFullWakeReasonLocalUser
);
8559 case kStimulusDarkWakeEntry
:
8560 case kStimulusDarkWakeReentry
:
8561 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8562 // Any system transitions since the last dark wake transition
8563 // will invalid the stimulus.
8565 if (arg
== _systemStateGeneration
) {
8566 DLOG("dark wake entry\n");
8567 systemDarkWake
= true;
8569 // Keep wranglerPowerOff an invariant when wrangler is absent
8571 wranglerPowerOff
= true;
8574 if (kStimulusDarkWakeEntry
== stimulus
) {
8575 clock_get_uptime(&userBecameInactiveTime
);
8576 flags
.bit
.evaluateDarkWake
= true;
8577 if (activitySinceSleep()) {
8578 DLOG("User activity recorded while going to darkwake\n");
8583 // Always accelerate disk spindown while in dark wake,
8584 // even if system does not support/allow sleep.
8586 cancelIdleSleepTimer();
8587 setQuickSpinDownTimeout();
8591 case kStimulusDarkWakeEvaluate
:
8592 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8593 if (systemDarkWake
) {
8594 flags
.bit
.evaluateDarkWake
= true;
8598 case kStimulusNoIdleSleepPreventers
:
8599 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
8600 flags
.bit
.adjustPowerState
= true;
8602 } /* switch(stimulus) */
8604 if (flags
.bit
.evaluateDarkWake
&& (kFullWakeReasonNone
== fullWakeReason
)) {
8605 DLOG("DarkWake: sleepASAP %d, clamshell closed %d, disabled %d/%x, desktopMode %d, ac %d\n",
8606 darkWakeToSleepASAP
, clamshellClosed
, clamshellDisabled
, clamshellSleepDisableMask
, desktopMode
, acAdaptorConnected
);
8607 if (darkWakeToSleepASAP
||
8608 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
))) {
8609 uint32_t newSleepReason
;
8611 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics
)) {
8612 // System was previously in full wake. Sleep reason from
8613 // full to dark already recorded in fullToDarkReason.
8615 if (lowBatteryCondition
) {
8616 newSleepReason
= kIOPMSleepReasonLowPower
;
8617 } else if (thermalEmergencyState
) {
8618 newSleepReason
= kIOPMSleepReasonThermalEmergency
;
8620 newSleepReason
= fullToDarkReason
;
8623 // In dark wake from system sleep.
8625 if (darkWakeSleepService
) {
8626 newSleepReason
= kIOPMSleepReasonSleepServiceExit
;
8628 newSleepReason
= kIOPMSleepReasonMaintenance
;
8632 if (checkSystemCanSleep(newSleepReason
)) {
8633 privateSleepSystem(newSleepReason
);
8635 } else { // non-maintenance (network) dark wake
8636 if (checkSystemCanSleep(kIOPMSleepReasonIdle
)) {
8637 // Release power clamp, and wait for children idle.
8638 adjustPowerState(true);
8640 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonDarkWakeCannotSleep
);
8645 if (systemDarkWake
) {
8646 // The rest are irrelevant while system is in dark wake.
8650 if ((flags
.bit
.displaySleepEntry
) &&
8651 (kFullWakeReasonDisplayOn
== fullWakeReason
)) {
8652 // kIOPMSleepReasonNotificationWakeExit
8653 DLOG("Display sleep while in notification wake\n");
8654 changePowerStateWithOverrideTo(SLEEP_STATE
, kIOPMSleepReasonNotificationWakeExit
);
8657 if (flags
.bit
.userBecameInactive
|| flags
.bit
.sleepDelayChanged
) {
8658 bool cancelQuickSpindown
= false;
8660 if (flags
.bit
.sleepDelayChanged
) {
8661 // Cancel existing idle sleep timer and quick disk spindown.
8662 // New settings will be applied by the idleSleepEnabled flag
8663 // handler below if idle sleep is enabled.
8665 DLOG("extra sleep timer changed\n");
8666 cancelIdleSleepTimer();
8667 cancelQuickSpindown
= true;
8669 DLOG("user inactive\n");
8672 if (!userIsActive
&& idleSleepEnabled
) {
8673 startIdleSleepTimer(getTimeToIdleSleep());
8676 if (cancelQuickSpindown
) {
8677 restoreUserSpinDownTimeout();
8681 if (flags
.bit
.idleSleepEnabled
) {
8682 DLOG("idle sleep timer enabled\n");
8684 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
8685 startIdleSleepTimer(getTimeToIdleSleep());
8687 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonIdleSleepEnabled
);
8688 startIdleSleepTimer( idleSeconds
);
8691 // Start idle timer if prefs now allow system sleep
8692 // and user is already inactive. Disk spindown is
8693 // accelerated upon timer expiration.
8695 if (!userIsActive
) {
8696 startIdleSleepTimer(getTimeToIdleSleep());
8701 if (flags
.bit
.idleSleepDisabled
) {
8702 DLOG("idle sleep timer disabled\n");
8703 cancelIdleSleepTimer();
8704 restoreUserSpinDownTimeout();
8708 if (flags
.bit
.adjustPowerState
) {
8709 bool sleepASAP
= false;
8711 if (!systemBooting
&& (0 == idleSleepPreventersCount())) {
8713 changePowerStateWithTagToPriv(getRUN_STATE(), kCPSReasonEvaluatePolicy
);
8714 if (idleSleepEnabled
) {
8715 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
8716 if (!extraSleepDelay
&& !idleSleepTimerPending
) {
8720 // stay awake for at least idleSeconds
8721 startIdleSleepTimer(idleSeconds
);
8724 } else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
) {
8729 adjustPowerState(sleepASAP
);
8733 //******************************************************************************
8736 IOPMrootDomain::idleSleepPreventersCount()
8739 unsigned int count __block
;
8741 preventIdleSleepList
->iterateObjects(^bool (OSObject
* obj
)
8743 count
+= (NULL
== obj
->metaCast("AppleARMBacklight"));
8749 return preventIdleSleepList
->getCount();
8753 //******************************************************************************
8756 // Request transition from dark wake to full wake
8757 //******************************************************************************
8760 IOPMrootDomain::requestFullWake( FullWakeReason reason
)
8762 uint32_t options
= 0;
8763 IOService
* pciRoot
= NULL
;
8764 bool promotion
= false;
8766 // System must be in dark wake and a valid reason for entering full wake
8767 if ((kFullWakeReasonNone
== reason
) ||
8768 (kFullWakeReasonNone
!= fullWakeReason
) ||
8769 (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))) {
8773 // Will clear reason upon exit from full wake
8774 fullWakeReason
= reason
;
8776 _desiredCapability
|= (kIOPMSystemCapabilityGraphics
|
8777 kIOPMSystemCapabilityAudio
);
8779 if ((kSystemTransitionWake
== _systemTransitionType
) &&
8780 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
8781 !darkWakePowerClamped
) {
8782 // Promote to full wake while waking up to dark wake due to tickle.
8783 // PM will hold off notifying the graphics subsystem about system wake
8784 // as late as possible, so if a HID tickle does arrive, graphics can
8785 // power up from this same wake transition. Otherwise, the latency to
8786 // power up graphics on the following transition can be huge on certain
8787 // systems. However, once any power clamping has taken effect, it is
8788 // too late to promote the current dark wake transition to a full wake.
8789 _pendingCapability
|= (kIOPMSystemCapabilityGraphics
|
8790 kIOPMSystemCapabilityAudio
);
8792 // Tell the PCI parent of audio and graphics drivers to stop
8793 // delaying the child notifications. Same for root domain.
8794 pciRoot
= pciHostBridgeDriver
.get();
8795 willEnterFullWake();
8799 // Unsafe to cancel once graphics was powered.
8800 // If system woke from dark wake, the return to sleep can
8801 // be cancelled. "awake -> dark -> sleep" transition
8802 // can be cancelled also, during the "dark -> sleep" phase
8803 // *prior* to driver power down.
8804 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) ||
8805 _pendingCapability
== 0) {
8806 options
|= kIOPMSyncCancelPowerDown
;
8809 synchronizePowerTree(options
, pciRoot
);
8811 if (kFullWakeReasonLocalUser
== fullWakeReason
) {
8812 // IOGraphics doesn't light the display even though graphics is
8813 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
8814 // So, do an explicit activity tickle
8816 wrangler
->activityTickle(0, 0);
8820 // Log a timestamp for the initial full wake request.
8821 // System may not always honor this full wake request.
8822 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
)) {
8826 clock_get_uptime(&now
);
8827 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
8828 absolutetime_to_nanoseconds(now
, &nsec
);
8829 MSG("full wake %s (reason %u) %u ms\n",
8830 promotion
? "promotion" : "request",
8831 fullWakeReason
, ((int)((nsec
) / NSEC_PER_MSEC
)));
8835 //******************************************************************************
8836 // willEnterFullWake
8838 // System will enter full wake from sleep, from dark wake, or from dark
8839 // wake promotion. This function aggregate things that are in common to
8840 // all three full wake transitions.
8842 // Assumptions: fullWakeReason was updated
8843 //******************************************************************************
8846 IOPMrootDomain::willEnterFullWake( void )
8848 hibernateRetry
= false;
8849 sleepToStandby
= false;
8850 standbyNixed
= false;
8851 resetTimers
= false;
8852 sleepTimerMaintenance
= false;
8854 assert(!CAP_CURRENT(kIOPMSystemCapabilityGraphics
));
8856 _systemMessageClientMask
= kSystemMessageClientPowerd
|
8857 kSystemMessageClientLegacyApp
;
8859 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0) {
8860 // First time to attain full wake capability since the last wake
8861 _systemMessageClientMask
|= kSystemMessageClientKernel
;
8863 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
8864 setProperty(gIOPMUserTriggeredFullWakeKey
.get(),
8865 (kFullWakeReasonLocalUser
== fullWakeReason
) ?
8866 kOSBooleanTrue
: kOSBooleanFalse
);
8869 IOHibernateSetWakeCapabilities(_pendingCapability
);
8872 IOService::setAdvisoryTickleEnable( true );
8873 tellClients(kIOMessageSystemWillPowerOn
);
8874 preventTransitionToUserActive(false);
8877 //******************************************************************************
8878 // fullWakeDelayedWork
8880 // System has already entered full wake. Invoked by a delayed thread call.
8881 //******************************************************************************
8884 IOPMrootDomain::fullWakeDelayedWork( void )
8886 #if DARK_TO_FULL_EVALUATE_CLAMSHELL_DELAY
8887 if (!gIOPMWorkLoop
->inGate()) {
8888 gIOPMWorkLoop
->runAction(
8889 OSMemberFunctionCast(IOWorkLoop::Action
, this,
8890 &IOPMrootDomain::fullWakeDelayedWork
), this);
8894 DLOG("fullWakeDelayedWork cap cur %x pend %x high %x, clamshell disable %x/%x\n",
8895 _currentCapability
, _pendingCapability
, _highestCapability
,
8896 clamshellDisabled
, clamshellSleepDisableMask
);
8898 if (clamshellExists
&&
8899 CAP_CURRENT(kIOPMSystemCapabilityGraphics
) &&
8900 !CAP_CHANGE(kIOPMSystemCapabilityGraphics
)) {
8901 if (clamshellSleepDisableMask
& kClamshellSleepDisableInternal
) {
8902 setClamShellSleepDisable(false, kClamshellSleepDisableInternal
);
8904 // Not the initial full wake after waking from sleep.
8905 // Evaluate the clamshell for rdar://problem/9157444.
8906 receivePowerNotification(kLocalEvalClamshellCommand
);
8912 //******************************************************************************
8913 // evaluateAssertions
8915 //******************************************************************************
8917 // Bitmask of all kernel assertions that prevent system idle sleep.
8918 // kIOPMDriverAssertionReservedBit7 is reserved for IOMediaBSDClient.
8919 #define NO_IDLE_SLEEP_ASSERTIONS_MASK \
8920 (kIOPMDriverAssertionReservedBit7 | \
8921 kIOPMDriverAssertionPreventSystemIdleSleepBit)
8924 IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions
, IOPMDriverAssertionType oldAssertions
)
8926 IOPMDriverAssertionType changedBits
= newAssertions
^ oldAssertions
;
8928 messageClients(kIOPMMessageDriverAssertionsChanged
);
8930 if (changedBits
& kIOPMDriverAssertionPreventDisplaySleepBit
) {
8932 bool value
= (newAssertions
& kIOPMDriverAssertionPreventDisplaySleepBit
) ? true : false;
8934 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value
);
8935 wrangler
->setIgnoreIdleTimer( value
);
8939 if (changedBits
& kIOPMDriverAssertionCPUBit
) {
8941 IOLog("CPU assertions %d\n", (0 != (kIOPMDriverAssertionCPUBit
& newAssertions
)));
8943 evaluatePolicy(_aotNow
? kStimulusNoIdleSleepPreventers
: kStimulusDarkWakeEvaluate
);
8944 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
8946 clock_usec_t microsecs
;
8947 clock_get_uptime(&now
);
8948 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
8949 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
8950 if (assertOnWakeReport
) {
8951 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
8952 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
8957 if (changedBits
& NO_IDLE_SLEEP_ASSERTIONS_MASK
) {
8958 if ((newAssertions
& NO_IDLE_SLEEP_ASSERTIONS_MASK
) != 0) {
8959 if ((oldAssertions
& NO_IDLE_SLEEP_ASSERTIONS_MASK
) == 0) {
8960 DLOG("PreventIdleSleep driver assertion raised\n");
8961 bool ok
= updatePreventIdleSleepList(this, true);
8962 if (ok
&& (changedBits
& kIOPMDriverAssertionPreventSystemIdleSleepBit
)) {
8963 // Cancel idle sleep if there is one in progress
8964 cancelIdlePowerDown(this);
8968 DLOG("PreventIdleSleep driver assertion dropped\n");
8969 updatePreventIdleSleepList(this, false);
8977 //******************************************************************************
8980 //******************************************************************************
8983 IOPMrootDomain::pmStatsRecordEvent(
8985 AbsoluteTime timestamp
)
8987 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
8988 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
8991 OSSharedPtr
<OSData
> publishPMStats
;
8993 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
8995 absolutetime_to_nanoseconds(timestamp
, &nsec
);
8997 switch (eventIndex
) {
8998 case kIOPMStatsHibernateImageWrite
:
9000 gPMStats
.hibWrite
.start
= nsec
;
9001 } else if (stopping
) {
9002 gPMStats
.hibWrite
.stop
= nsec
;
9006 delta
= gPMStats
.hibWrite
.stop
- gPMStats
.hibWrite
.start
;
9007 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/ NSEC_PER_MSEC
);
9010 case kIOPMStatsHibernateImageRead
:
9012 gPMStats
.hibRead
.start
= nsec
;
9013 } else if (stopping
) {
9014 gPMStats
.hibRead
.stop
= nsec
;
9018 delta
= gPMStats
.hibRead
.stop
- gPMStats
.hibRead
.start
;
9019 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/ NSEC_PER_MSEC
);
9021 publishPMStats
= OSData::withBytes(&gPMStats
, sizeof(gPMStats
));
9022 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
.get());
9023 bzero(&gPMStats
, sizeof(gPMStats
));
9030 * Appends a record of the application response to
9031 * IOPMrootDomain::pmStatsAppResponses
9034 IOPMrootDomain::pmStatsRecordApplicationResponse(
9035 const OSSymbol
*response
,
9041 IOPMPowerStateIndex powerState
,
9044 OSSharedPtr
<OSDictionary
> responseDescription
;
9045 OSSharedPtr
<OSNumber
> delayNum
;
9046 OSSharedPtr
<OSNumber
> powerCaps
;
9047 OSSharedPtr
<OSNumber
> pidNum
;
9048 OSSharedPtr
<OSNumber
> msgNum
;
9049 OSSharedPtr
<const OSSymbol
> appname
;
9050 OSSharedPtr
<const OSSymbol
> sleep
;
9051 OSSharedPtr
<const OSSymbol
> wake
;
9052 IOPMServiceInterestNotifier
*notify
= NULL
;
9054 if (object
&& (notify
= OSDynamicCast(IOPMServiceInterestNotifier
, object
))) {
9055 if (response
->isEqualTo(gIOPMStatsResponseTimedOut
.get())) {
9056 notify
->ackTimeoutCnt
++;
9058 notify
->ackTimeoutCnt
= 0;
9062 if (response
->isEqualTo(gIOPMStatsResponsePrompt
.get()) ||
9063 (_systemTransitionType
== kSystemTransitionNone
) || (_systemTransitionType
== kSystemTransitionNewCapClient
)) {
9068 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
.get())) {
9069 kdebugTrace(kPMLogDrvPSChangeDelay
, id
, messageType
, delay_ms
);
9070 } else if (notify
) {
9071 // User space app or kernel capability client
9073 kdebugTrace(kPMLogAppResponseDelay
, id
, notify
->msgType
, delay_ms
);
9075 kdebugTrace(kPMLogDrvResponseDelay
, notify
->uuid0
, messageType
, delay_ms
);
9077 notify
->msgType
= 0;
9080 responseDescription
= OSDictionary::withCapacity(5);
9081 if (responseDescription
) {
9083 responseDescription
->setObject(_statsResponseTypeKey
.get(), response
);
9086 msgNum
= OSNumber::withNumber(messageType
, 32);
9088 responseDescription
->setObject(_statsMessageTypeKey
.get(), msgNum
.get());
9091 if (!name
&& notify
&& notify
->identifier
) {
9092 name
= notify
->identifier
->getCStringNoCopy();
9095 if (name
&& (strlen(name
) > 0)) {
9096 appname
= OSSymbol::withCString(name
);
9098 responseDescription
->setObject(_statsNameKey
.get(), appname
.get());
9102 if (!id
&& notify
) {
9106 pidNum
= OSNumber::withNumber(id
, 64);
9108 responseDescription
->setObject(_statsPIDKey
.get(), pidNum
.get());
9112 delayNum
= OSNumber::withNumber(delay_ms
, 32);
9114 responseDescription
->setObject(_statsTimeMSKey
.get(), delayNum
.get());
9117 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
.get())) {
9118 powerCaps
= OSNumber::withNumber(powerState
, 32);
9120 #if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
9121 static const char * driverCallTypes
[] = {
9122 [kDriverCallInformPreChange
] = "powerStateWillChangeTo",
9123 [kDriverCallInformPostChange
] = "powerStateDidChangeTo",
9124 [kDriverCallSetPowerState
] = "setPowerState"
9127 if (messageType
< (sizeof(driverCallTypes
) / sizeof(driverCallTypes
[0]))) {
9128 DLOG("%s[0x%qx]::%s(%u) %stook %d ms\n",
9129 name
, id
, driverCallTypes
[messageType
], (uint32_t) powerState
,
9130 async
? "async " : "", delay_ms
);
9134 powerCaps
= OSNumber::withNumber(_pendingCapability
, 32);
9137 responseDescription
->setObject(_statsPowerCapsKey
.get(), powerCaps
.get());
9140 sleep
= OSSymbol::withCString("Sleep");
9141 wake
= OSSymbol::withCString("Wake");
9142 if (_systemTransitionType
== kSystemTransitionSleep
) {
9143 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
.get());
9144 } else if (_systemTransitionType
== kSystemTransitionWake
) {
9145 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
.get());
9146 } else if (_systemTransitionType
== kSystemTransitionCapability
) {
9147 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
)) {
9148 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
.get());
9149 } else if (CAP_GAIN(kIOPMSystemCapabilityGraphics
)) {
9150 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
.get());
9154 IOLockLock(pmStatsLock
);
9155 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount() < 50) {
9156 pmStatsAppResponses
->setObject(responseDescription
.get());
9158 IOLockUnlock(pmStatsLock
);
9165 // MARK: PMTraceWorker
9167 //******************************************************************************
9168 // TracePoint support
9170 //******************************************************************************
9172 #define kIOPMRegisterNVRAMTracePointHandlerKey \
9173 "IOPMRegisterNVRAMTracePointHandler"
9176 IOPMrootDomain::callPlatformFunction(
9177 const OSSymbol
* functionName
,
9178 bool waitForFunction
,
9179 void * param1
, void * param2
,
9180 void * param3
, void * param4
)
9182 if (pmTracer
&& functionName
&&
9183 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
9184 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
) {
9185 uint32_t tracePointPhases
, tracePointPCI
;
9186 uint64_t statusCode
;
9188 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
9189 pmTracer
->tracePointTarget
= (void *) param2
;
9190 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
9191 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
9192 if ((tracePointPhases
& 0xff) == kIOPMTracePointSystemSleep
) {
9193 OSSharedPtr
<IORegistryEntry
> node
= IORegistryEntry::fromPath( "/chosen", gIODTPlane
);
9195 OSSharedPtr
<OSObject
> bootRomFailureProp
;
9196 bootRomFailureProp
= node
->copyProperty(kIOEFIBootRomFailureKey
);
9197 OSData
*data
= OSDynamicCast(OSData
, bootRomFailureProp
.get());
9198 uint32_t bootFailureCode
;
9199 if (data
&& data
->getLength() == sizeof(bootFailureCode
)) {
9200 // Failure code from EFI/BootRom is a four byte structure
9201 memcpy(&bootFailureCode
, data
->getBytesNoCopy(), sizeof(bootFailureCode
));
9202 tracePointPCI
= OSSwapBigToHostInt32(bootFailureCode
);
9206 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
9207 if ((tracePointPhases
& 0xff) != kIOPMTracePointSystemUp
) {
9208 MSG("Sleep failure code 0x%08x 0x%08x\n",
9209 tracePointPCI
, tracePointPhases
);
9211 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
9212 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
9214 return kIOReturnSuccess
;
9217 else if (functionName
&&
9218 functionName
->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey
)) {
9219 if (gSleepPolicyHandler
) {
9220 return kIOReturnExclusiveAccess
;
9223 return kIOReturnBadArgument
;
9225 gSleepPolicyHandler
= (IOPMSystemSleepPolicyHandler
) param1
;
9226 gSleepPolicyTarget
= (void *) param2
;
9227 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue
);
9228 return kIOReturnSuccess
;
9232 return super::callPlatformFunction(
9233 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
9237 IOPMrootDomain::kdebugTrace(uint32_t event
, uint64_t id
,
9238 uintptr_t param1
, uintptr_t param2
, uintptr_t param3
)
9240 uint32_t code
= IODBG_POWER(event
);
9241 uint64_t regId
= id
;
9243 regId
= getRegistryEntryID();
9245 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE
, code
, (uintptr_t) regId
, param1
, param2
, param3
, 0);
9249 IOPMrootDomain::tracePoint( uint8_t point
)
9251 if (systemBooting
) {
9255 if (kIOPMTracePointWakeCapabilityClients
== point
) {
9256 acceptSystemWakeEvents(kAcceptSystemWakeEvents_Disable
);
9259 kdebugTrace(kPMLogSleepWakeTracePoint
, 0, point
, 0);
9260 pmTracer
->tracePoint(point
);
9264 kext_log_putc(char c
)
9266 if (gKextNameEnd
|| gKextNamePos
>= (sizeof(gKextNameBuf
) - 1)) {
9269 if (c
== '(' || c
== '[' || c
== ' ') {
9271 gKextNameEnd
= true;
9274 gKextNameBuf
[gKextNamePos
++] = c
;
9278 kext_log(const char *fmt
, ...)
9282 va_start(listp
, fmt
);
9283 _doprnt(fmt
, &listp
, &kext_log_putc
, 16);
9289 static OSPtr
<const OSSymbol
>
9290 copyKextIdentifierWithAddress(vm_address_t address
)
9292 OSSharedPtr
<const OSSymbol
> identifer
;
9294 IOLockLock(gHaltLogLock
);
9296 gKextNameEnd
= false;
9298 gKextNameBuf
[0] = 0;
9300 OSKext::printKextsInBacktrace(&address
, 1, kext_log
, OSKext::kPrintKextsLock
| OSKext::kPrintKextsTerse
);
9301 gKextNameBuf
[sizeof(gKextNameBuf
) - 1] = 0;
9302 identifer
= OSSymbol::withCString((gKextNameBuf
[0] != 0) ? gKextNameBuf
: kOSKextKernelIdentifier
);
9304 IOLockUnlock(gHaltLogLock
);
9309 // Caller serialized using PM workloop
9311 IOPMrootDomain::getNotificationClientName(OSObject
*object
)
9313 IOPMServiceInterestNotifier
*notifier
= (typeof(notifier
))object
;
9314 const char *clientName
= "UNKNOWN";
9316 if (!notifier
->clientName
) {
9317 // Check for user client
9318 if (systemCapabilityNotifier
&& (((IOPMServiceInterestNotifier
*) systemCapabilityNotifier
.get())->handler
== notifier
->handler
)) {
9319 OSNumber
*clientID
= NULL
;
9320 messageClient(kIOMessageCopyClientID
, object
, &clientID
);
9322 OSSharedPtr
<OSString
> string(IOCopyLogNameForPID(clientID
->unsigned32BitValue()), OSNoRetain
);
9324 notifier
->clientName
= OSSymbol::withString(string
.get());
9326 clientID
->release();
9328 } else if (notifier
->identifier
) {
9329 notifier
->clientName
.reset(notifier
->identifier
.get(), OSRetain
);
9333 if (notifier
->clientName
) {
9334 clientName
= notifier
->clientName
->getCStringNoCopy();
9341 IOPMrootDomain::traceNotification(OSObject
*object
, bool start
, uint64_t timestamp
, uint32_t msgIndex
)
9343 IOPMServiceInterestNotifier
*notifier
;
9345 if (systemBooting
) {
9348 notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, object
);
9354 pmTracer
->traceDetail(notifier
->uuid0
>> 32);
9355 kdebugTrace(kPMLogSleepWakeMessage
, pmTracer
->getTracePhase(),
9356 (uintptr_t) notifier
->msgType
, (uintptr_t) notifier
->uuid0
, (uintptr_t) notifier
->uuid1
);
9358 // Update notifier state used for response/ack logging
9359 notifier
->msgIndex
= msgIndex
;
9360 notifier
->msgAbsTime
= timestamp
;
9362 if (msgIndex
!= UINT_MAX
) {
9363 DLOG("%s[%u] to %s\n", getIOMessageString(notifier
->msgType
), msgIndex
, getNotificationClientName(notifier
));
9365 DLOG("%s to %s\n", getIOMessageString(notifier
->msgType
), getNotificationClientName(notifier
));
9368 assert(notifierObject
== NULL
);
9369 notifierThread
= current_thread();
9370 notifierObject
.reset(notifier
, OSRetain
);
9375 SUB_ABSOLUTETIME(×tamp
, ¬ifier
->msgAbsTime
);
9376 absolutetime_to_nanoseconds(timestamp
, &nsec
);
9377 delayMS
= (uint32_t)(nsec
/ 1000000ULL);
9378 if (delayMS
> notifier
->maxMsgDelayMS
) {
9379 notifier
->maxMsgDelayMS
= delayMS
;
9382 assert(notifierObject
== notifier
);
9383 notifierObject
.reset();
9384 notifierThread
= NULL
;
9389 IOPMrootDomain::traceNotificationAck(OSObject
*object
, uint32_t delay_ms
)
9391 if (systemBooting
) {
9394 IOPMServiceInterestNotifier
*notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, object
);
9399 kdebugTrace(kPMLogDrvResponseDelay
, notifier
->uuid0
,
9400 (uintptr_t) notifier
->uuid1
, (uintptr_t) 0, (uintptr_t) delay_ms
);
9402 DLOG("%s[%u] ack from %s took %d ms\n",
9403 getIOMessageString(notifier
->msgType
), notifier
->msgIndex
, getNotificationClientName(notifier
), delay_ms
);
9404 if (delay_ms
> notifier
->maxAckDelayMS
) {
9405 notifier
->maxAckDelayMS
= delay_ms
;
9410 IOPMrootDomain::traceNotificationResponse(OSObject
*object
, uint32_t delay_ms
, uint32_t ack_time_us
)
9412 if (systemBooting
) {
9415 IOPMServiceInterestNotifier
*notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, object
);
9420 kdebugTrace(kPMLogDrvResponseDelay
, notifier
->uuid0
,
9421 (uintptr_t) notifier
->uuid1
, (uintptr_t)(ack_time_us
/ 1000), (uintptr_t) delay_ms
);
9423 if (ack_time_us
== 0) {
9424 // Client work is done and ack will not be forthcoming
9425 DLOG("%s[%u] response from %s took %d ms\n",
9426 getIOMessageString(notifier
->msgType
), notifier
->msgIndex
, getNotificationClientName(notifier
), delay_ms
);
9428 // Client needs more time and it must ack within ack_time_us
9429 DLOG("%s[%u] response from %s took %d ms (ack in %d us)\n",
9430 getIOMessageString(notifier
->msgType
), notifier
->msgIndex
, getNotificationClientName(notifier
), delay_ms
, ack_time_us
);
9435 IOPMrootDomain::traceFilteredNotification(OSObject
*object
)
9437 if ((kIOLogDebugPower
& gIOKitDebug
) == 0) {
9440 if (systemBooting
) {
9443 IOPMServiceInterestNotifier
*notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, object
);
9448 DLOG("%s to %s dropped\n", getIOMessageString(notifier
->msgType
), getNotificationClientName(notifier
));
9452 IOPMrootDomain::traceDetail(uint32_t msgType
, uint32_t msgIndex
, uint32_t delay
)
9454 if (!systemBooting
) {
9455 uint32_t detail
= ((msgType
& 0xffff) << 16) | (delay
& 0xffff);
9456 pmTracer
->traceDetail( detail
);
9457 kdebugTrace(kPMLogSleepWakeTracePoint
, pmTracer
->getTracePhase(), msgType
, delay
);
9458 DLOG("trace point 0x%02x msgType 0x%x detail 0x%08x\n", pmTracer
->getTracePhase(), msgType
, delay
);
9463 IOPMrootDomain::configureReportGated(uint64_t channel_id
, uint64_t action
, void *result
)
9466 void **report
= NULL
;
9469 uint32_t *clientCnt
;
9474 if (channel_id
== kAssertDelayChID
) {
9475 report
= &assertOnWakeReport
;
9476 bktCnt
= kAssertDelayBcktCnt
;
9477 bktSize
= kAssertDelayBcktSize
;
9478 clientCnt
= &assertOnWakeClientCnt
;
9479 } else if (channel_id
== kSleepDelaysChID
) {
9480 report
= &sleepDelaysReport
;
9481 bktCnt
= kSleepDelaysBcktCnt
;
9482 bktSize
= kSleepDelaysBcktSize
;
9483 clientCnt
= &sleepDelaysClientCnt
;
9490 case kIOReportEnable
:
9497 reportSize
= HISTREPORT_BUFSIZE(bktCnt
);
9498 *report
= IOMalloc(reportSize
);
9499 if (*report
== NULL
) {
9502 bzero(*report
, reportSize
);
9503 HISTREPORT_INIT((uint16_t)bktCnt
, bktSize
, *report
, reportSize
,
9504 getRegistryEntryID(), channel_id
, kIOReportCategoryPower
);
9506 if (channel_id
== kAssertDelayChID
) {
9507 assertOnWakeSecs
= 0;
9512 case kIOReportDisable
:
9513 if (*clientCnt
== 0) {
9516 if (*clientCnt
== 1) {
9517 IOFree(*report
, HISTREPORT_BUFSIZE(bktCnt
));
9522 if (channel_id
== kAssertDelayChID
) {
9523 assertOnWakeSecs
= -1; // Invalid value to prevent updates
9527 case kIOReportGetDimensions
:
9529 HISTREPORT_UPDATERES(*report
, kIOReportGetDimensions
, result
);
9538 IOPMrootDomain::configureReport(IOReportChannelList
*channelList
,
9539 IOReportConfigureAction action
,
9544 uint64_t configAction
= (uint64_t)action
;
9546 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
9547 if ((channelList
->channels
[cnt
].channel_id
== kSleepCntChID
) ||
9548 (channelList
->channels
[cnt
].channel_id
== kDarkWkCntChID
) ||
9549 (channelList
->channels
[cnt
].channel_id
== kUserWkCntChID
)) {
9550 if (action
!= kIOReportGetDimensions
) {
9553 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions
, result
);
9554 } else if ((channelList
->channels
[cnt
].channel_id
== kAssertDelayChID
) ||
9555 (channelList
->channels
[cnt
].channel_id
== kSleepDelaysChID
)) {
9556 gIOPMWorkLoop
->runAction(
9557 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::configureReportGated
),
9558 (OSObject
*)this, (void *)channelList
->channels
[cnt
].channel_id
,
9559 (void *)configAction
, (void *)result
);
9563 return super::configureReport(channelList
, action
, result
, destination
);
9567 IOPMrootDomain::updateReportGated(uint64_t ch_id
, void *result
, IOBufferMemoryDescriptor
*dest
)
9576 if (ch_id
== kAssertDelayChID
) {
9577 report
= &assertOnWakeReport
;
9578 } else if (ch_id
== kSleepDelaysChID
) {
9579 report
= &sleepDelaysReport
;
9582 return kIOReturnBadArgument
;
9585 if (*report
== NULL
) {
9586 return kIOReturnNotOpen
;
9589 HISTREPORT_UPDATEPREP(*report
, data2cpy
, size2cpy
);
9590 if (size2cpy
> (dest
->getCapacity() - dest
->getLength())) {
9591 return kIOReturnOverrun
;
9594 HISTREPORT_UPDATERES(*report
, kIOReportCopyChannelData
, result
);
9595 dest
->appendBytes(data2cpy
, size2cpy
);
9597 return kIOReturnSuccess
;
9601 IOPMrootDomain::updateReport(IOReportChannelList
*channelList
,
9602 IOReportUpdateAction action
,
9608 uint8_t buf
[SIMPLEREPORT_BUFSIZE
];
9609 IOBufferMemoryDescriptor
*dest
= OSDynamicCast(IOBufferMemoryDescriptor
, (OSObject
*)destination
);
9613 if (action
!= kIOReportCopyChannelData
) {
9617 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
9618 ch_id
= channelList
->channels
[cnt
].channel_id
;
9620 if ((ch_id
== kAssertDelayChID
) || (ch_id
== kSleepDelaysChID
)) {
9621 gIOPMWorkLoop
->runAction(
9622 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::updateReportGated
),
9623 (OSObject
*)this, (void *)ch_id
,
9624 (void *)result
, (void *)dest
);
9626 } else if ((ch_id
== kSleepCntChID
) ||
9627 (ch_id
== kDarkWkCntChID
) || (ch_id
== kUserWkCntChID
)) {
9628 SIMPLEREPORT_INIT(buf
, sizeof(buf
), getRegistryEntryID(), ch_id
, kIOReportCategoryPower
);
9633 if (ch_id
== kSleepCntChID
) {
9634 SIMPLEREPORT_SETVALUE(buf
, sleepCnt
);
9635 } else if (ch_id
== kDarkWkCntChID
) {
9636 SIMPLEREPORT_SETVALUE(buf
, darkWakeCnt
);
9637 } else if (ch_id
== kUserWkCntChID
) {
9638 SIMPLEREPORT_SETVALUE(buf
, displayWakeCnt
);
9641 SIMPLEREPORT_UPDATEPREP(buf
, data2cpy
, size2cpy
);
9642 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData
, result
);
9643 dest
->appendBytes(data2cpy
, size2cpy
);
9647 return super::updateReport(channelList
, action
, result
, destination
);
9651 //******************************************************************************
9652 // PMTraceWorker Class
9654 //******************************************************************************
9657 #define super OSObject
9658 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
9660 #define kPMBestGuessPCIDevicesCount 25
9661 #define kPMMaxRTCBitfieldSize 32
9663 OSPtr
<PMTraceWorker
>
9664 PMTraceWorker::tracer(IOPMrootDomain
* owner
)
9666 OSSharedPtr
<PMTraceWorker
> me
= OSMakeShared
<PMTraceWorker
>();
9667 if (!me
|| !me
->init()) {
9671 DLOG("PMTraceWorker %p\n", OBFUSCATE(me
.get()));
9673 // Note that we cannot instantiate the PCI device -> bit mappings here, since
9674 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
9675 // this dictionary lazily.
9677 me
->pciDeviceBitMappings
= NULL
;
9678 me
->pmTraceWorkerLock
= IOLockAlloc();
9679 me
->tracePhase
= kIOPMTracePointSystemUp
;
9680 me
->traceData32
= 0;
9681 me
->loginWindowData
= 0;
9682 me
->coreDisplayData
= 0;
9683 me
->coreGraphicsData
= 0;
9688 PMTraceWorker::RTC_TRACE(void)
9690 if (tracePointHandler
&& tracePointTarget
) {
9693 IOLockLock(pmTraceWorkerLock
);
9694 wordA
= (loginWindowData
<< 24) | (coreDisplayData
<< 16) |
9695 (coreGraphicsData
<< 8) | tracePhase
;
9696 IOLockUnlock(pmTraceWorkerLock
);
9698 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
9699 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
9701 #if DEVELOPMENT || DEBUG
9702 if ((swd_panic_phase
!= 0) && (swd_panic_phase
== tracePhase
)) {
9703 DEBUG_LOG("Causing sleep wake failure in phase 0x%08x\n", tracePhase
);
9704 IOLock
*l
= IOLockAlloc();
9712 PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
9714 OSSharedPtr
<const OSSymbol
> deviceName
;
9717 IOLockLock(pmTraceWorkerLock
);
9719 if (!pciDeviceBitMappings
) {
9720 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
9721 if (!pciDeviceBitMappings
) {
9726 // Check for bitmask overflow.
9727 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
) {
9731 if ((deviceName
= pciDevice
->copyName()) &&
9732 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
.get(), 0) == (unsigned int)-1) &&
9733 pciDeviceBitMappings
->setObject(deviceName
.get())) {
9734 index
= pciDeviceBitMappings
->getCount() - 1;
9735 _LOG("PMTrace PCI array: set object %s => %d\n",
9736 deviceName
->getCStringNoCopy(), index
);
9739 if (!addedToRegistry
&& (index
>= 0)) {
9740 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
9744 IOLockUnlock(pmTraceWorkerLock
);
9749 PMTraceWorker::serialize(OSSerialize
*s
) const
9752 if (pciDeviceBitMappings
) {
9753 IOLockLock(pmTraceWorkerLock
);
9754 ok
= pciDeviceBitMappings
->serialize(s
);
9755 IOLockUnlock(pmTraceWorkerLock
);
9761 PMTraceWorker::tracePoint(uint8_t phase
)
9763 // clear trace detail when phase begins
9764 if (tracePhase
!= phase
) {
9770 DLOG("trace point 0x%02x\n", tracePhase
);
9775 PMTraceWorker::traceDetail(uint32_t detail
)
9777 if (detail
== traceData32
) {
9780 traceData32
= detail
;
9785 PMTraceWorker::traceComponentWakeProgress(uint32_t component
, uint32_t data
)
9787 switch (component
) {
9788 case kIOPMLoginWindowProgress
:
9789 loginWindowData
= data
& kIOPMLoginWindowProgressMask
;
9791 case kIOPMCoreDisplayProgress
:
9792 coreDisplayData
= data
& kIOPMCoreDisplayProgressMask
;
9794 case kIOPMCoreGraphicsProgress
:
9795 coreGraphicsData
= data
& kIOPMCoreGraphicsProgressMask
;
9801 DLOG("component trace point 0x%02x data 0x%08x\n", component
, data
);
9806 PMTraceWorker::tracePCIPowerChange(
9807 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
9810 uint32_t expectedFlag
;
9812 // Ignore PCI changes outside of system sleep/wake.
9813 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
9814 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
)) {
9818 // Only record the WillChange transition when going to sleep,
9819 // and the DidChange on the way up.
9820 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
9821 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
9822 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
9823 if (changeFlags
!= expectedFlag
) {
9827 // Mark this device off in our bitfield
9828 if (bitNum
< kPMMaxRTCBitfieldSize
) {
9829 bitMask
= (1 << bitNum
);
9831 if (kPowerChangeStart
== type
) {
9832 traceData32
|= bitMask
;
9833 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
9834 service
->getName(), bitNum
, bitMask
, traceData32
);
9835 owner
->kdebugTrace(kPMLogPCIDevChangeStart
, service
->getRegistryEntryID(), traceData32
, 0);
9837 traceData32
&= ~bitMask
;
9838 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
9839 service
->getName(), bitNum
, bitMask
, traceData32
);
9840 owner
->kdebugTrace(kPMLogPCIDevChangeDone
, service
->getRegistryEntryID(), traceData32
, 0);
9843 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
9849 PMTraceWorker::getPMStatusCode()
9851 return ((uint64_t)traceData32
<< 32) | ((uint64_t)tracePhase
);
9855 PMTraceWorker::getTracePhase()
9861 PMTraceWorker::getTraceData()
9867 // MARK: PMHaltWorker
9869 //******************************************************************************
9870 // PMHaltWorker Class
9872 //******************************************************************************
9875 PMHaltWorker::worker( void )
9881 me
= OSTypeAlloc( PMHaltWorker
);
9882 if (!me
|| !me
->init()) {
9886 me
->lock
= IOLockAlloc();
9891 DLOG("PMHaltWorker %p\n", OBFUSCATE(me
));
9892 me
->retain(); // thread holds extra retain
9893 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
)) {
9897 thread_deallocate(thread
);
9908 PMHaltWorker::free( void )
9910 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
9915 return OSObject::free();
9919 PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
9921 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
9923 IOLockLock( gPMHaltLock
);
9925 me
->depth
= gPMHaltDepth
;
9926 IOLockUnlock( gPMHaltLock
);
9928 while (me
->depth
>= 0) {
9929 PMHaltWorker::work( me
);
9931 IOLockLock( gPMHaltLock
);
9932 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
) {
9933 // This is the last thread to finish work on this level,
9934 // inform everyone to start working on next lower level.
9936 me
->depth
= gPMHaltDepth
;
9937 gPMHaltIdleCount
= 0;
9938 thread_wakeup((event_t
) &gPMHaltIdleCount
);
9940 // One or more threads are still working on this level,
9941 // this thread must wait.
9942 me
->depth
= gPMHaltDepth
- 1;
9944 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
9945 } while (me
->depth
!= gPMHaltDepth
);
9947 IOLockUnlock( gPMHaltLock
);
9950 // No more work to do, terminate thread
9951 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me
), me
->visits
);
9952 thread_wakeup( &gPMHaltDepth
);
9957 PMHaltWorker::work( PMHaltWorker
* me
)
9959 OSSharedPtr
<IOService
> service
;
9961 AbsoluteTime startTime
, elapsedTime
;
9968 // Claim an unit of work from the shared pool
9969 IOLockLock( gPMHaltLock
);
9970 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
9972 service
.reset(OSDynamicCast(IOService
, inner
->getAnyObject()), OSRetain
);
9974 inner
->removeObject(service
.get());
9977 IOLockUnlock( gPMHaltLock
);
9979 break; // no more work at this depth
9981 clock_get_uptime(&startTime
);
9983 if (!service
->isInactive() &&
9984 service
->setProperty(gPMHaltClientAcknowledgeKey
.get(), me
)) {
9985 IOLockLock(me
->lock
);
9986 me
->startTime
= startTime
;
9987 me
->service
= service
.get();
9988 me
->timeout
= false;
9989 IOLockUnlock(me
->lock
);
9991 service
->systemWillShutdown( gPMHaltMessageType
);
9993 // Wait for driver acknowledgement
9994 IOLockLock(me
->lock
);
9995 while (service
->propertyExists(gPMHaltClientAcknowledgeKey
.get())) {
9996 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
9999 timeout
= me
->timeout
;
10000 IOLockUnlock(me
->lock
);
10003 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
10004 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
) {
10005 LOG("%s driver %s (0x%llx) took %u ms\n",
10006 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ?
10007 "PowerOff" : "Restart",
10008 service
->getName(), service
->getRegistryEntryID(),
10009 (uint32_t) deltaTime
);
10010 halt_log_enter("PowerOff/Restart handler completed",
10011 OSMemberFunctionCast(const void *, service
.get(), &IOService::systemWillShutdown
),
10020 PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
10023 AbsoluteTime startTime
;
10024 AbsoluteTime endTime
;
10028 IOLockLock(me
->lock
);
10029 if (me
->service
&& !me
->timeout
) {
10030 startTime
= me
->startTime
;
10032 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0) {
10033 SUB_ABSOLUTETIME(&endTime
, &startTime
);
10034 absolutetime_to_nanoseconds(endTime
, &nano
);
10036 if (nano
> 3000000000ULL) {
10037 me
->timeout
= true;
10039 halt_log_enter("PowerOff/Restart still waiting on handler",
10040 OSMemberFunctionCast(const void *, me
->service
, &IOService::systemWillShutdown
),
10042 MSG("%s still waiting on %s\n",
10043 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" : "Restart",
10044 me
->service
->getName());
10047 IOLockUnlock(me
->lock
);
10050 //******************************************************************************
10051 // acknowledgeSystemWillShutdown
10053 // Acknowledgement from drivers that they have prepared for shutdown/restart.
10054 //******************************************************************************
10057 IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
10059 PMHaltWorker
* worker
;
10060 OSSharedPtr
<OSObject
> prop
;
10066 //DLOG("%s acknowledged\n", from->getName());
10067 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
.get());
10069 worker
= (PMHaltWorker
*) prop
.get();
10070 IOLockLock(worker
->lock
);
10071 from
->removeProperty( gPMHaltClientAcknowledgeKey
.get());
10072 thread_wakeup((event_t
) worker
);
10073 IOLockUnlock(worker
->lock
);
10075 DLOG("%s acknowledged without worker property\n",
10081 //******************************************************************************
10082 // notifySystemShutdown
10084 // Notify all objects in PM tree that system will shutdown or restart
10085 //******************************************************************************
10088 notifySystemShutdown( IOService
* root
, uint32_t messageType
)
10090 #define PLACEHOLDER ((OSSet *)gPMHaltArray.get())
10091 OSSharedPtr
<IORegistryIterator
> iter
;
10092 IORegistryEntry
* entry
;
10095 OSSharedPtr
<OSSet
> newInner
;
10096 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
10097 AbsoluteTime deadline
;
10098 unsigned int totalNodes
= 0;
10099 unsigned int depth
;
10100 unsigned int rootDepth
;
10101 unsigned int numWorkers
;
10102 unsigned int count
;
10107 DLOG("%s msgType = 0x%x\n", __FUNCTION__
, messageType
);
10109 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
10111 // Iterate the entire PM tree starting from root
10113 rootDepth
= root
->getDepth( gIOPowerPlane
);
10118 // debug - for repeated test runs
10119 while (PMHaltWorker::metaClass
->getInstanceCount()) {
10123 if (!gPMHaltArray
) {
10124 gPMHaltArray
= OSArray::withCapacity(40);
10125 if (!gPMHaltArray
) {
10129 gPMHaltArray
->flushCollection();
10132 if (!gPMHaltLock
) {
10133 gPMHaltLock
= IOLockAlloc();
10134 if (!gPMHaltLock
) {
10139 if (!gPMHaltClientAcknowledgeKey
) {
10140 gPMHaltClientAcknowledgeKey
=
10141 OSSymbol::withCStringNoCopy("PMShutdown");
10142 if (!gPMHaltClientAcknowledgeKey
) {
10147 gPMHaltMessageType
= messageType
;
10149 // Depth-first walk of PM plane
10151 iter
= IORegistryIterator::iterateOver(
10152 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
10155 while ((entry
= iter
->getNextObject())) {
10156 node
= OSDynamicCast(IOService
, entry
);
10162 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
)) {
10166 depth
= node
->getDepth( gIOPowerPlane
);
10167 if (depth
<= rootDepth
) {
10173 // adjust to zero based depth
10174 depth
-= (rootDepth
+ 1);
10176 // gPMHaltArray is an array of containers, each container
10177 // refers to nodes with the same depth.
10179 count
= gPMHaltArray
->getCount();
10180 while (depth
>= count
) {
10181 // expand array and insert placeholders
10182 gPMHaltArray
->setObject(PLACEHOLDER
);
10185 count
= gPMHaltArray
->getCount();
10186 if (depth
< count
) {
10187 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
10188 if (inner
== PLACEHOLDER
) {
10189 newInner
= OSSet::withCapacity(40);
10191 gPMHaltArray
->replaceObject(depth
, newInner
.get());
10192 inner
= newInner
.get();
10196 // PM nodes that appear more than once in the tree will have
10197 // the same depth, OSSet will refuse to add the node twice.
10199 ok
= inner
->setObject(node
);
10203 DLOG("Skipped PM node %s\n", node
->getName());
10209 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++) {
10211 if (inner
!= PLACEHOLDER
) {
10212 count
= inner
->getCount();
10214 DLOG("Nodes at depth %u = %u\n", i
, count
);
10217 // strip placeholders (not all depths are populated)
10219 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
));) {
10220 if (inner
== PLACEHOLDER
) {
10221 gPMHaltArray
->removeObject(i
);
10224 count
= inner
->getCount();
10225 if (count
> numWorkers
) {
10226 numWorkers
= count
;
10228 totalNodes
+= count
;
10232 if (gPMHaltArray
->getCount() == 0 || !numWorkers
) {
10236 gPMHaltBusyCount
= 0;
10237 gPMHaltIdleCount
= 0;
10238 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
10240 // Create multiple workers (and threads)
10242 if (numWorkers
> kPMHaltMaxWorkers
) {
10243 numWorkers
= kPMHaltMaxWorkers
;
10246 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
10247 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
10249 for (unsigned int i
= 0; i
< numWorkers
; i
++) {
10250 workers
[i
] = PMHaltWorker::worker();
10253 // Wait for workers to exhaust all available work
10255 IOLockLock(gPMHaltLock
);
10256 while (gPMHaltDepth
>= 0) {
10257 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
10259 waitResult
= IOLockSleepDeadline(
10260 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
10261 if (THREAD_TIMED_OUT
== waitResult
) {
10263 clock_get_uptime(&now
);
10265 IOLockUnlock(gPMHaltLock
);
10266 for (unsigned int i
= 0; i
< numWorkers
; i
++) {
10268 PMHaltWorker::checkTimeout(workers
[i
], &now
);
10271 IOLockLock(gPMHaltLock
);
10274 IOLockUnlock(gPMHaltLock
);
10276 // Release all workers
10278 for (unsigned int i
= 0; i
< numWorkers
; i
++) {
10280 workers
[i
]->release();
10282 // worker also retained by it's own thread
10286 DLOG("%s done\n", __FUNCTION__
);
10291 // MARK: Kernel Assertion
10293 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10295 IOPMDriverAssertionID
10296 IOPMrootDomain::createPMAssertion(
10297 IOPMDriverAssertionType whichAssertionBits
,
10298 IOPMDriverAssertionLevel assertionLevel
,
10299 IOService
*ownerService
,
10300 const char *ownerDescription
)
10303 IOPMDriverAssertionID newAssertion
;
10305 if (!pmAssertions
) {
10309 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
10311 if (kIOReturnSuccess
== ret
) {
10312 return newAssertion
;
10319 IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
10321 if (!pmAssertions
) {
10322 return kIOReturnInternalError
;
10325 return pmAssertions
->releaseAssertion(releaseAssertion
);
10330 IOPMrootDomain::setPMAssertionLevel(
10331 IOPMDriverAssertionID assertionID
,
10332 IOPMDriverAssertionLevel assertionLevel
)
10334 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
10337 IOPMDriverAssertionLevel
10338 IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
10340 IOPMDriverAssertionType sysLevels
;
10342 if (!pmAssertions
|| whichAssertion
== 0) {
10343 return kIOPMDriverAssertionLevelOff
;
10346 sysLevels
= pmAssertions
->getActivatedAssertions();
10348 // Check that every bit set in argument 'whichAssertion' is asserted
10349 // in the aggregate bits.
10350 if ((sysLevels
& whichAssertion
) == whichAssertion
) {
10351 return kIOPMDriverAssertionLevelOn
;
10353 return kIOPMDriverAssertionLevelOff
;
10358 IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
10360 if (!pmAssertions
) {
10361 return kIOReturnNotFound
;
10364 return pmAssertions
->setUserAssertionLevels(inLevels
);
10368 IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
10370 if (pmAssertions
) {
10371 pmAssertions
->publishProperties();
10373 return IOService::serializeProperties(s
);
10376 OSSharedPtr
<OSObject
>
10377 IOPMrootDomain::copyProperty( const char * aKey
) const
10379 OSSharedPtr
<OSObject
> obj
;
10380 obj
= IOService::copyProperty(aKey
);
10386 if (!strncmp(aKey
, kIOPMSleepWakeWdogRebootKey
,
10387 sizeof(kIOPMSleepWakeWdogRebootKey
))) {
10388 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
10389 return OSSharedPtr
<OSBoolean
>(kOSBooleanTrue
, OSNoRetain
);
10391 return OSSharedPtr
<OSBoolean
>(kOSBooleanFalse
, OSNoRetain
);
10395 if (!strncmp(aKey
, kIOPMSleepWakeWdogLogsValidKey
,
10396 sizeof(kIOPMSleepWakeWdogLogsValidKey
))) {
10397 if (swd_flags
& SWD_VALID_LOGS
) {
10398 return OSSharedPtr
<OSBoolean
>(kOSBooleanTrue
, OSNoRetain
);
10400 return OSSharedPtr
<OSBoolean
>(kOSBooleanFalse
, OSNoRetain
);
10405 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
10406 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
10407 * issued by DisplayWrangler on darkwake.
10409 if (!strcmp(aKey
, "DesktopMode")) {
10411 return OSSharedPtr
<OSBoolean
>(kOSBooleanTrue
, OSNoRetain
);
10413 return OSSharedPtr
<OSBoolean
>(kOSBooleanFalse
, OSNoRetain
);
10416 if (!strcmp(aKey
, "DisplayIdleForDemandSleep")) {
10417 if (displayIdleForDemandSleep
) {
10418 return OSSharedPtr
<OSBoolean
>(kOSBooleanTrue
, OSNoRetain
);
10420 return OSSharedPtr
<OSBoolean
>(kOSBooleanFalse
, OSNoRetain
);
10424 if (!strcmp(aKey
, kIOPMDriverWakeEventsKey
)) {
10425 OSSharedPtr
<OSArray
> array
;
10427 if (_systemWakeEventsArray
&& _systemWakeEventsArray
->getCount()) {
10428 OSSharedPtr
<OSCollection
> collection
= _systemWakeEventsArray
->copyCollection();
10430 array
= OSDynamicPtrCast
<OSArray
>(collection
);
10433 WAKEEVENT_UNLOCK();
10434 return os::move(array
);
10437 if (!strcmp(aKey
, kIOPMSleepStatisticsAppsKey
)) {
10438 OSSharedPtr
<OSArray
> array
;
10439 IOLockLock(pmStatsLock
);
10440 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount()) {
10441 OSSharedPtr
<OSCollection
> collection
= pmStatsAppResponses
->copyCollection();
10443 array
= OSDynamicPtrCast
<OSArray
>(collection
);
10446 IOLockUnlock(pmStatsLock
);
10447 return os::move(array
);
10450 if (!strcmp(aKey
, kIOPMIdleSleepPreventersKey
)) {
10451 OSArray
*idleSleepList
= NULL
;
10452 gRootDomain
->copySleepPreventersList(&idleSleepList
, NULL
);
10453 return OSSharedPtr
<OSArray
>(idleSleepList
, OSNoRetain
);
10456 if (!strcmp(aKey
, kIOPMSystemSleepPreventersKey
)) {
10457 OSArray
*systemSleepList
= NULL
;
10458 gRootDomain
->copySleepPreventersList(NULL
, &systemSleepList
);
10459 return OSSharedPtr
<OSArray
>(systemSleepList
, OSNoRetain
);
10462 if (!strcmp(aKey
, kIOPMIdleSleepPreventersWithIDKey
)) {
10463 OSArray
*idleSleepList
= NULL
;
10464 gRootDomain
->copySleepPreventersListWithID(&idleSleepList
, NULL
);
10465 return OSSharedPtr
<OSArray
>(idleSleepList
, OSNoRetain
);
10468 if (!strcmp(aKey
, kIOPMSystemSleepPreventersWithIDKey
)) {
10469 OSArray
*systemSleepList
= NULL
;
10470 gRootDomain
->copySleepPreventersListWithID(NULL
, &systemSleepList
);
10471 return OSSharedPtr
<OSArray
>(systemSleepList
, OSNoRetain
);
10477 // MARK: Wake Event Reporting
10480 IOPMrootDomain::copyWakeReasonString( char * outBuf
, size_t bufSize
)
10483 strlcpy(outBuf
, gWakeReasonString
, bufSize
);
10484 WAKEEVENT_UNLOCK();
10488 IOPMrootDomain::copyShutdownReasonString( char * outBuf
, size_t bufSize
)
10491 strlcpy(outBuf
, gShutdownReasonString
, bufSize
);
10492 WAKEEVENT_UNLOCK();
10495 //******************************************************************************
10496 // acceptSystemWakeEvents
10498 // Private control for the acceptance of driver wake event claims.
10499 //******************************************************************************
10502 IOPMrootDomain::acceptSystemWakeEvents( uint32_t control
)
10504 bool logWakeReason
= false;
10508 case kAcceptSystemWakeEvents_Enable
:
10509 assert(_acceptSystemWakeEvents
== false);
10510 if (!_systemWakeEventsArray
) {
10511 _systemWakeEventsArray
= OSArray::withCapacity(4);
10513 _acceptSystemWakeEvents
= (_systemWakeEventsArray
!= NULL
);
10514 if (!(_aotNow
&& (kIOPMWakeEventAOTExitFlags
& _aotPendingFlags
))) {
10515 gWakeReasonString
[0] = '\0';
10516 if (_systemWakeEventsArray
) {
10517 _systemWakeEventsArray
->flushCollection();
10521 // Remove stale WakeType property before system sleep
10522 removeProperty(kIOPMRootDomainWakeTypeKey
);
10523 removeProperty(kIOPMRootDomainWakeReasonKey
);
10526 case kAcceptSystemWakeEvents_Disable
:
10527 _acceptSystemWakeEvents
= false;
10528 #if defined(XNU_TARGET_OS_OSX)
10529 logWakeReason
= (gWakeReasonString
[0] != '\0');
10530 #else /* !defined(XNU_TARGET_OS_OSX) */
10531 logWakeReason
= gWakeReasonSysctlRegistered
;
10533 static int panic_allowed
= -1;
10535 if ((panic_allowed
== -1) &&
10536 (PE_parse_boot_argn("swd_wakereason_panic", &panic_allowed
, sizeof(panic_allowed
)) == false)) {
10540 if (panic_allowed
) {
10542 // Panic if wake reason is null or empty
10543 for (i
= 0; (i
< strlen(gWakeReasonString
)); i
++) {
10544 if ((gWakeReasonString
[i
] != ' ') && (gWakeReasonString
[i
] != '\t')) {
10548 if (i
>= strlen(gWakeReasonString
)) {
10549 panic("Wake reason is empty\n");
10552 #endif /* DEVELOPMENT */
10553 #endif /* !defined(XNU_TARGET_OS_OSX) */
10555 // publish kIOPMRootDomainWakeReasonKey if not already set
10556 if (!propertyExists(kIOPMRootDomainWakeReasonKey
)) {
10557 setProperty(kIOPMRootDomainWakeReasonKey
, gWakeReasonString
);
10561 case kAcceptSystemWakeEvents_Reenable
:
10562 assert(_acceptSystemWakeEvents
== false);
10563 _acceptSystemWakeEvents
= (_systemWakeEventsArray
!= NULL
);
10564 removeProperty(kIOPMRootDomainWakeReasonKey
);
10567 WAKEEVENT_UNLOCK();
10569 if (logWakeReason
) {
10570 MSG("system wake events: %s\n", gWakeReasonString
);
10574 //******************************************************************************
10575 // claimSystemWakeEvent
10577 // For a driver to claim a device is the source/conduit of a system wake event.
10578 //******************************************************************************
10581 IOPMrootDomain::claimSystemWakeEvent(
10582 IOService
* device
,
10583 IOOptionBits flags
,
10584 const char * reason
,
10585 OSObject
* details
)
10587 OSSharedPtr
<const OSSymbol
> deviceName
;
10588 OSSharedPtr
<OSNumber
> deviceRegId
;
10589 OSSharedPtr
<OSNumber
> claimTime
;
10590 OSSharedPtr
<OSData
> flagsData
;
10591 OSSharedPtr
<OSString
> reasonString
;
10592 OSSharedPtr
<OSDictionary
> dict
;
10593 uint64_t timestamp
;
10594 bool addWakeReason
;
10596 if (!device
|| !reason
) {
10600 pmEventTimeStamp(×tamp
);
10602 IOOptionBits aotFlags
= 0;
10603 bool needAOTEvaluate
= FALSE
;
10605 if (kIOPMAOTModeAddEventFlags
& _aotMode
) {
10606 if (!strcmp("hold", reason
)
10607 || !strcmp("help", reason
)
10608 || !strcmp("menu", reason
)
10609 || !strcmp("stockholm", reason
)
10610 || !strcmp("ringer", reason
)
10611 || !strcmp("ringerab", reason
)
10612 || !strcmp("smc0", reason
)
10613 || !strcmp("AOP.RTPWakeupAP", reason
)
10614 || !strcmp("BT.OutboxNotEmpty", reason
)
10615 || !strcmp("WL.OutboxNotEmpty", reason
)) {
10616 flags
|= kIOPMWakeEventAOTExit
;
10620 #if DEVELOPMENT || DEBUG
10621 if (_aotLingerTime
&& !strcmp("rtc", reason
)) {
10622 flags
|= kIOPMWakeEventAOTPossibleExit
;
10624 #endif /* DEVELOPMENT || DEBUG */
10626 #if defined(XNU_TARGET_OS_OSX) && !DISPLAY_WRANGLER_PRESENT
10627 // Publishing the WakeType is serialized by the PM work loop
10628 if (!strcmp("rtc", reason
) && (_nextScheduledAlarmType
!= NULL
)) {
10629 pmPowerStateQueue
->submitPowerEvent(kPowerEventPublishWakeType
,
10630 (void *) _nextScheduledAlarmType
.get());
10633 // Workaround for the missing wake HID event
10634 if (gDarkWakeFlags
& kDarkWakeFlagUserWakeWorkaround
) {
10635 if (!strcmp("trackpadkeyboard", reason
)) {
10636 pmPowerStateQueue
->submitPowerEvent(kPowerEventPublishWakeType
,
10637 (void *) gIOPMWakeTypeUserKey
.get());
10642 deviceName
= device
->copyName(gIOServicePlane
);
10643 deviceRegId
= OSNumber::withNumber(device
->getRegistryEntryID(), 64);
10644 claimTime
= OSNumber::withNumber(timestamp
, 64);
10645 flagsData
= OSData::withBytes(&flags
, sizeof(flags
));
10646 reasonString
= OSString::withCString(reason
);
10647 dict
= OSDictionary::withCapacity(5 + (details
? 1 : 0));
10648 if (!dict
|| !deviceName
|| !deviceRegId
|| !claimTime
|| !flagsData
|| !reasonString
) {
10652 dict
->setObject(gIONameKey
, deviceName
.get());
10653 dict
->setObject(gIORegistryEntryIDKey
, deviceRegId
.get());
10654 dict
->setObject(kIOPMWakeEventTimeKey
, claimTime
.get());
10655 dict
->setObject(kIOPMWakeEventFlagsKey
, flagsData
.get());
10656 dict
->setObject(kIOPMWakeEventReasonKey
, reasonString
.get());
10658 dict
->setObject(kIOPMWakeEventDetailsKey
, details
);
10662 addWakeReason
= _acceptSystemWakeEvents
;
10664 IOLog("claimSystemWakeEvent(%s, %s, 0x%x) 0x%x %d\n", reason
, deviceName
->getCStringNoCopy(), (int)flags
, _aotPendingFlags
, _aotReadyToFullWake
);
10666 aotFlags
= (kIOPMWakeEventAOTFlags
& flags
);
10667 aotFlags
= (aotFlags
& ~_aotPendingFlags
);
10668 needAOTEvaluate
= false;
10669 if (_aotNow
&& aotFlags
) {
10670 if (kIOPMWakeEventAOTPossibleExit
& flags
) {
10671 _aotMetrics
->possibleCount
++;
10673 if (kIOPMWakeEventAOTConfirmedPossibleExit
& flags
) {
10674 _aotMetrics
->confirmedPossibleCount
++;
10676 if (kIOPMWakeEventAOTRejectedPossibleExit
& flags
) {
10677 _aotMetrics
->rejectedPossibleCount
++;
10679 if (kIOPMWakeEventAOTExpiredPossibleExit
& flags
) {
10680 _aotMetrics
->expiredPossibleCount
++;
10683 _aotPendingFlags
|= aotFlags
;
10684 addWakeReason
= _aotNow
&& _systemWakeEventsArray
&& ((kIOPMWakeEventAOTExitFlags
& aotFlags
));
10685 needAOTEvaluate
= _aotReadyToFullWake
;
10687 DMSG("claimSystemWakeEvent(%s, 0x%x, %s, 0x%llx) aot %d phase 0x%x add %d\n",
10688 reason
, (int)flags
, deviceName
->getCStringNoCopy(), device
->getRegistryEntryID(),
10689 _aotNow
, pmTracer
->getTracePhase(), addWakeReason
);
10691 if (!gWakeReasonSysctlRegistered
) {
10692 // Lazy registration until the platform driver stops registering
10694 gWakeReasonSysctlRegistered
= true;
10695 #if !defined(XNU_TARGET_OS_OSX)
10696 sysctl_register_oid(&sysctl__kern_wakereason
);
10697 #endif /* !defined(XNU_TARGET_OS_OSX) */
10699 if (addWakeReason
) {
10700 _systemWakeEventsArray
->setObject(dict
.get());
10701 if (gWakeReasonString
[0] != '\0') {
10702 strlcat(gWakeReasonString
, " ", sizeof(gWakeReasonString
));
10704 strlcat(gWakeReasonString
, reason
, sizeof(gWakeReasonString
));
10707 WAKEEVENT_UNLOCK();
10708 if (needAOTEvaluate
) {
10709 // Call aotEvaluate() on PM work loop since it may call
10710 // aotExit() which accesses PM state.
10711 pmPowerStateQueue
->submitPowerEvent(kPowerEventAOTEvaluate
);
10718 //******************************************************************************
10719 // claimSystemBootEvent
10721 // For a driver to claim a device is the source/conduit of a system boot event.
10722 //******************************************************************************
10725 IOPMrootDomain::claimSystemBootEvent(
10726 IOService
* device
,
10727 IOOptionBits flags
,
10728 const char * reason
,
10729 __unused OSObject
* details
)
10731 if (!device
|| !reason
) {
10735 DEBUG_LOG("claimSystemBootEvent(%s, %s, 0x%x)\n", reason
, device
->getName(), (uint32_t) flags
);
10737 if (!gBootReasonSysctlRegistered
) {
10738 // Lazy sysctl registration after setting gBootReasonString
10739 strlcat(gBootReasonString
, reason
, sizeof(gBootReasonString
));
10740 sysctl_register_oid(&sysctl__kern_bootreason
);
10741 gBootReasonSysctlRegistered
= true;
10743 WAKEEVENT_UNLOCK();
10746 //******************************************************************************
10747 // claimSystemShutdownEvent
10749 // For drivers to claim a system shutdown event on the ensuing boot.
10750 //******************************************************************************
10753 IOPMrootDomain::claimSystemShutdownEvent(
10754 IOService
* device
,
10755 IOOptionBits flags
,
10756 const char * reason
,
10757 __unused OSObject
* details
)
10759 if (!device
|| !reason
) {
10763 DEBUG_LOG("claimSystemShutdownEvent(%s, %s, 0x%x)\n", reason
, device
->getName(), (uint32_t) flags
);
10765 if (gShutdownReasonString
[0] != '\0') {
10766 strlcat(gShutdownReasonString
, " ", sizeof(gShutdownReasonString
));
10768 strlcat(gShutdownReasonString
, reason
, sizeof(gShutdownReasonString
));
10770 if (!gShutdownReasonSysctlRegistered
) {
10771 sysctl_register_oid(&sysctl__kern_shutdownreason
);
10772 gShutdownReasonSysctlRegistered
= true;
10774 WAKEEVENT_UNLOCK();
10777 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10780 // MARK: PMSettingHandle
10782 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
10785 PMSettingHandle::free( void )
10788 pmso
->clientHandleFreed();
10797 // MARK: PMSettingObject
10800 #define super OSObject
10801 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
10804 * Static constructor/initializer for PMSettingObject
10806 PMSettingObject
*PMSettingObject::pmSettingObject(
10807 IOPMrootDomain
* parent_arg
,
10808 IOPMSettingControllerCallback handler_arg
,
10809 OSObject
* target_arg
,
10810 uintptr_t refcon_arg
,
10811 uint32_t supportedPowerSources
,
10812 const OSSymbol
* settings
[],
10813 OSObject
* *handle_obj
)
10815 uint32_t settingCount
= 0;
10816 PMSettingObject
*pmso
= NULL
;
10817 PMSettingHandle
*pmsh
= NULL
;
10819 if (!parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
) {
10823 // count OSSymbol entries in NULL terminated settings array
10824 while (settings
[settingCount
]) {
10827 if (0 == settingCount
) {
10831 pmso
= new PMSettingObject
;
10832 if (!pmso
|| !pmso
->init()) {
10836 pmsh
= new PMSettingHandle
;
10837 if (!pmsh
|| !pmsh
->init()) {
10841 queue_init(&pmso
->calloutQueue
);
10842 pmso
->parent
= parent_arg
;
10843 pmso
->func
= handler_arg
;
10844 pmso
->target
= target_arg
;
10845 pmso
->refcon
= refcon_arg
;
10846 pmso
->settingCount
= settingCount
;
10848 pmso
->retain(); // handle holds a retain on pmso
10852 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t) * settingCount
);
10853 if (pmso
->publishedFeatureID
) {
10854 for (unsigned int i
= 0; i
< settingCount
; i
++) {
10855 // Since there is now at least one listener to this setting, publish
10856 // PM root domain support for it.
10857 parent_arg
->publishPMSetting( settings
[i
],
10858 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
10862 *handle_obj
= pmsh
;
10876 PMSettingObject::free( void )
10878 if (publishedFeatureID
) {
10879 for (uint32_t i
= 0; i
< settingCount
; i
++) {
10880 if (publishedFeatureID
[i
]) {
10881 parent
->removePublishedFeature( publishedFeatureID
[i
] );
10885 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
10892 PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
10894 return (*func
)(target
, type
, object
, refcon
);
10898 PMSettingObject::clientHandleFreed( void )
10900 parent
->deregisterPMSettingObject(this);
10904 // MARK: PMAssertionsTracker
10906 //*********************************************************************************
10907 //*********************************************************************************
10908 //*********************************************************************************
10909 // class PMAssertionsTracker Implementation
10911 #define kAssertUniqueIDStart 500
10913 PMAssertionsTracker
*
10914 PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
10916 PMAssertionsTracker
*me
;
10918 me
= new PMAssertionsTracker
;
10919 if (!me
|| !me
->init()) {
10926 me
->owner
= rootDomain
;
10927 me
->issuingUniqueID
= kAssertUniqueIDStart
;
10928 me
->assertionsArray
= OSArray::withCapacity(5);
10929 me
->assertionsKernel
= 0;
10930 me
->assertionsUser
= 0;
10931 me
->assertionsCombined
= 0;
10932 me
->assertionsArrayLock
= IOLockAlloc();
10933 me
->tabulateProducerCount
= me
->tabulateConsumerCount
= 0;
10935 assert(me
->assertionsArray
);
10936 assert(me
->assertionsArrayLock
);
10942 * - Update assertionsKernel to reflect the state of all
10943 * assertions in the kernel.
10944 * - Update assertionsCombined to reflect both kernel & user space.
10947 PMAssertionsTracker::tabulate(void)
10951 PMAssertStruct
*_a
= NULL
;
10954 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
10955 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
10959 assertionsKernel
= 0;
10960 assertionsCombined
= 0;
10962 if (!assertionsArray
) {
10966 if ((count
= assertionsArray
->getCount())) {
10967 for (i
= 0; i
< count
; i
++) {
10968 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
10970 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
10971 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
)) {
10972 assertionsKernel
|= _a
->assertionBits
;
10978 tabulateProducerCount
++;
10979 assertionsCombined
= assertionsKernel
| assertionsUser
;
10981 if ((assertionsKernel
!= oldKernel
) ||
10982 (assertionsCombined
!= oldCombined
)) {
10983 owner
->evaluateAssertions(assertionsCombined
, oldCombined
);
10988 PMAssertionsTracker::updateCPUBitAccounting( PMAssertStruct
*assertStruct
)
10993 if (((assertStruct
->assertionBits
& kIOPMDriverAssertionCPUBit
) == 0) ||
10994 (assertStruct
->assertCPUStartTime
== 0)) {
10998 now
= mach_absolute_time();
10999 SUB_ABSOLUTETIME(&now
, &assertStruct
->assertCPUStartTime
);
11000 absolutetime_to_nanoseconds(now
, &nsec
);
11001 assertStruct
->assertCPUDuration
+= nsec
;
11002 assertStruct
->assertCPUStartTime
= 0;
11004 if (assertStruct
->assertCPUDuration
> maxAssertCPUDuration
) {
11005 maxAssertCPUDuration
= assertStruct
->assertCPUDuration
;
11006 maxAssertCPUEntryId
= assertStruct
->registryEntryID
;
11011 PMAssertionsTracker::reportCPUBitAccounting( void )
11013 PMAssertStruct
*_a
;
11021 // Account for drivers that are still holding the CPU assertion
11022 if (assertionsKernel
& kIOPMDriverAssertionCPUBit
) {
11023 now
= mach_absolute_time();
11024 if ((count
= assertionsArray
->getCount())) {
11025 for (i
= 0; i
< count
; i
++) {
11026 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
11028 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
11029 if ((_a
->assertionBits
& kIOPMDriverAssertionCPUBit
) &&
11030 (_a
->level
== kIOPMDriverAssertionLevelOn
) &&
11031 (_a
->assertCPUStartTime
!= 0)) {
11032 // Don't modify PMAssertStruct, leave that
11033 // for updateCPUBitAccounting()
11034 SUB_ABSOLUTETIME(&now
, &_a
->assertCPUStartTime
);
11035 absolutetime_to_nanoseconds(now
, &nsec
);
11036 nsec
+= _a
->assertCPUDuration
;
11037 if (nsec
> maxAssertCPUDuration
) {
11038 maxAssertCPUDuration
= nsec
;
11039 maxAssertCPUEntryId
= _a
->registryEntryID
;
11047 if (maxAssertCPUDuration
) {
11048 DLOG("cpu assertion held for %llu ms by 0x%llx\n",
11049 (maxAssertCPUDuration
/ NSEC_PER_MSEC
), maxAssertCPUEntryId
);
11052 maxAssertCPUDuration
= 0;
11053 maxAssertCPUEntryId
= 0;
11057 PMAssertionsTracker::publishProperties( void )
11059 OSSharedPtr
<OSArray
> assertionsSummary
;
11061 if (tabulateConsumerCount
!= tabulateProducerCount
) {
11062 IOLockLock(assertionsArrayLock
);
11064 tabulateConsumerCount
= tabulateProducerCount
;
11066 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
11068 assertionsSummary
= copyAssertionsArray();
11069 if (assertionsSummary
) {
11070 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
.get());
11072 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
11075 /* Publish the IOPMrootDomain property "DriverPMAssertions"
11077 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
11079 IOLockUnlock(assertionsArrayLock
);
11083 PMAssertionsTracker::PMAssertStruct
*
11084 PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
11086 PMAssertStruct
*_a
= NULL
;
11092 if (assertionsArray
11093 && (count
= assertionsArray
->getCount())) {
11094 for (i
= 0; i
< count
; i
++) {
11095 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
11097 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
11098 if (_a
&& (_id
== _a
->id
)) {
11116 /* PMAssertionsTracker::handleCreateAssertion
11117 * Perform assertion work on the PM workloop. Do not call directly.
11120 PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
11122 PMAssertStruct
*assertStruct
;
11126 if (newAssertion
) {
11127 IOLockLock(assertionsArrayLock
);
11128 assertStruct
= (PMAssertStruct
*) newAssertion
->getBytesNoCopy();
11129 if ((assertStruct
->assertionBits
& kIOPMDriverAssertionCPUBit
) &&
11130 (assertStruct
->level
== kIOPMDriverAssertionLevelOn
)) {
11131 assertStruct
->assertCPUStartTime
= mach_absolute_time();
11133 assertionsArray
->setObject(newAssertion
);
11134 IOLockUnlock(assertionsArrayLock
);
11135 newAssertion
->release();
11139 return kIOReturnSuccess
;
11142 /* PMAssertionsTracker::createAssertion
11143 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
11147 PMAssertionsTracker::createAssertion(
11148 IOPMDriverAssertionType which
,
11149 IOPMDriverAssertionLevel level
,
11150 IOService
*serviceID
,
11151 const char *whoItIs
,
11152 IOPMDriverAssertionID
*outID
)
11154 OSSharedPtr
<OSData
> dataStore
;
11155 PMAssertStruct track
;
11157 // Warning: trillions and trillions of created assertions may overflow the unique ID.
11158 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
11159 track
.level
= level
;
11160 track
.assertionBits
= which
;
11162 // NB: ownerString is explicitly managed by PMAssertStruct
11163 // it will be released in `handleReleaseAssertion' below
11164 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
).detach():nullptr;
11165 track
.ownerService
= serviceID
;
11166 track
.registryEntryID
= serviceID
? serviceID
->getRegistryEntryID():0;
11167 track
.modifiedTime
= 0;
11168 pmEventTimeStamp(&track
.createdTime
);
11169 track
.assertCPUStartTime
= 0;
11170 track
.assertCPUDuration
= 0;
11172 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
11174 if (track
.ownerString
) {
11175 track
.ownerString
->release();
11176 track
.ownerString
= NULL
;
11178 return kIOReturnNoMemory
;
11183 if (owner
&& owner
->pmPowerStateQueue
) {
11184 // queue action is responsible for releasing dataStore
11185 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
.detach());
11188 return kIOReturnSuccess
;
11191 /* PMAssertionsTracker::handleReleaseAssertion
11192 * Runs in PM workloop. Do not call directly.
11195 PMAssertionsTracker::handleReleaseAssertion(
11196 IOPMDriverAssertionID _id
)
11201 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
11203 if (!assertStruct
) {
11204 return kIOReturnNotFound
;
11207 IOLockLock(assertionsArrayLock
);
11209 if ((assertStruct
->assertionBits
& kIOPMDriverAssertionCPUBit
) &&
11210 (assertStruct
->level
== kIOPMDriverAssertionLevelOn
)) {
11211 updateCPUBitAccounting(assertStruct
);
11214 if (assertStruct
->ownerString
) {
11215 assertStruct
->ownerString
->release();
11216 assertStruct
->ownerString
= NULL
;
11219 assertionsArray
->removeObject(index
);
11220 IOLockUnlock(assertionsArrayLock
);
11223 return kIOReturnSuccess
;
11226 /* PMAssertionsTracker::releaseAssertion
11227 * Releases an assertion and affects system behavior if appropiate.
11228 * Actual work happens on PM workloop.
11231 PMAssertionsTracker::releaseAssertion(
11232 IOPMDriverAssertionID _id
)
11234 if (owner
&& owner
->pmPowerStateQueue
) {
11235 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, NULL
, _id
);
11237 return kIOReturnSuccess
;
11240 /* PMAssertionsTracker::handleSetAssertionLevel
11241 * Runs in PM workloop. Do not call directly.
11244 PMAssertionsTracker::handleSetAssertionLevel(
11245 IOPMDriverAssertionID _id
,
11246 IOPMDriverAssertionLevel _level
)
11248 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
11252 if (!assertStruct
) {
11253 return kIOReturnNotFound
;
11256 IOLockLock(assertionsArrayLock
);
11257 pmEventTimeStamp(&assertStruct
->modifiedTime
);
11258 if ((assertStruct
->assertionBits
& kIOPMDriverAssertionCPUBit
) &&
11259 (assertStruct
->level
!= _level
)) {
11260 if (_level
== kIOPMDriverAssertionLevelOn
) {
11261 assertStruct
->assertCPUStartTime
= mach_absolute_time();
11263 updateCPUBitAccounting(assertStruct
);
11266 assertStruct
->level
= _level
;
11267 IOLockUnlock(assertionsArrayLock
);
11270 return kIOReturnSuccess
;
11273 /* PMAssertionsTracker::setAssertionLevel
11276 PMAssertionsTracker::setAssertionLevel(
11277 IOPMDriverAssertionID _id
,
11278 IOPMDriverAssertionLevel _level
)
11280 if (owner
&& owner
->pmPowerStateQueue
) {
11281 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
11282 (void *)(uintptr_t)_level
, _id
);
11285 return kIOReturnSuccess
;
11289 PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
11291 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
11295 if (new_user_levels
!= assertionsUser
) {
11296 DLOG("assertionsUser 0x%llx->0x%llx\n", assertionsUser
, new_user_levels
);
11297 assertionsUser
= new_user_levels
;
11301 return kIOReturnSuccess
;
11305 PMAssertionsTracker::setUserAssertionLevels(
11306 IOPMDriverAssertionType new_user_levels
)
11308 if (gIOPMWorkLoop
) {
11309 gIOPMWorkLoop
->runAction(
11310 OSMemberFunctionCast(
11311 IOWorkLoop::Action
,
11313 &PMAssertionsTracker::handleSetUserAssertionLevels
),
11315 (void *) &new_user_levels
, NULL
, NULL
, NULL
);
11318 return kIOReturnSuccess
;
11322 OSSharedPtr
<OSArray
>
11323 PMAssertionsTracker::copyAssertionsArray(void)
11327 OSSharedPtr
<OSArray
> outArray
= NULL
;
11329 if (!assertionsArray
|| (0 == (count
= assertionsArray
->getCount()))) {
11332 outArray
= OSArray::withCapacity(count
);
11337 for (i
= 0; i
< count
; i
++) {
11338 PMAssertStruct
*_a
= NULL
;
11340 OSSharedPtr
<OSDictionary
> details
;
11342 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
11343 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy())) {
11344 OSSharedPtr
<OSNumber
> _n
;
11346 details
= OSDictionary::withCapacity(7);
11351 outArray
->setObject(details
.get());
11353 _n
= OSNumber::withNumber(_a
->id
, 64);
11355 details
->setObject(kIOPMDriverAssertionIDKey
, _n
.get());
11357 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
11359 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
.get());
11361 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
11363 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
.get());
11365 _n
= OSNumber::withNumber((uintptr_t)_a
->registryEntryID
, 64);
11367 details
->setObject(kIOPMDriverAssertionRegistryEntryIDKey
, _n
.get());
11369 _n
= OSNumber::withNumber(_a
->level
, 64);
11371 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
.get());
11373 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
11375 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
.get());
11378 if (_a
->ownerString
) {
11379 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
11385 return os::move(outArray
);
11388 IOPMDriverAssertionType
11389 PMAssertionsTracker::getActivatedAssertions(void)
11391 return assertionsCombined
;
11394 IOPMDriverAssertionLevel
11395 PMAssertionsTracker::getAssertionLevel(
11396 IOPMDriverAssertionType type
)
11398 // FIXME: unused and also wrong
11399 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
)) {
11400 return kIOPMDriverAssertionLevelOn
;
11402 return kIOPMDriverAssertionLevelOff
;
11406 //*********************************************************************************
11407 //*********************************************************************************
11408 //*********************************************************************************
11412 pmEventTimeStamp(uint64_t *recordTS
)
11415 clock_usec_t tusec
;
11421 // We assume tsec fits into 32 bits; 32 bits holds enough
11422 // seconds for 136 years since the epoch in 1970.
11423 clock_get_calendar_microtime(&tsec
, &tusec
);
11426 // Pack the sec & microsec calendar time into a uint64_t, for fun.
11428 *recordTS
|= (uint32_t)tusec
;
11429 *recordTS
|= ((uint64_t)tsec
<< 32);
11435 // MARK: IORootParent
11437 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
11439 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
11441 // The reason that root domain needs a root parent is to facilitate demand
11442 // sleep, since a power change from the root parent cannot be vetoed.
11444 // The above statement is no longer true since root domain now performs
11445 // demand sleep using overrides. But root parent remains to avoid changing
11446 // the power tree stacking. Root parent is parked at the max power state.
11449 static IOPMPowerState patriarchPowerStates
[2] =
11451 {1, 0, ON_POWER
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
11452 {1, 0, ON_POWER
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
11456 IORootParent::initialize( void )
11459 gIOPMPSExternalConnectedKey
= OSSymbol::withCStringNoCopy(kIOPMPSExternalConnectedKey
);
11460 gIOPMPSExternalChargeCapableKey
= OSSymbol::withCStringNoCopy(kIOPMPSExternalChargeCapableKey
);
11461 gIOPMPSBatteryInstalledKey
= OSSymbol::withCStringNoCopy(kIOPMPSBatteryInstalledKey
);
11462 gIOPMPSIsChargingKey
= OSSymbol::withCStringNoCopy(kIOPMPSIsChargingKey
);
11463 gIOPMPSAtWarnLevelKey
= OSSymbol::withCStringNoCopy(kIOPMPSAtWarnLevelKey
);
11464 gIOPMPSAtCriticalLevelKey
= OSSymbol::withCStringNoCopy(kIOPMPSAtCriticalLevelKey
);
11465 gIOPMPSCurrentCapacityKey
= OSSymbol::withCStringNoCopy(kIOPMPSCurrentCapacityKey
);
11466 gIOPMPSMaxCapacityKey
= OSSymbol::withCStringNoCopy(kIOPMPSMaxCapacityKey
);
11467 gIOPMPSDesignCapacityKey
= OSSymbol::withCStringNoCopy(kIOPMPSDesignCapacityKey
);
11468 gIOPMPSTimeRemainingKey
= OSSymbol::withCStringNoCopy(kIOPMPSTimeRemainingKey
);
11469 gIOPMPSAmperageKey
= OSSymbol::withCStringNoCopy(kIOPMPSAmperageKey
);
11470 gIOPMPSVoltageKey
= OSSymbol::withCStringNoCopy(kIOPMPSVoltageKey
);
11471 gIOPMPSCycleCountKey
= OSSymbol::withCStringNoCopy(kIOPMPSCycleCountKey
);
11472 gIOPMPSMaxErrKey
= OSSymbol::withCStringNoCopy(kIOPMPSMaxErrKey
);
11473 gIOPMPSAdapterInfoKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterInfoKey
);
11474 gIOPMPSLocationKey
= OSSymbol::withCStringNoCopy(kIOPMPSLocationKey
);
11475 gIOPMPSErrorConditionKey
= OSSymbol::withCStringNoCopy(kIOPMPSErrorConditionKey
);
11476 gIOPMPSManufacturerKey
= OSSymbol::withCStringNoCopy(kIOPMPSManufacturerKey
);
11477 gIOPMPSManufactureDateKey
= OSSymbol::withCStringNoCopy(kIOPMPSManufactureDateKey
);
11478 gIOPMPSModelKey
= OSSymbol::withCStringNoCopy(kIOPMPSModelKey
);
11479 gIOPMPSSerialKey
= OSSymbol::withCStringNoCopy(kIOPMPSSerialKey
);
11480 gIOPMPSLegacyBatteryInfoKey
= OSSymbol::withCStringNoCopy(kIOPMPSLegacyBatteryInfoKey
);
11481 gIOPMPSBatteryHealthKey
= OSSymbol::withCStringNoCopy(kIOPMPSBatteryHealthKey
);
11482 gIOPMPSHealthConfidenceKey
= OSSymbol::withCStringNoCopy(kIOPMPSHealthConfidenceKey
);
11483 gIOPMPSCapacityEstimatedKey
= OSSymbol::withCStringNoCopy(kIOPMPSCapacityEstimatedKey
);
11484 gIOPMPSBatteryChargeStatusKey
= OSSymbol::withCStringNoCopy(kIOPMPSBatteryChargeStatusKey
);
11485 gIOPMPSBatteryTemperatureKey
= OSSymbol::withCStringNoCopy(kIOPMPSBatteryTemperatureKey
);
11486 gIOPMPSAdapterDetailsKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsKey
);
11487 gIOPMPSChargerConfigurationKey
= OSSymbol::withCStringNoCopy(kIOPMPSChargerConfigurationKey
);
11488 gIOPMPSAdapterDetailsIDKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsIDKey
);
11489 gIOPMPSAdapterDetailsWattsKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsWattsKey
);
11490 gIOPMPSAdapterDetailsRevisionKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsRevisionKey
);
11491 gIOPMPSAdapterDetailsSerialNumberKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsSerialNumberKey
);
11492 gIOPMPSAdapterDetailsFamilyKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsFamilyKey
);
11493 gIOPMPSAdapterDetailsAmperageKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsAmperageKey
);
11494 gIOPMPSAdapterDetailsDescriptionKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsDescriptionKey
);
11495 gIOPMPSAdapterDetailsPMUConfigurationKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsPMUConfigurationKey
);
11496 gIOPMPSAdapterDetailsSourceIDKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsSourceIDKey
);
11497 gIOPMPSAdapterDetailsErrorFlagsKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsErrorFlagsKey
);
11498 gIOPMPSAdapterDetailsSharedSourceKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsSharedSourceKey
);
11499 gIOPMPSAdapterDetailsCloakedKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsCloakedKey
);
11500 gIOPMPSInvalidWakeSecondsKey
= OSSymbol::withCStringNoCopy(kIOPMPSInvalidWakeSecondsKey
);
11501 gIOPMPSPostChargeWaitSecondsKey
= OSSymbol::withCStringNoCopy(kIOPMPSPostChargeWaitSecondsKey
);
11502 gIOPMPSPostDishargeWaitSecondsKey
= OSSymbol::withCStringNoCopy(kIOPMPSPostDishargeWaitSecondsKey
);
11506 IORootParent::start( IOService
* nub
)
11508 IOService::start(nub
);
11509 attachToParent( getRegistryRoot(), gIOPowerPlane
);
11511 registerPowerDriver(this, patriarchPowerStates
, 2);
11517 IORootParent::shutDownSystem( void )
11522 IORootParent::restartSystem( void )
11527 IORootParent::sleepSystem( void )
11532 IORootParent::dozeSystem( void )
11537 IORootParent::sleepToDoze( void )
11542 IORootParent::wakeSystem( void )
11546 OSSharedPtr
<OSObject
>
11547 IORootParent::copyProperty( const char * aKey
) const
11549 return IOService::copyProperty(aKey
);
11553 IOPMrootDomain::getWatchdogTimeout()
11555 if (gSwdSleepWakeTimeout
) {
11556 gSwdSleepTimeout
= gSwdWakeTimeout
= gSwdSleepWakeTimeout
;
11558 if ((pmTracer
->getTracePhase() < kIOPMTracePointSystemSleep
) ||
11559 (pmTracer
->getTracePhase() == kIOPMTracePointDarkWakeEntry
)) {
11560 return gSwdSleepTimeout
? gSwdSleepTimeout
: WATCHDOG_SLEEP_TIMEOUT
;
11562 return gSwdWakeTimeout
? gSwdWakeTimeout
: WATCHDOG_WAKE_TIMEOUT
;
11567 #if defined(__i386__) || defined(__x86_64__) || (defined(__arm64__) && HIBERNATION)
11569 IOPMrootDomain::restartWithStackshot()
11571 takeStackshot(true);
11573 return kIOReturnSuccess
;
11577 IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger
)
11579 takeStackshot(wdogTrigger
);
11583 IOPMrootDomain::tracePhase2String(uint32_t tracePhase
, const char **phaseString
, const char **description
)
11585 switch (tracePhase
) {
11586 case kIOPMTracePointSleepStarted
:
11587 *phaseString
= "kIOPMTracePointSleepStarted";
11588 *description
= "starting sleep";
11591 case kIOPMTracePointSleepApplications
:
11592 *phaseString
= "kIOPMTracePointSleepApplications";
11593 *description
= "notifying applications";
11596 case kIOPMTracePointSleepPriorityClients
:
11597 *phaseString
= "kIOPMTracePointSleepPriorityClients";
11598 *description
= "notifying clients about upcoming system capability changes";
11601 case kIOPMTracePointSleepWillChangeInterests
:
11602 *phaseString
= "kIOPMTracePointSleepWillChangeInterests";
11603 *description
= "creating hibernation file or while calling rootDomain's clients about upcoming rootDomain's state changes";
11606 case kIOPMTracePointSleepPowerPlaneDrivers
:
11607 *phaseString
= "kIOPMTracePointSleepPowerPlaneDrivers";
11608 *description
= "calling power state change callbacks";
11611 case kIOPMTracePointSleepDidChangeInterests
:
11612 *phaseString
= "kIOPMTracePointSleepDidChangeInterests";
11613 *description
= "calling rootDomain's clients about rootDomain's state changes";
11616 case kIOPMTracePointSleepCapabilityClients
:
11617 *phaseString
= "kIOPMTracePointSleepCapabilityClients";
11618 *description
= "notifying clients about current system capabilities";
11621 case kIOPMTracePointSleepPlatformActions
:
11622 *phaseString
= "kIOPMTracePointSleepPlatformActions";
11623 *description
= "calling Quiesce/Sleep action callbacks";
11626 case kIOPMTracePointSleepCPUs
:
11628 *phaseString
= "kIOPMTracePointSleepCPUs";
11629 #if defined(__i386__) || defined(__x86_64__)
11631 * We cannot use the getCPUNumber() method to get the cpu number, since
11632 * that cpu number is unrelated to the cpu number we need (we need the cpu
11633 * number as enumerated by the scheduler, NOT the CPU number enumerated
11634 * by ACPIPlatform as the CPUs are enumerated in MADT order).
11635 * Instead, pass the Mach processor pointer associated with the current
11636 * shutdown target so its associated cpu_id can be used in
11637 * processor_to_datastring.
11639 if (currentShutdownTarget
!= NULL
&&
11640 currentShutdownTarget
->getMachProcessor() != NULL
) {
11641 const char *sbuf
= processor_to_datastring("halting all non-boot CPUs",
11642 currentShutdownTarget
->getMachProcessor());
11643 *description
= sbuf
;
11645 *description
= "halting all non-boot CPUs";
11648 *description
= "halting all non-boot CPUs";
11652 case kIOPMTracePointSleepPlatformDriver
:
11653 *phaseString
= "kIOPMTracePointSleepPlatformDriver";
11654 *description
= "executing platform specific code";
11657 case kIOPMTracePointHibernate
:
11658 *phaseString
= "kIOPMTracePointHibernate";
11659 *description
= "writing the hibernation image";
11662 case kIOPMTracePointSystemSleep
:
11663 *phaseString
= "kIOPMTracePointSystemSleep";
11664 *description
= "in EFI/Bootrom after last point of entry to sleep";
11667 case kIOPMTracePointWakePlatformDriver
:
11668 *phaseString
= "kIOPMTracePointWakePlatformDriver";
11669 *description
= "executing platform specific code";
11673 case kIOPMTracePointWakePlatformActions
:
11674 *phaseString
= "kIOPMTracePointWakePlatformActions";
11675 *description
= "calling Wake action callbacks";
11678 case kIOPMTracePointWakeCPUs
:
11679 *phaseString
= "kIOPMTracePointWakeCPUs";
11680 *description
= "starting non-boot CPUs";
11683 case kIOPMTracePointWakeWillPowerOnClients
:
11684 *phaseString
= "kIOPMTracePointWakeWillPowerOnClients";
11685 *description
= "sending kIOMessageSystemWillPowerOn message to kernel and userspace clients";
11688 case kIOPMTracePointWakeWillChangeInterests
:
11689 *phaseString
= "kIOPMTracePointWakeWillChangeInterests";
11690 *description
= "calling rootDomain's clients about upcoming rootDomain's state changes";
11693 case kIOPMTracePointWakeDidChangeInterests
:
11694 *phaseString
= "kIOPMTracePointWakeDidChangeInterests";
11695 *description
= "calling rootDomain's clients about completed rootDomain's state changes";
11698 case kIOPMTracePointWakePowerPlaneDrivers
:
11699 *phaseString
= "kIOPMTracePointWakePowerPlaneDrivers";
11700 *description
= "calling power state change callbacks";
11703 case kIOPMTracePointWakeCapabilityClients
:
11704 *phaseString
= "kIOPMTracePointWakeCapabilityClients";
11705 *description
= "informing clients about current system capabilities";
11708 case kIOPMTracePointWakeApplications
:
11709 *phaseString
= "kIOPMTracePointWakeApplications";
11710 *description
= "sending asynchronous kIOMessageSystemHasPoweredOn message to userspace clients";
11713 case kIOPMTracePointDarkWakeEntry
:
11714 *phaseString
= "kIOPMTracePointDarkWakeEntry";
11715 *description
= "entering darkwake on way to sleep";
11718 case kIOPMTracePointDarkWakeExit
:
11719 *phaseString
= "kIOPMTracePointDarkWakeExit";
11720 *description
= "entering fullwake from darkwake";
11724 *phaseString
= NULL
;
11725 *description
= NULL
;
11730 IOPMrootDomain::saveFailureData2File()
11732 unsigned int len
= 0;
11733 char failureStr
[512];
11736 OSNumber
*statusCode
;
11737 uint64_t pmStatusCode
= 0;
11738 uint32_t phaseData
= 0;
11739 uint32_t phaseDetail
= 0;
11740 bool efiFailure
= false;
11742 OSSharedPtr
<OSObject
> statusCodeProp
= copyProperty(kIOPMSleepWakeFailureCodeKey
);
11743 statusCode
= OSDynamicCast(OSNumber
, statusCodeProp
.get());
11745 pmStatusCode
= statusCode
->unsigned64BitValue();
11746 phaseData
= pmStatusCode
& 0xFFFFFFFF;
11747 phaseDetail
= (pmStatusCode
>> 32) & 0xFFFFFFFF;
11748 if ((phaseData
& 0xFF) == kIOPMTracePointSystemSleep
) {
11749 LOG("Sleep Wake failure in EFI\n");
11752 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
);
11753 len
= (typeof(len
))strnlen(failureStr
, sizeof(failureStr
));
11758 if (PEReadNVRAMProperty(kIOSleepWakeFailurePanic
, NULL
, &len
)) {
11759 swd_flags
|= SWD_BOOT_BY_SW_WDOG
;
11760 PERemoveNVRAMProperty(kIOSleepWakeFailurePanic
);
11761 // dump panic will handle saving nvram data
11765 /* Keeping this around for capturing data during power
11768 if (!PEReadNVRAMProperty(kIOSleepWakeFailureString
, NULL
, &len
)) {
11769 DLOG("No sleep wake failure string\n");
11773 DLOG("Ignoring zero byte SleepWake failure string\n");
11777 // if PMStatus code is zero, delete stackshot and return
11779 if (((pmStatusCode
& 0xFFFFFFFF) & 0xFF) == 0) {
11780 // there was no sleep wake failure
11781 // this can happen if delete stackshot was called
11782 // before take stackshot completed. Let us delete any
11783 // sleep wake failure data in nvram
11784 DLOG("Deleting stackshot on successful wake\n");
11790 if (len
> sizeof(failureStr
)) {
11791 len
= sizeof(failureStr
);
11794 PEReadNVRAMProperty(kIOSleepWakeFailureString
, failureStr
, &len
);
11796 if (failureStr
[0] != 0) {
11797 error
= sleepWakeDebugSaveFile(kSleepWakeFailureStringFile
, failureStr
, len
);
11799 DLOG("Failed to save SleepWake failure string to file. error:%d\n", error
);
11801 DLOG("Saved SleepWake failure string to file.\n");
11805 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
)) {
11810 unsigned int len
= 0;
11812 char nvram_var_name_buffer
[20];
11813 unsigned int concat_len
= 0;
11814 swd_hdr
*hdr
= NULL
;
11817 hdr
= (swd_hdr
*)swd_buffer
;
11818 outbuf
= (char *)hdr
+ hdr
->spindump_offset
;
11819 OSBoundedArrayRef
<char> boundedOutBuf(outbuf
, hdr
->alloc_size
- hdr
->spindump_offset
);
11821 for (int i
= 0; i
< 8; i
++) {
11822 snprintf(nvram_var_name_buffer
, sizeof(nvram_var_name_buffer
), "%s%02d", SWD_STACKSHOT_VAR_PREFIX
, i
+ 1);
11823 if (!PEReadNVRAMProperty(nvram_var_name_buffer
, NULL
, &len
)) {
11824 LOG("No SleepWake blob to read beyond chunk %d\n", i
);
11827 if (PEReadNVRAMProperty(nvram_var_name_buffer
, boundedOutBuf
.slice(concat_len
, len
).data(), &len
) == FALSE
) {
11828 PERemoveNVRAMProperty(nvram_var_name_buffer
);
11829 LOG("Could not read the property :-(\n");
11832 PERemoveNVRAMProperty(nvram_var_name_buffer
);
11835 LOG("Concatenated length for the SWD blob %d\n", concat_len
);
11838 error
= sleepWakeDebugSaveFile(kSleepWakeStacksFilename
, outbuf
, concat_len
);
11840 LOG("Failed to save SleepWake zipped data to file. error:%d\n", error
);
11842 LOG("Saved SleepWake zipped data to file.\n");
11845 // There is a sleep wake failure string but no stackshot
11846 // Write a placeholder stacks file so that swd runs
11847 snprintf(outbuf
, 20, "%s", "No stackshot data\n");
11848 error
= sleepWakeDebugSaveFile(kSleepWakeStacksFilename
, outbuf
, 20);
11850 LOG("Failed to save SleepWake zipped data to file. error:%d\n", error
);
11852 LOG("Saved SleepWake zipped data to file.\n");
11856 LOG("No buffer allocated to save failure stackshot\n");
11860 gRootDomain
->swd_lock
= 0;
11862 PERemoveNVRAMProperty(kIOSleepWakeFailureString
);
11868 IOPMrootDomain::getFailureData(thread_t
*thread
, char *failureStr
, size_t strLen
)
11870 OSSharedPtr
<IORegistryIterator
> iter
;
11871 OSSharedPtr
<const OSSymbol
> kextName
= NULL
;
11872 IORegistryEntry
* entry
;
11874 bool nodeFound
= false;
11876 const void * callMethod
= NULL
;
11877 const char * objectName
= NULL
;
11878 uint32_t timeout
= getWatchdogTimeout();
11879 const char * phaseString
= NULL
;
11880 const char * phaseDescription
= NULL
;
11882 IOPMServiceInterestNotifier
*notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, notifierObject
.get());
11883 uint32_t tracePhase
= pmTracer
->getTracePhase();
11886 if ((tracePhase
< kIOPMTracePointSystemSleep
) || (tracePhase
== kIOPMTracePointDarkWakeEntry
)) {
11887 snprintf(failureStr
, strLen
, "Sleep transition timed out after %d seconds", timeout
);
11889 snprintf(failureStr
, strLen
, "Wake transition timed out after %d seconds", timeout
);
11891 tracePhase2String(tracePhase
, &phaseString
, &phaseDescription
);
11893 if (notifierThread
) {
11894 if (notifier
&& (notifier
->identifier
)) {
11895 objectName
= notifier
->identifier
->getCStringNoCopy();
11897 *thread
= notifierThread
;
11899 iter
= IORegistryIterator::iterateOver(
11900 getPMRootDomain(), gIOPowerPlane
, kIORegistryIterateRecursively
);
11903 while ((entry
= iter
->getNextObject())) {
11904 node
= OSDynamicCast(IOService
, entry
);
11908 if (OSDynamicCast(IOPowerConnection
, node
)) {
11912 if (node
->getBlockingDriverCall(thread
, &callMethod
)) {
11919 kextName
= copyKextIdentifierWithAddress((vm_address_t
) callMethod
);
11921 objectName
= kextName
->getCStringNoCopy();
11925 if (phaseDescription
) {
11926 strlcat(failureStr
, " while ", strLen
);
11927 strlcat(failureStr
, phaseDescription
, strLen
);
11928 strlcat(failureStr
, ".", strLen
);
11931 strlcat(failureStr
, " Suspected bundle: ", strLen
);
11932 strlcat(failureStr
, objectName
, strLen
);
11933 strlcat(failureStr
, ".", strLen
);
11936 char threadName
[40];
11937 snprintf(threadName
, sizeof(threadName
), " Thread 0x%llx.", thread_tid(*thread
));
11938 strlcat(failureStr
, threadName
, strLen
);
11941 DLOG("%s\n", failureStr
);
11944 struct swd_stackshot_compressed_data
{
11945 z_output_func zoutput
;
11947 uint64_t totalbytes
;
11948 uint64_t lastpercent
;
11950 unsigned outremain
;
11955 struct swd_stackshot_compressed_data swd_zip_var
= { };
11958 swd_zs_alloc(void *__unused ref
, u_int items
, u_int size
)
11961 LOG("Alloc in zipping %d items of size %d\n", items
, size
);
11963 result
= (void *)(swd_zs_zmem
+ swd_zs_zoffset
);
11964 swd_zs_zoffset
+= ~31L & (31 + (items
* size
)); // 32b align for vector crc
11965 LOG("Offset %zu\n", swd_zs_zoffset
);
11970 swd_zinput(z_streamp strm
, Bytef
*buf
, unsigned size
)
11974 len
= strm
->avail_in
;
11983 if (strm
->next_in
!= (Bytef
*) strm
) {
11984 memcpy(buf
, strm
->next_in
, len
);
11989 strm
->adler
= z_crc32(strm
->adler
, buf
, len
);
11991 strm
->avail_in
-= len
;
11992 strm
->next_in
+= len
;
11993 strm
->total_in
+= len
;
11999 swd_zoutput(z_streamp strm
, Bytef
*buf
, unsigned len
)
12001 unsigned int i
= 0;
12002 // if outlen > max size don't add to the buffer
12003 assert(buf
!= NULL
);
12005 if (swd_zip_var
.outlen
+ len
> SWD_COMPRESSED_BUFSIZE
) {
12006 LOG("No space to GZIP... not writing to NVRAM\n");
12010 for (i
= 0; i
< len
; i
++) {
12011 *(swd_zip_var
.outbuf
+ swd_zip_var
.outlen
+ i
) = *(buf
+ i
);
12013 swd_zip_var
.outlen
+= len
;
12018 swd_zs_free(void * __unused ref
, void * __unused ptr
)
12023 swd_compress(char *inPtr
, char *outPtr
, size_t numBytes
)
12028 if (((unsigned int) numBytes
) != numBytes
) {
12032 if (!swd_zs
.zalloc
) {
12033 swd_zs
.zalloc
= swd_zs_alloc
;
12034 swd_zs
.zfree
= swd_zs_free
;
12035 if (deflateInit2(&swd_zs
, Z_BEST_SPEED
, Z_DEFLATED
, wbits
+ 16, memlevel
, Z_DEFAULT_STRATEGY
)) {
12036 // allocation failed
12037 bzero(&swd_zs
, sizeof(swd_zs
));
12038 // swd_zs_zoffset = 0;
12040 LOG("PMRD inited the zlib allocation routines\n");
12044 swd_zip_var
.zipped
= 0;
12045 swd_zip_var
.totalbytes
= 0; // should this be the max that we have?
12046 swd_zip_var
.lastpercent
= 0;
12047 swd_zip_var
.error
= kIOReturnSuccess
;
12048 swd_zip_var
.outremain
= 0;
12049 swd_zip_var
.outlen
= 0;
12050 swd_zip_var
.writes
= 0;
12051 swd_zip_var
.outbuf
= (Bytef
*)outPtr
;
12053 swd_zip_var
.totalbytes
= numBytes
;
12055 swd_zs
.avail_in
= 0;
12056 swd_zs
.next_in
= NULL
;
12057 swd_zs
.avail_out
= 0;
12058 swd_zs
.next_out
= NULL
;
12060 deflateResetWithIO(&swd_zs
, swd_zinput
, swd_zoutput
);
12066 while (swd_zip_var
.error
>= 0) {
12067 if (!zs
->avail_in
) {
12068 zs
->next_in
= (unsigned char *)inPtr
? (Bytef
*)inPtr
: (Bytef
*)zs
; /* zero marker? */
12069 zs
->avail_in
= (unsigned int) numBytes
;
12071 if (!zs
->avail_out
) {
12072 zs
->next_out
= (Bytef
*)zs
;
12073 zs
->avail_out
= UINT32_MAX
;
12075 zr
= deflate(zs
, Z_NO_FLUSH
);
12076 if (Z_STREAM_END
== zr
) {
12080 LOG("ZERR %d\n", zr
);
12081 swd_zip_var
.error
= zr
;
12083 if (zs
->total_in
== numBytes
) {
12089 //now flush the stream
12090 while (swd_zip_var
.error
>= 0) {
12091 if (!zs
->avail_out
) {
12092 zs
->next_out
= (Bytef
*)zs
;
12093 zs
->avail_out
= UINT32_MAX
;
12095 zr
= deflate(zs
, Z_FINISH
);
12096 if (Z_STREAM_END
== zr
) {
12100 LOG("ZERR %d\n", zr
);
12101 swd_zip_var
.error
= zr
;
12103 if (zs
->total_in
== numBytes
) {
12104 LOG("Total output size %d\n", swd_zip_var
.outlen
);
12110 return swd_zip_var
.outlen
;
12114 IOPMrootDomain::deleteStackshot()
12116 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
)) {
12117 // takeStackshot hasn't completed
12120 LOG("Deleting any sleepwake failure data in nvram\n");
12122 PERemoveNVRAMProperty(kIOSleepWakeFailureString
);
12123 char nvram_var_name_buf
[20];
12124 for (int i
= 0; i
< 8; i
++) {
12125 snprintf(nvram_var_name_buf
, sizeof(nvram_var_name_buf
), "%s%02d", SWD_STACKSHOT_VAR_PREFIX
, i
+ 1);
12126 if (PERemoveNVRAMProperty(nvram_var_name_buf
) == false) {
12127 LOG("Removing %s returned false\n", nvram_var_name_buf
);
12130 // force NVRAM sync
12131 if (PEWriteNVRAMProperty(kIONVRAMSyncNowPropertyKey
, kIONVRAMSyncNowPropertyKey
, (unsigned int) strlen(kIONVRAMSyncNowPropertyKey
)) == false) {
12132 DLOG("Failed to force nvram sync\n");
12134 gRootDomain
->swd_lock
= 0;
12138 IOPMrootDomain::takeStackshot(bool wdogTrigger
)
12140 swd_hdr
* hdr
= NULL
;
12144 kern_return_t kr
= KERN_SUCCESS
;
12149 uint32_t bytesRemaining
;
12150 unsigned bytesWritten
= 0;
12152 char failureStr
[512];
12153 thread_t thread
= NULL
;
12154 const char * swfPanic
= "swfPanic";
12159 #if defined(__i386__) || defined(__x86_64__)
12160 const bool concise
= false;
12162 const bool concise
= true;
12165 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
)) {
12170 if ((kIOSleepWakeWdogOff
& gIOKitDebug
) || systemBooting
|| systemShutdown
|| gWillShutdown
) {
12175 getFailureData(&thread
, failureStr
, sizeof(failureStr
));
12177 if (concise
|| (PEGetCoprocessorVersion() >= kCoprocessorVersion2
)) {
12178 goto skip_stackshot
;
12183 clock_get_uptime(&now
);
12184 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
12185 absolutetime_to_nanoseconds(now
, &nsec
);
12186 snprintf(failureStr
, sizeof(failureStr
), "Power button pressed during wake transition after %u ms.\n", ((int)((nsec
) / NSEC_PER_MSEC
)));
12189 if (swd_buffer
== NULL
) {
12190 sleepWakeDebugMemAlloc();
12191 if (swd_buffer
== NULL
) {
12195 hdr
= (swd_hdr
*)swd_buffer
;
12196 bufSize
= hdr
->alloc_size
;
12198 dstAddr
= (char*)hdr
+ hdr
->spindump_offset
;
12199 flags
= STACKSHOT_KCDATA_FORMAT
| STACKSHOT_NO_IO_STATS
| STACKSHOT_SAVE_KEXT_LOADINFO
| STACKSHOT_ACTIVE_KERNEL_THREADS_ONLY
| STACKSHOT_THREAD_WAITINFO
;
12200 /* If not wdogTrigger only take kernel tasks stackshot
12208 /* Attempt to take stackshot with all ACTIVE_KERNEL_THREADS
12209 * If we run out of space, take stackshot with only kernel task
12211 while (success
== 0 && cnt
< max_cnt
) {
12212 bytesRemaining
= bufSize
- hdr
->spindump_offset
;
12214 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining
);
12216 size
= bytesRemaining
;
12217 kr
= stack_snapshot_from_kernel(pid
, dstAddr
, size
, flags
, 0, 0, &bytesWritten
);
12218 DLOG("stack_snapshot_from_kernel returned 0x%x. pid: %d bufsize:0x%x flags:0x%llx bytesWritten: %d\n",
12219 kr
, pid
, size
, flags
, bytesWritten
);
12220 if (kr
== KERN_INSUFFICIENT_BUFFER_SIZE
) {
12224 LOG("Insufficient buffer size for only kernel task\n");
12228 if (kr
== KERN_SUCCESS
) {
12229 if (bytesWritten
== 0) {
12230 MSG("Failed to get stackshot(0x%x) bufsize:0x%x flags:0x%llx\n", kr
, size
, flags
);
12233 bytesRemaining
-= bytesWritten
;
12234 hdr
->spindump_size
= (bufSize
- bytesRemaining
- hdr
->spindump_offset
);
12236 memset(hdr
->reason
, 0x20, sizeof(hdr
->reason
));
12238 // Compress stackshot and save to NVRAM
12240 char *outbuf
= (char *)swd_compressed_buffer
;
12242 int num_chunks
= 0;
12243 int max_chunks
= 0;
12245 char nvram_var_name_buffer
[20];
12247 outlen
= swd_compress((char*)hdr
+ hdr
->spindump_offset
, outbuf
, bytesWritten
);
12250 max_chunks
= outlen
/ (2096 - 200);
12251 leftover
= outlen
% (2096 - 200);
12253 if (max_chunks
< 8) {
12254 for (num_chunks
= 0; num_chunks
< max_chunks
; num_chunks
++) {
12255 snprintf(nvram_var_name_buffer
, sizeof(nvram_var_name_buffer
), "%s%02d", SWD_STACKSHOT_VAR_PREFIX
, num_chunks
+ 1);
12256 if (PEWriteNVRAMPropertyWithCopy(nvram_var_name_buffer
, (outbuf
+ (num_chunks
* (2096 - 200))), (2096 - 200)) == FALSE
) {
12257 LOG("Failed to update NVRAM %d\n", num_chunks
);
12262 snprintf(nvram_var_name_buffer
, sizeof(nvram_var_name_buffer
), "%s%02d", SWD_STACKSHOT_VAR_PREFIX
, num_chunks
+ 1);
12263 if (PEWriteNVRAMPropertyWithCopy(nvram_var_name_buffer
, (outbuf
+ (num_chunks
* (2096 - 200))), leftover
) == FALSE
) {
12264 LOG("Failed to update NVRAM with leftovers\n");
12268 LOG("Successfully saved stackshot to NVRAM\n");
12270 LOG("Compressed failure stackshot is too large. size=%d bytes\n", outlen
);
12274 LOG("Compressed failure stackshot of only kernel is too large size=%d bytes\n", outlen
);
12283 if (failureStr
[0]) {
12284 // append sleep-wake failure code
12285 char traceCode
[80];
12286 snprintf(traceCode
, sizeof(traceCode
), "\nFailure code:: 0x%08x %08x\n",
12287 pmTracer
->getTraceData(), pmTracer
->getTracePhase());
12288 strlcat(failureStr
, traceCode
, sizeof(failureStr
));
12289 if (PEWriteNVRAMProperty(kIOSleepWakeFailureString
, failureStr
, (unsigned int) strnlen(failureStr
, sizeof(failureStr
))) == false) {
12290 DLOG("Failed to write SleepWake failure string\n");
12294 // force NVRAM sync
12295 if (PEWriteNVRAMProperty(kIONVRAMSyncNowPropertyKey
, kIONVRAMSyncNowPropertyKey
, (unsigned int) strlen(kIONVRAMSyncNowPropertyKey
)) == false) {
12296 DLOG("Failed to force nvram sync\n");
12301 if (PEGetCoprocessorVersion() < kCoprocessorVersion2
) {
12302 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
12303 // If current boot is due to this watch dog trigger restart in previous boot,
12304 // then don't trigger again until at least 1 successful sleep & wake.
12305 if (!(sleepCnt
&& (displayWakeCnt
|| darkWakeCnt
))) {
12306 LOG("Shutting down due to repeated Sleep/Wake failures\n");
12307 if (!tasksSuspended
) {
12308 tasksSuspended
= TRUE
;
12309 updateTasksSuspend();
12311 PEHaltRestart(kPEHaltCPU
);
12315 if (gSwdPanic
== 0) {
12316 LOG("Calling panic prevented by swd_panic boot-args. Calling restart");
12317 if (!tasksSuspended
) {
12318 tasksSuspended
= TRUE
;
12319 updateTasksSuspend();
12321 PEHaltRestart(kPERestartCPU
);
12324 if (!concise
&& (PEWriteNVRAMProperty(kIOSleepWakeFailurePanic
, swfPanic
, (unsigned int) strlen(swfPanic
)) == false)) {
12325 DLOG("Failed to write SleepWake failure panic key\n");
12327 #if defined(__x86_64__)
12329 panic_with_thread_context(0, NULL
, DEBUGGER_OPTION_ATTEMPTCOREDUMPANDREBOOT
, thread
, "%s", failureStr
);
12331 #endif /* defined(__x86_64__) */
12333 panic_with_options(0, NULL
, DEBUGGER_OPTION_ATTEMPTCOREDUMPANDREBOOT
, "%s", failureStr
);
12336 gRootDomain
->swd_lock
= 0;
12342 IOPMrootDomain::sleepWakeDebugMemAlloc()
12344 vm_size_t size
= SWD_STACKSHOT_SIZE
+ SWD_COMPRESSED_BUFSIZE
+ SWD_ZLIB_BUFSIZE
;
12346 swd_hdr
*hdr
= NULL
;
12347 void *bufPtr
= NULL
;
12349 OSSharedPtr
<IOBufferMemoryDescriptor
> memDesc
;
12352 if (kIOSleepWakeWdogOff
& gIOKitDebug
) {
12356 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
)) {
12360 memDesc
= IOBufferMemoryDescriptor::inTaskWithOptions(
12361 kernel_task
, kIODirectionIn
| kIOMemoryMapperNone
,
12363 if (memDesc
== NULL
) {
12364 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
12368 bufPtr
= memDesc
->getBytesNoCopy();
12370 // Carve out memory for zlib routines
12371 swd_zs_zmem
= (vm_offset_t
)bufPtr
;
12372 bufPtr
= (char *)bufPtr
+ SWD_ZLIB_BUFSIZE
;
12374 // Carve out memory for compressed stackshots
12375 swd_compressed_buffer
= bufPtr
;
12376 bufPtr
= (char *)bufPtr
+ SWD_COMPRESSED_BUFSIZE
;
12378 // Remaining is used for holding stackshot
12379 hdr
= (swd_hdr
*)bufPtr
;
12380 memset(hdr
, 0, sizeof(swd_hdr
));
12382 hdr
->signature
= SWD_HDR_SIGNATURE
;
12383 hdr
->alloc_size
= SWD_STACKSHOT_SIZE
;
12385 hdr
->spindump_offset
= sizeof(swd_hdr
);
12386 swd_buffer
= (void *)hdr
;
12387 swd_memDesc
= os::move(memDesc
);
12388 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr
->alloc_size
, hdr
->spindump_offset
);
12391 gRootDomain
->swd_lock
= 0;
12395 IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc()
12398 vm_size_t size
= SWD_SPINDUMP_SIZE
;
12400 swd_hdr
*hdr
= NULL
;
12402 OSSharedPtr
<IOBufferMemoryDescriptor
> memDesc
;
12404 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
)) {
12408 memDesc
= IOBufferMemoryDescriptor::inTaskWithOptions(
12409 kernel_task
, kIODirectionIn
| kIOMemoryMapperNone
,
12410 SWD_SPINDUMP_SIZE
);
12412 if (memDesc
== NULL
) {
12413 DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
12418 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
12419 memset(hdr
, 0, sizeof(swd_hdr
));
12421 hdr
->signature
= SWD_HDR_SIGNATURE
;
12422 hdr
->alloc_size
= size
;
12424 hdr
->spindump_offset
= sizeof(swd_hdr
);
12425 swd_spindump_buffer
= (void *)hdr
;
12426 swd_spindump_memDesc
= os::move(memDesc
);
12429 gRootDomain
->swd_lock
= 0;
12430 #endif /* UNUSED */
12434 IOPMrootDomain::sleepWakeDebugEnableWdog()
12439 IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
12441 return !systemBooting
&& !systemShutdown
&& !gWillShutdown
;
12445 IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
12447 swd_hdr
*hdr
= NULL
;
12448 errno_t error
= EIO
;
12450 if (swd_spindump_buffer
&& gSpinDumpBufferFull
) {
12451 hdr
= (swd_hdr
*)swd_spindump_buffer
;
12453 error
= sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
12454 (char*)hdr
+ hdr
->spindump_offset
, hdr
->spindump_size
);
12460 sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
12461 (char*)hdr
+ offsetof(swd_hdr
, UUID
),
12462 sizeof(swd_hdr
) - offsetof(swd_hdr
, UUID
));
12464 gSpinDumpBufferFull
= false;
12469 IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)
12471 struct vnode
*vp
= NULL
;
12472 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
12473 kauth_cred_t cred
= vfs_context_ucred(ctx
);
12474 struct vnode_attr va
;
12475 errno_t error
= EIO
;
12477 if (vnode_open(name
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
12478 S_IRUSR
| S_IRGRP
| S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0) {
12479 LOG("Failed to open the file %s\n", name
);
12480 swd_flags
|= SWD_FILEOP_ERROR
;
12484 VATTR_WANTED(&va
, va_nlink
);
12485 /* Don't dump to non-regular files or files with links. */
12486 if (vp
->v_type
!= VREG
||
12487 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
12488 LOG("Bailing as this is not a regular file\n");
12489 swd_flags
|= SWD_FILEOP_ERROR
;
12493 VATTR_SET(&va
, va_data_size
, 0);
12494 vnode_setattr(vp
, &va
, ctx
);
12498 error
= vn_rdwr(UIO_WRITE
, vp
, buf
, len
, 0,
12499 UIO_SYSSPACE
, IO_NODELOCKED
| IO_UNIT
, cred
, (int *) NULL
, vfs_context_proc(ctx
));
12501 LOG("Failed to save sleep wake log. err 0x%x\n", error
);
12502 swd_flags
|= SWD_FILEOP_ERROR
;
12504 DLOG("Saved %d bytes to file %s\n", len
, name
);
12510 vnode_close(vp
, FWRITE
, ctx
);
12513 vfs_context_rele(ctx
);
12519 #else /* defined(__i386__) || defined(__x86_64__) */
12522 IOPMrootDomain::sleepWakeDebugTrig(bool restart
)
12525 if (gSwdPanic
== 0) {
12528 panic("Sleep/Wake hang detected");
12534 IOPMrootDomain::takeStackshot(bool restart
)
12536 #pragma unused(restart)
12540 IOPMrootDomain::deleteStackshot()
12545 IOPMrootDomain::sleepWakeDebugMemAlloc()
12550 IOPMrootDomain::saveFailureData2File()
12555 IOPMrootDomain::sleepWakeDebugEnableWdog()
12560 IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
12566 IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
12571 IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)
12576 #endif /* defined(__i386__) || defined(__x86_64__) */